cgalMesh | R Documentation |
R6 class to represent a CGAL mesh.
new()
Creates a new cgalMesh
object.
cgalMesh$new(mesh, vertices, faces, normals = NULL, clean = FALSE)
mesh
there are four possibilities for this argument: it can be
missing, in which case the arguments vertices
and faces
must be given, or it can be the path to a mesh file (accepted formats:
off
, obj
, stl
, ply
, ts
, vtp
),
or it can be a rgl mesh (i.e. a mesh3d
object), or it
can be a list containing (at least) the fields vertices
(numeric matrix with three columns) and faces
(matrix of
integers or list of vectors of integers), and optionally a field
normals
(numeric matrix with three columns); if
this argument is a rgl mesh containing some colors, these
colors will be assigned to the created cgalMesh
object
vertices
if mesh
is missing, must be a numeric matrix with
three columns
faces
if mesh
is missing, must be either a matrix of
integers (each row gives the vertex indices of a face) or a list of
vectors of integers (each one gives the vertex indices of a face)
normals
if mesh
is missing, must be NULL
or a
numeric matrix with three columns and as many rows as vertices
clean
Boolean value indicating whether to clean the mesh (merge
duplicated vertices and duplicated faces, remove isolated vertices);
set to FALSE
if you know your mesh is already clean
A cgalMesh
object.
library(cgalMeshes) meshFile <- system.file( "extdata", "bigPolyhedron.off", package = "cgalMeshes" ) mesh <- cgalMesh$new(meshFile) rglmesh <- mesh$getMesh() library(rgl) open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.9) shade3d(rglmesh, color = "tomato") plotEdges( mesh$getVertices(), mesh$getEdges(), color = "darkred" ) # this one has colors: #### meshFile <- system.file( "extdata", "pentagrammicDipyramid.ply", package = "cgalMeshes" ) mesh <- cgalMesh$new(meshFile) rmesh <- mesh$getMesh() library(rgl) open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.85) shade3d(rmesh, meshColor = "faces")
print()
Print a cgalMesh
object.
cgalMesh$print(...)
...
ignored
No value returned, just prints some information about the mesh.
area()
Compute the area of the mesh. The mesh must be triangle and must not self-intersect.
cgalMesh$area()
A number, the mesh area.
library(rgl) mesh <- cgalMesh$new(cube3d())$triangulate() mesh$area()
assignFaceColors()
Assign colors (or any character strings) to the faces of the mesh.
cgalMesh$assignFaceColors(colors)
colors
a character vector whose length equals the number of faces, or a single character string to be assigned to each face
The current cgalMesh
object, invisibly.
assignFaceScalars()
Assign scalars to the faces of the mesh.
cgalMesh$assignFaceScalars(scalars)
scalars
a numeric vector whose length equals the number of faces
The current cgalMesh
object, invisibly.
assignNormals()
Assign per-vertex normals to the mesh.
cgalMesh$assignNormals(normals)
normals
a numeric matrix with three columns and as many rows as the number of vertices
The current cgalMesh
object, invisibly.
assignVertexColors()
Assign colors (or any character strings) to the vertices of the mesh.
cgalMesh$assignVertexColors(colors)
colors
a character vector whose length equals the number of vertices
The current cgalMesh
object, invisibly.
assignVertexScalars()
Assign scalars to the vertices of the mesh.
cgalMesh$assignVertexScalars(scalars)
scalars
a numeric vector whose length equals the number of vertices
The current cgalMesh
object, invisibly.
boundingBox()
Bounding box of the mesh.
cgalMesh$boundingBox()
A list containing the smallest corner point and the largest
corner point of the bounding box, named lcorner
and
ucorner
respectively. Use isoCuboidMesh
to get a
mesh of this bounding box.
library(cgalMeshes) library(rgl) rmesh <- cyclideMesh(a = 97, c = 32, mu = 57) mesh <- cgalMesh$new(rmesh) bbox <- mesh$boundingBox() bxmesh <- isoCuboidMesh(bbox[["lcorner"]], bbox[["ucorner"]]) open3d(windowRect = 50 + c(0, 0, 512, 512)) view3d(0, -60) shade3d(rmesh, color = "gold") wire3d(bxmesh, color = "black")
boundsVolume()
Check whether the mesh bounds a volume. The mesh must be triangle.
cgalMesh$boundsVolume()
A Boolean value, whether the mesh bounds a volume.
library(rgl) mesh <- cgalMesh$new(tetrahedron3d()) mesh$boundsVolume() # TRUE mesh$reverseOrientation() mesh$boundsVolume() # TRUE
CatmullClark()
Performs the Catmull-Clark subdivision and deformation. The mesh must be triangle.
cgalMesh$CatmullClark(iterations = 1)
iterations
number of iterations
The modified reference mesh, invisibly.
library(cgalMeshes) library(rgl) hopfMesh <- HopfTorusMesh(nu = 80, nv = 40) mesh <- cgalMesh$new(hopfMesh) mesh$CatmullClark(iterations = 2) mesh$computeNormals() rmesh <- mesh$getMesh() # plot open3d(windowRect = 50 + c(0, 0, 800, 400)) mfrow3d(1, 2) view3d(0, 0, zoom = 0.9) shade3d(hopfMesh, color = "red") wire3d(hopfMesh, color = "black") next3d() view3d(0, 0, zoom = 0.9) shade3d(rmesh, color = "red") wire3d(rmesh, color = "black")
centroid()
Centroid of the mesh. The mesh must be triangle.
cgalMesh$centroid()
The Cartesian coordinates of the centroid of the mesh.
library(cgalMeshes) library(rgl) mesh <- cgalMesh$new(icosahedron3d()) mesh$centroid()
clip()
Clip mesh to the volume bounded by another mesh. The mesh must be triangle. Face properties (colors and scalars) are preserved. WARNING: the reference mesh is then replaced by its clipped version.
cgalMesh$clip(clipper, clipVolume)
clipper
a cgalMesh
object; it must represent a closed
triangle mesh which doesn't self-intersect
clipVolume
Boolean, whether the clipping has to be done on the
volume bounded by the reference mesh rather than on its surface (i.e.
the reference mesh will be kept closed if it is closed); if
TRUE
, the mesh to be clipped must not self-intersect
The reference mesh is always replaced by the result of the
clipping. If clipVolume=TRUE
, this function returns two
cgalMesh
objects: the two parts of the clipped mesh contained
in the reference mesh and the clipping mesh respectively. Otherwise,
this function returns the modified reference mesh.
# cube clipped to sphere #### library(cgalMeshes) library(rgl) mesh <- cgalMesh$new(cube3d())$triangulate() clipper <- cgalMesh$new(sphereMesh(r= sqrt(2))) mesh$assignFaceColors("blue") clipper$assignFaceColors("red") meshes <- mesh$clip(clipper, clipVolume = TRUE) mesh1 <- meshes[[1]] mesh2 <- meshes[[2]] mesh2$computeNormals() rglmesh1 <- mesh1$getMesh() rglmesh2 <- mesh2$getMesh() open3d(windowRect = 50 + c(0, 0, 512, 512)) view3d(45, 45, zoom = 0.9) shade3d(rglmesh1, meshColor = "faces") shade3d(rglmesh2, meshColor = "faces") # Togliatti surface clipped to a ball #### library(rmarchingcubes) library(rgl) library(cgalMeshes) # Togliatti surface equation: f(x,y,z) = 0 f <- function(x, y, z) { 64*(x-1) * (x^4 - 4*x^3 - 10*x^2*y^2 - 4*x^2 + 16*x - 20*x*y^2 + 5*y^4 + 16 - 20*y^2) - 5*sqrt(5-sqrt(5))*(2*z - sqrt(5-sqrt(5))) * (4*(x^2 + y^2 - z^2) + (1 + 3*sqrt(5)))^2 } # grid n <- 200L x <- y <- seq(-5, 5, length.out = n) z <- seq(-4, 4, length.out = n) Grid <- expand.grid(X = x, Y = y, Z = z) # calculate voxel voxel <- array(with(Grid, f(X, Y, Z)), dim = c(n, n, n)) # calculate isosurface contour_shape <- contour3d( griddata = voxel, level = 0, x = x, y = y, z = z ) # make rgl mesh (plotted later) rglMesh <- tmesh3d( vertices = t(contour_shape[["vertices"]]), indices = t(contour_shape[["triangles"]]), normals = contour_shape[["normals"]], homogeneous = FALSE ) # make CGAL mesh mesh <- cgalMesh$new(rglMesh) # clip to sphere of radius 4.8 sphere <- sphereMesh(r = 4.8) clipper <- cgalMesh$new(sphere) mesh$clip(clipper, clipVolume = FALSE) rglClippedMesh <- mesh$getMesh() # plot open3d(windowRect = 50 + c(0, 0, 900, 450)) mfrow3d(1L, 2L) view3d(0, -70, zoom = 0.8) shade3d(rglMesh, color = "firebrick") next3d() view3d(0, -70, zoom = 0.8) shade3d(rglClippedMesh, color = "firebrick") shade3d(sphere, color = "yellow", alpha = 0.15)
clipToPlane()
Clip the mesh to a plane. The mesh must be triangle. Face properties (colors, scalars) are preserved.
cgalMesh$clipToPlane(planePoint, planeNormal, clipVolume)
planePoint
numeric vector of length three, a point belonging to the plane
planeNormal
numeric vector of length three, a vector orthogonal to the plane
clipVolume
Boolean, whether to clip on the volume
If clipVolume=FALSE
, the modified reference mesh is
invisibly returned. If clipVolume=TRUE
, a list of two
cgalMesh
objects is returned: the first one is the part of
the clipped mesh corresponding to the original mesh, the second
one is the part of the clipped mesh corresponding to the plane.
library(cgalMeshes) library(rgl) rmesh <- sphereMesh() mesh <- cgalMesh$new(rmesh) nfaces <- nrow(mesh$getFaces()) if(require("randomcoloR")) { colors <- randomColor(nfaces, hue = "random", luminosity = "dark") } else { colors <- rainbow(nfaces) } mesh$assignFaceColors(colors) meshes <- mesh$clipToPlane( planePoint = c(0, 0, 0), planeNormal = c(0, 0, 1), clipVolume = TRUE ) mesh1 <- meshes[[1]] mesh2 <- meshes[[2]] mesh1$computeNormals() rClippedMesh1 <- mesh1$getMesh() rClippedMesh2 <- mesh2$getMesh() open3d(windowRect = 50 + c(0, 0, 512, 512)) view3d(70, 0) shade3d(rClippedMesh1, meshColor = "faces") shade3d(rClippedMesh2, color = "orange")
clipToIsoCuboid()
Clip the mesh to an iso-oriented cuboid. The mesh must be triangle. Face properties (colors, scalars) are preserved.
cgalMesh$clipToIsoCuboid(lcorner, ucorner, clipVolume)
lcorner, ucorner
two diagonally opposite vertices of the
iso-oriented cuboid, the smallest and the largest (see
isoCuboidMesh
)
clipVolume
Boolean, whether to clip on the volume
If clipVolume=FALSE
, the modified reference mesh is
invisibly returned. If clipVolume=TRUE
, a list of two
cgalMesh
objects is returned: the first one is the part of
the clipped mesh corresponding to the original mesh, the second
one is the part of the clipped mesh corresponding to the cuboid.
library(cgalMeshes) library(rgl) rmesh <- HopfTorusMesh(nu = 200, nv = 200) mesh <- cgalMesh$new(rmesh) mesh$assignFaceColors("orangered") lcorner <- c(-7, -7, -5) ucorner <- c(7, 6, 5) bxmesh <- isoCuboidMesh(lcorner, ucorner) mesh$clipToIsoCuboid( lcorner, ucorner, clipVolume = FALSE ) mesh$computeNormals() rClippedMesh <- mesh$getMesh() open3d(windowRect = 50 + c(0, 0, 512, 512)) view3d(-40, 0) shade3d(rClippedMesh, meshColor = "faces") shade3d(bxmesh, color = "cyan", alpha = 0.3)
computeNormals()
Compute per-vertex normals of the mesh.
cgalMesh$computeNormals()
The current cgalMesh
object, invisibly.
To get the normals, use the getNormals
method.
connectedComponents()
Decomposition into connected components. All face properties (colors, scalars) and vertex properties (colors, scalars, normals) are preserved.
cgalMesh$connectedComponents(triangulate = FALSE)
triangulate
Boolean, whether to triangulate the connected components.
A list of cgalMesh
objects, one for each connected
component.
library(cgalMeshes) library(rmarchingcubes) # isosurface function (slice of a seven-dimensional toratope) f <- function(x, y, z, a) { (sqrt( (sqrt((sqrt((x*sin(a))^2 + (z*cos(a))^2) - 5)^2 + (y*sin(a))^2) - 2.5)^2 + (x*cos(a))^2) - 1.25 )^2 + (sqrt((sqrt((z*sin(a))^2 + (y*cos(a))^2) - 2.5)^2) - 1.25)^2 } # make grid n <- 200L x <- seq(-10, 10, len = n) y <- seq(-10, 10, len = n) z <- seq(-10, 10, len = n) Grid <- expand.grid(X = x, Y = y, Z = z) # compute isosurface voxel <- array(with(Grid, f(X, Y, Z, a = pi/2)), dim = c(n, n, n)) isosurface <- contour3d(voxel, level = 0.25, x = x, y = y, z = z) # make CGAL mesh mesh <- cgalMesh$new( vertices = isosurface[["vertices"]], faces = isosurface[["triangles"]], normals = isosurface[["normals"]] ) # connected components components <- mesh$connectedComponents() ncc <- length(components) # plot library(rgl) colors <- rainbow(ncc) open3d(windowRect = 50 + c(0, 0, 512, 512)) view3d(30, 50) for(i in 1L:ncc) { rglMesh <- components[[i]]$getMesh() shade3d(rglMesh, color = colors[i]) }
convexParts()
Decomposition into convex parts. The mesh must be triangle.
cgalMesh$convexParts(triangulate = TRUE)
triangulate
Boolean, whether to triangulate the convex parts
A list of cgalMesh
objects, one for each convex part.
library(cgalMeshes) library(rgl) mesh <- cgalMesh$new(pentagrammicPrism)$triangulate() cxparts <- mesh$convexParts() ncxparts <- length(cxparts) colors <- hcl.colors(ncxparts, palette = "plasma") open3d(windowRect = 50 + c(0, 0, 512, 512)) view3d(20, -20, zoom = 0.8) for(i in 1L:ncxparts) { cxmesh <- cxparts[[i]]$getMesh() shade3d(cxmesh, color = colors[i]) }
copy()
Copy the mesh. This can change the order of the vertices.
cgalMesh$copy()
A new cgalMesh
object.
library(rgl) mesh <- cgalMesh$new(cube3d()) tmesh <- mesh$copy()$triangulate() tmesh$isTriangle() # TRUE mesh$isTriangle() # FALSE
distance()
Distance from one or more points to the mesh. The mesh must be triangle.
cgalMesh$distance(points)
points
either one point given as a numeric vector or several points given as a numeric matrix with three columns
A numeric vector providing the distances between the given point(s) to the mesh.
# cube example #### library(cgalMeshes) mesh <- cgalMesh$new(rgl::cube3d())$triangulate() points <- rbind( c(0, 0, 0), c(1, 1, 1) ) mesh$distance(points) # should be 1 and 0 # cyclide example #### library(cgalMeshes) a <- 100; c <- 30; mu <- 80 mesh <- cgalMesh$new(cyclideMesh(a, c, mu, nu = 100L, nv = 100L)) O2 <- c(c, 0, 0) # should be a - mu = 20 (see ?cyclideMesh): mesh$distance(O2)
DooSabin()
Performs the Doo-Sabin subdivision and deformation.
cgalMesh$DooSabin(iterations = 1)
iterations
number of iterations
The modified reference mesh, invisibly.
library(cgalMeshes) library(rgl) hopfMesh <- HopfTorusMesh(nu = 80, nv = 40) mesh <- cgalMesh$new(hopfMesh) mesh$DooSabin(iterations = 2) mesh$triangulate() mesh$computeNormals() rmesh <- mesh$getMesh() # plot open3d(windowRect = 50 + c(0, 0, 800, 400)) mfrow3d(1, 2) view3d(0, 0, zoom = 0.9) shade3d(hopfMesh, color = "brown") wire3d(hopfMesh, color = "black") next3d() view3d(0, 0, zoom = 0.9) shade3d(rmesh, color = "brown") wire3d(rmesh, color = "black")
facesAroundVertex()
Faces containing a given vertex.
cgalMesh$facesAroundVertex(v)
v
a vertex index
An integer vector, the indices of the faces containing v
.
fair()
Fair a region of the mesh, i.e. make it smooth. The mesh must be triangle. This modifies the reference mesh. All face properties and vertex properties except the normals are preserved.
cgalMesh$fair(indices)
indices
the indices of the vertices in the region to be faired
The modified cgalMesh
object.
library(cgalMeshes) rglHopf <- HopfTorusMesh(nu = 100, nv = 100) hopf <- cgalMesh$new(rglHopf) # squared norms of the vertices normsq <- apply(hopf$getVertices(), 1L, crossprod) # fair the region where the squared norm is > 19 indices <- which(normsq > 19) hopf$fair(indices) rglHopf_faired <- hopf$getMesh() # plot library(rgl) open3d(windowRect = 50 + c(0, 0, 900, 450)) mfrow3d(1L, 2L) view3d(0, 0, zoom = 0.8) shade3d(rglHopf, color = "orangered") next3d() view3d(0, 0, zoom = 0.8) shade3d(rglHopf_faired, color = "orangered")
fillBoundaryHole()
Fill a hole in the mesh. The face properties and the vertex properties are preserved.
cgalMesh$fillBoundaryHole(border, fair = TRUE)
border
index of the boundary cycle forming the hole to be
filled; the boundary cycles can be identified with
$getBorders()
fair
Boolean, whether to fair (i.e. smooth) the filled hole
The filled hole as a cgalMesh
object. The reference
mesh is updated.
library(cgalMeshes) library(rgl) # make a sphere sphere <- sphereMesh() mesh <- cgalMesh$new(sphere) # make a hole in this sphere mesh$clipToPlane( planePoint = c(0.5, 0, 0), planeNormal = c(1, 0, 0), clipVolume = FALSE ) mesh$computeNormals() rmesh <- mesh$getMesh() # fill the hole hole <- mesh$fillBoundaryHole(1, fair = TRUE) hole$computeNormals() rhole <- hole$getMesh() # plot open3d(windowRect = 50 + c(0, 0, 512, 512)) view3d(30, 30) shade3d(rmesh, color = "red") shade3d(rhole, color = "blue")
fillFaceColors()
Replace missing face colors with a color.
cgalMesh$fillFaceColors(color)
color
the color to replace the missing face colors
The reference mesh, invisibly.
filterMesh()
Split the mesh into two meshes according to a given set of selected faces. Face properties are preserved.
cgalMesh$filterMesh(faces)
faces
a vector of face indices
Two cgalMesh
objects. The first one is the mesh consisting
of the faces of the reference mesh given in the faces
argument. The second one is the complementary mesh.
library(rgl) library(cgalMeshes) rmesh <- HopfTorusMesh(nu = 80, nv = 60) mesh <- cgalMesh$new(rmesh) areas <- mesh$getFacesInfo()[, "area"] bigFaces <- which(areas > 1) meshes <- mesh$filterMesh(bigFaces) rmesh1 <- meshes[[1]]$getMesh() rmesh2 <- meshes[[2]]$getMesh() open3d(windowRect = 50 + c(0, 0, 512, 512)) view3d(0, 0) shade3d(rmesh1, color = "red") shade3d(rmesh2, color = "blue") wire3d(rmesh)
fixManifoldness()
Duplicate non-manifold vertices.
cgalMesh$fixManifoldness()
The possibly modified reference mesh, invisibly.
geoDists()
Estimated geodesic distances between vertices. The mesh must be triangle.
cgalMesh$geoDists(index)
index
index of the source vertex
The estimated geodesic distances from the source vertex to each vertex.
# torus #### library(cgalMeshes) library(rgl) rglmesh <- torusMesh(R = 3, r = 2, nu = 90, nv = 60) mesh <- cgalMesh$new(rglmesh) # estimated geodesic distances geodists <- mesh$geoDists(1L) # normalization to (0, 1) geodists <- geodists / max(geodists) # color each vertex according to its geodesic distance from the source fcolor <- colorRamp(viridisLite::turbo(200L)) colors <- fcolor(geodists) colors <- rgb(colors[, 1L], colors[, 2L], colors[, 3L], maxColorValue = 255) rglmesh[["material"]] <- list("color" = colors) # plot open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.8) shade3d(rglmesh) wire3d(rglmesh, color = "black") if(!rgl.useNULL()) { play3d(spin3d(axis = c(1, 1, 1), rpm = 5), duration = 20) } # a trefoil knot (taken from `?rgl::cylinder3d`) #### library(cgalMeshes) library(rgl) theta <- seq(0, 2*pi, length.out = 50L) knot <- cylinder3d( center = cbind( sin(theta) + 2*sin(2*theta), 2*sin(3*theta), cos(theta) - 2*cos(2*theta)), e1 = cbind( cos(theta) + 4*cos(2*theta), 6*cos(3*theta), sin(theta) + 4*sin(2*theta)), radius = 0.8, closed = TRUE) knot <- subdivision3d(knot, depth = 2) mesh <- cgalMesh$new(knot)$triangulate() rglmesh <- mesh$getMesh() # estimated geodesic distances geodists <- mesh$geoDists(1L) # normalization to (0, 1) geodists <- geodists / max(geodists) # color each vertex according to its geodesic distance from the source fcolor <- colorRamp(viridisLite::inferno(200L)) colors <- fcolor(geodists) colors <- rgb(colors[, 1L], colors[, 2L], colors[, 3L], maxColorValue = 255) rglmesh[["material"]] <- list("color" = colors) # plot open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.8) shade3d(rglmesh) if(!rgl.useNULL()) { play3d(spin3d(axis = c(1, 1, 0), rpm = 5), duration = 20) }
getBorders()
Get the borders of the mesh.
cgalMesh$getBorders()
A list of matrices representing the boundary cycles. Each matrix
has three columns: "edge"
, an edge index, and
"v1"
and "v2"
, the vertex indices of this edge.
library(cgalMeshes) library(rgl) # isosurface f=0 f <- function(x, y, z) { sin_x <- sin(x) sin_y <- sin(y) sin_z <- sin(z) cos_x <- cos(x) cos_y <- cos(y) cos_z <- cos(z) d <- sqrt( (-sin_x * sin_y + cos_x * cos_z) ** 2 + (-sin_y * sin_z + cos_y * cos_x) ** 2 + (-sin_z * sin_x + cos_z * cos_y) ** 2 ) ( cos( x - (-sin_x * sin_y + cos_x * cos_z) / d ) * sin( y - (-sin_y * sin_z + cos_y * cos_x) / d ) + cos( y - (-sin_y * sin_z + cos_y * cos_x) / d ) * sin( z - (-sin_z * sin_x + cos_z * cos_y)/ d ) + cos( z - (-sin_z * sin_x + cos_z * cos_y) / d ) * sin( x - (-sin_x * sin_y + cos_x * cos_z) / d ) ) * ( ( cos( x + (-sin_x * sin_y + cos_x * cos_z) / d ) * sin( y + (-sin_y * sin_z + cos_y * cos_x) / d ) + cos( y + (-sin_y * sin_z + cos_y * cos_x) / d ) * sin( z + (-sin_z * sin_x + cos_z * cos_y) / d ) + cos( z + (-sin_z * sin_x + cos_z * cos_y) / d ) * sin( x + (-sin_x * sin_y + cos_x * cos_z) / d ) ) ) } # construct the isosurface f=0 ngrid <- 200L x <- y <- z <- seq(-8.1, 8.1, length.out = ngrid) Grid <- expand.grid(X = x, Y = y, Z = z) voxel <- array( with(Grid, f(X, Y, Z)), dim = c(ngrid, ngrid, ngrid) ) library(rmarchingcubes) contour_shape <- contour3d( griddata = voxel, level = 0, x = x, y = y, z = z ) # make mesh mesh <- cgalMesh$new( list( "vertices" = contour_shape[["vertices"]], "faces" = contour_shape[["triangles"]] ) ) # clip the mesh to the ball of radius 8 spheremesh <- cgalMesh$new(sphereMesh(r = 8)) mesh$clip(spheremesh, clipVolume = FALSE) # compute normals mesh$computeNormals() # we will plot the borders borders <- mesh$getBorders() # plot rmesh <- mesh$getMesh() open3d(windowRect = c(50, 50, 562, 562), zoom = 0.7) shade3d(rmesh, color = "darkred") vertices <- mesh$getVertices() for(border in borders){ plotEdges( vertices, border[, c("v1", "v2")], color = "gold", lwd = 3, edgesAsTubes = FALSE, verticesAsSpheres = FALSE ) }
getEdges()
Get the edges of the mesh.
cgalMesh$getEdges()
A dataframe with seven columns; the first two ones give the
vertex indices of each edge (one edge per row), the third one gives
the lengths of each edge, the fourth one indicates whether the edges
is a border edge, the fifth one gives the dihedral angles
in degrees between the two faces adjacent to each edge, and the last
two ones gives the indices of the faces the edge belongs to (the
second index is NA
if the edge is a border edge).
library(rgl) mesh <- cgalMesh$new(dodecahedron3d()) head(mesh$getEdges())
getFaces()
Get the faces of the mesh.
cgalMesh$getFaces()
The faces in a matrix if the mesh is triangle or quad, otherwise in a list.
getFacesInfo()
Get the centroids, the circumcenters, and the areas of the faces, for a triangle mesh only.
cgalMesh$getFacesInfo()
A matrix with seven columns: the first three ones provide the Cartesian coordinates of the centroids, the three next ones provide the Cartesian coordinates of the circumcenters, and the last one provides the areas.
getFaceColors()
Get the face colors (if there are).
cgalMesh$getFaceColors()
The vector of colors (or any character vector) attached to
the faces of the mesh, or NULL
if nothing is assigned to
the faces.
getFaceScalars()
Get the face scalars (if there are).
cgalMesh$getFaceScalars()
The vector of scalars attached to
the faces of the mesh, or NULL
if nothing is assigned to
the faces.
getVertexColors()
Get the vertex colors (if there are).
cgalMesh$getVertexColors()
The vector of colors (or any character vector) attached to
the vertices of the mesh, or NULL
if nothing is assigned to
the vertices.
getVertexScalars()
Get the vertex scalars (if there are).
cgalMesh$getVertexScalars()
The vector of scalars attached to
the vertices of the mesh, or NULL
if nothing is assigned to
the vertices.
getNormals()
Get the per-vertex normals (if there are).
cgalMesh$getNormals()
The matrix of per-vertex normals if they have been given or
computed (see computeNormals
, or NULL
otherwise.
getMesh()
Get the mesh.
cgalMesh$getMesh(rgl = TRUE, ...)
rgl
Boolean, whether to return a rgl mesh if possible, i.e. if the mesh only has triangular or quadrilateral faces
...
arguments passed to mesh3d
(if
a rgl mesh is returned)
A rgl mesh or a list with two or three fields:
vertices
, faces
, and normals
if XXXXXXXXXXXXXXXXXXXXXXXXX the argument
normals
is set to TRUE
library(rgl) mesh <- cgalMesh$new(cube3d())$triangulate() mesh$getMesh()
getVertices()
Get the vertices of the mesh.
cgalMesh$getVertices()
The vertices in a matrix.
HausdorffApproximate()
Approximate Hausdorff distance between the reference mesh and another mesh.
cgalMesh$HausdorffApproximate(mesh2, symmetric = TRUE)
mesh2
a cgalMesh
object
symmetric
Boolean, whether to consider the symmetric Hausdorff distance.
A number. The algorithm uses some simulations and thus the result can vary.
HausdorffEstimate()
Estimate of Hausdorff distance between the reference mesh and another mesh.
cgalMesh$HausdorffEstimate(mesh2, errorBound = 1e-04, symmetric = TRUE)
mesh2
a cgalMesh
object
errorBound
a positive number, a bound on the error of the estimate
symmetric
Boolean, whether to consider the symmetric Hausdorff distance.
A number.
intersection()
Intersection with another mesh.
cgalMesh$intersection(mesh2)
mesh2
a cgalMesh
object
A cgalMesh
object.
library(cgalMeshes) library(rgl) # take two cubes rglmesh1 <- cube3d() rglmesh2 <- translate3d(cube3d(), 1, 1, 1) mesh1 <- cgalMesh$new(rglmesh1) mesh2 <- cgalMesh$new(rglmesh2) # the two meshes must be triangle mesh1$triangulate() mesh2$triangulate() # intersection imesh <- mesh1$intersection(mesh2) rglimesh <- imesh$getMesh() # extract edges for plotting extEdges <- exteriorEdges(imesh$getEdges()) # plot open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.9) shade3d(rglimesh, color = "red") plotEdges(imesh$getVertices(), extEdges) shade3d(rglmesh1, color = "yellow", alpha = 0.2) shade3d(rglmesh2, color = "cyan", alpha = 0.2)
isClosed()
Check whether the mesh is closed.
cgalMesh$isClosed()
A Boolean value, whether the mesh is closed.
isotropicRemeshing()
Isotropic remeshing.
cgalMesh$isotropicRemeshing(targetEdgeLength, iterations = 1, relaxSteps = 1)
targetEdgeLength
positive number, the target edge length of the remeshed mesh
iterations
number of iterations, a positive integer
relaxSteps
number of relaxation steps, a positive integer
The modified cgalMesh
object, invisibly.
library(cgalMeshes) library(rgl) mesh <- cgalMesh$new(HopfTorusMesh(nu = 80, nv = 50)) mesh$isotropicRemeshing(targetEdgeLength = 0.7) # squared norms of the vertices normsq <- apply(mesh$getVertices(), 1L, crossprod) # fair the region where the squared norm is > 19 mesh$fair(which(normsq > 19)) # plot mesh$computeNormals() rmesh <- mesh$getMesh() open3d(windowRect = 50 + c(0, 0, 512, 512)) view3d(0, 0) shade3d(rmesh, color = "maroon") wire3d(rmesh)
isOutwardOriented()
Check whether the mesh is outward oriented. The mesh must be triangle.
cgalMesh$isOutwardOriented()
A Boolean value, whether the mesh is outward oriented.
library(rgl) mesh <- cgalMesh$new(tetrahedron3d()) mesh$isOutwardOriented() # TRUE mesh$reverseOrientation() mesh$isOutwardOriented() # FALSE
isTriangle()
Check whether the mesh is triangle.
cgalMesh$isTriangle()
A Boolean value, whether the mesh is triangle.
library(rgl) mesh <- cgalMesh$new(cube3d()) mesh$isTriangle()
isValid()
Check whether the mesh is valid.
cgalMesh$isValid()
A Boolean value, whether the mesh is valid.
isValidFaceGraph()
Check whether the mesh is valid.
cgalMesh$isValidFaceGraph()
A Boolean value, whether the mesh is valid.
isValidHalfedgeGraph()
Check whether the mesh is valid.
cgalMesh$isValidHalfedgeGraph()
A Boolean value, whether the mesh is valid.
isValidPolygonMesh()
Check whether the mesh is valid.
cgalMesh$isValidPolygonMesh()
A Boolean value, whether the mesh is valid.
LoopSubdivision()
Performs the Loop subdivision and deformation.
cgalMesh$LoopSubdivision(iterations = 1)
iterations
number of iterations
The modified reference mesh, invisibly.
library(cgalMeshes) library(rgl) hopfMesh <- HopfTorusMesh(nu = 80, nv = 40) mesh <- cgalMesh$new(hopfMesh) mesh$LoopSubdivision(iterations = 2) mesh$computeNormals() rmesh <- mesh$getMesh() # plot open3d(windowRect = 50 + c(0, 0, 800, 400)) mfrow3d(1, 2) view3d(0, 0, zoom = 0.9) shade3d(hopfMesh, color = "gold") wire3d(hopfMesh, color = "black") next3d() view3d(0, 0, zoom = 0.9) shade3d(rmesh, color = "gold") wire3d(rmesh, color = "black")
merge()
Merge the mesh and another mesh.
cgalMesh$merge(mesh2)
mesh2
a cgalMesh
object
The updated reference mesh, invisibly.
library(cgalMeshes) library(rgl) mesh1 <- cgalMesh$new(sphereMesh()) mesh1$assignFaceColors("red") mesh2 <- cgalMesh$new(sphereMesh(x = 3)) mesh2$assignFaceColors("blue") mesh1$merge(mesh2) rmesh <- mesh1$getMesh() open3d(windowRect = c(50, 50, 562, 562)) shade3d(rmesh, meshColor = "faces")
orientToBoundVolume()
Reorient the connected components of the mesh in order that it bounds a volume. The mesh must be triangle.
cgalMesh$orientToBoundVolume()
The modified cgalMesh
object, invisibly. WARNING:
even if you store the result in a new variable, the original mesh is
modified.
# two disjoint tetrahedra #### vertices <- rbind( c(0, 0, 0), c(2, 2, 0), c(2, 0, 2), c(0, 2, 2), c(3, 3, 3), c(5, 5, 3), c(5, 3, 5), c(3, 5, 5) ) faces <- rbind( c(3, 2, 1), c(3, 4, 2), c(1, 2, 4), c(4, 3, 1), c(5, 6, 7), c(6, 8, 7), c(8, 6, 5), c(5, 7, 8) ) mesh <- cgalMesh$new(vertices = vertices, faces = faces) mesh$boundsVolume() # FALSE mesh$orientToBoundVolume() mesh$boundsVolume() # TRUE
removeSelfIntersections()
Remove self-intersections (experimental). The mesh must be triangle.
cgalMesh$removeSelfIntersections()
The modified cgalMesh
object, invisibly.
reverseOrientation()
Reverse the orientation of the faces of the mesh.
cgalMesh$reverseOrientation()
The modified cgalMesh
object, invisibly. WARNING:
even if you store the result in a new variable, the original mesh is
modified.
library(rgl) mesh <- cgalMesh$new(tetrahedron3d()) mesh$isOutwardOriented() # TRUE mesh$reverseOrientation() mesh$isOutwardOriented() # FALSE
sample()
Random sampling on the mesh. The mesh must be triangle.
cgalMesh$sample(nsims)
nsims
integer, the desired number of simulations
A nsims x 3
matrix containing the simulations.
selfIntersects()
Check whether the mesh self-intersects. The mesh must be triangle.
cgalMesh$selfIntersects()
A Boolean value, whether the mesh self-intersects.
library(rgl) mesh <- cgalMesh$new(dodecahedron3d()) mesh$selfIntersects()
sharpEdges()
Returns edges considered to be sharp according to the given angle bound.
cgalMesh$sharpEdges(angleBound)
angleBound
angle bound in degrees; an edge whose corresponding dihedral angle is smaller than this bound is considered as sharp
An integer matrix with three columns: "edge"
, an edge
index, and "v1"
and "v2"
, the vertex indices of this
edge.
library(cgalMeshes) library(rgl) # astroidal ellipsoid f <- function(u, v) { rbind( cos(u)^3 * cos(v)^3, sin(u)^3 * cos(v)^3, sin(v)^3 ) } rmesh <- parametricMesh( f, urange = c(0, 2*pi), vrange = c(0, 2*pi), periodic = c(TRUE, TRUE), nu = 120, nv = 110 ) mesh <- cgalMesh$new(rmesh) sharpEdges <- mesh$sharpEdges(30) # plot open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.8) shade3d(addNormals(rmesh), color = "chartreuse") plotEdges( mesh$getVertices(), sharpEdges[, c("v1", "v2")], edgesAsTubes = FALSE, lwd = 5, verticesAsSpheres = FALSE )
Sqrt3Subdivision()
Performs the 'Sqrt3' subdivision and deformation. The mesh must be triangle.
cgalMesh$Sqrt3Subdivision(iterations = 1)
iterations
number of iterations
The modified reference mesh, invisibly.
library(cgalMeshes) library(rgl) hopfMesh <- HopfTorusMesh(nu = 80, nv = 40) mesh <- cgalMesh$new(hopfMesh) mesh$Sqrt3Subdivision(iterations = 2) mesh$computeNormals() rmesh <- mesh$getMesh() # plot open3d(windowRect = 50 + c(0, 0, 800, 400)) mfrow3d(1, 2) view3d(0, 0, zoom = 0.9) shade3d(hopfMesh, color = "cyan") wire3d(hopfMesh, color = "black") next3d() view3d(0, 0, zoom = 0.9) shade3d(rmesh, color = "cyan") wire3d(rmesh, color = "black")
subtract()
Subtract a mesh. Both meshes must be triangle. Face
properties of the two meshes are copied to the new mesh.
WARNING: this modifies the reference mesh and mesh2
.
cgalMesh$subtract(mesh2)
mesh2
a cgalMesh
object
A cgalMesh
object, the difference between the reference
mesh and mesh2
. Both the reference mesh and mesh2
are
modified: they are corefined.
library(cgalMeshes) library(rgl) # take two cubes rglmesh1 <- cube3d() rglmesh2 <- translate3d(cube3d(), 1, 1, 1) mesh1 <- cgalMesh$new(rglmesh1) mesh2 <- cgalMesh$new(rglmesh2) # the two meshes must be triangle mesh1$triangulate() mesh2$triangulate() # assign colors mesh1$assignFaceColors("red") mesh2$assignFaceColors("navy") # difference mesh <- mesh1$subtract(mesh2) rglmesh <- mesh$getMesh() # extract edges for plotting extEdges <- exteriorEdges(mesh$getEdges()) # plot open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.9) shade3d(rglmesh, meshColor = "faces") plotEdges(mesh$getVertices(), extEdges) shade3d(rglmesh2, color = "cyan", alpha = 0.2)
triangulate()
Triangulate mesh.
cgalMesh$triangulate()
The modified cgalMesh
object, invisibly. WARNING:
even if you store the result in a new variable, the original mesh is
modified (see the example). You may want to triangulate a copy of the
mesh; see the copy
method.
library(rgl) mesh <- cgalMesh$new(cube3d()) mesh$isTriangle() # FALSE # warning: triangulating the mesh modifies it mesh$triangulate() mesh$isTriangle() # TRUE
union()
Union with another mesh. Both meshes must be triangle. Face
properties of the two united meshes are copied to the union mesh.
WARNING: this modifies the reference mesh and mesh2
.
cgalMesh$union(mesh2)
mesh2
a cgalMesh
object
A cgalMesh
object, the union of the reference mesh with
mesh2
. Both the reference mesh and mesh2
are modified:
they are corefined.
library(cgalMeshes) library(rgl) # take two cubes rglmesh1 <- cube3d() rglmesh2 <- translate3d(cube3d(), 1, 1, 1) mesh1 <- cgalMesh$new(rglmesh1) mesh2 <- cgalMesh$new(rglmesh2) # the two meshes must be triangle mesh1$triangulate() mesh2$triangulate() # assign a color to the faces; they will be retrieved in the union mesh1$assignFaceColors("yellow") mesh2$assignFaceColors("navy") # union umesh <- mesh1$union(mesh2) rglumesh <- umesh$getMesh() # extract edges for plotting extEdges <- exteriorEdges(umesh$getEdges()) # plot open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.9) shade3d(rglumesh, meshColor = "faces") plotEdges(umesh$getVertices(), extEdges)
volume()
Compute the volume of the mesh. The mesh must be closed, triangle, and must not self-intersect.
cgalMesh$volume()
A number, the mesh volume.
library(rgl) mesh <- cgalMesh$new(cube3d())$triangulate() mesh$volume()
whereIs()
Locate points with respect to a closed triangle mesh.
cgalMesh$whereIs(points)
points
a numeric matrix with three columns
An integer vector taking values -1
for outside, 1
for inside, and 0
if the point is on the boundary.
library(cgalMeshes) mesh <- cgalMesh$new(sphereMesh()) pt1 <- c(0, 0, 0) # inside pt2 <- c(2, 0, 0) # outside mesh$whereIs(rbind(pt1, pt2))
writeMeshFile()
Write mesh to a file.
cgalMesh$writeMeshFile(filename, precision = 17, comments = "", binary = FALSE)
filename
path to the file to be written, with extension
off
or ply
; if you use the ply
format, the mesh
properties (vertex colors, face colors, normals) are written in the
file
precision
a positive integer, the desired number of decimal places
comments
for ply
extension only, a string to be included
in the header of the PLY file
binary
Boolean, for ply
extension only, whether to write
a binary ply
file
Nothing, just writes a file.
## ------------------------------------------------
## Method `cgalMesh$new`
## ------------------------------------------------
library(cgalMeshes)
meshFile <- system.file(
"extdata", "bigPolyhedron.off", package = "cgalMeshes"
)
mesh <- cgalMesh$new(meshFile)
rglmesh <- mesh$getMesh()
library(rgl)
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.9)
shade3d(rglmesh, color = "tomato")
plotEdges(
mesh$getVertices(), mesh$getEdges(), color = "darkred"
)
# this one has colors: ####
meshFile <- system.file(
"extdata", "pentagrammicDipyramid.ply", package = "cgalMeshes"
)
mesh <- cgalMesh$new(meshFile)
rmesh <- mesh$getMesh()
library(rgl)
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.85)
shade3d(rmesh, meshColor = "faces")
## ------------------------------------------------
## Method `cgalMesh$area`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(cube3d())$triangulate()
mesh$area()
## ------------------------------------------------
## Method `cgalMesh$boundingBox`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
rmesh <- cyclideMesh(a = 97, c = 32, mu = 57)
mesh <- cgalMesh$new(rmesh)
bbox <- mesh$boundingBox()
bxmesh <- isoCuboidMesh(bbox[["lcorner"]], bbox[["ucorner"]])
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(0, -60)
shade3d(rmesh, color = "gold")
wire3d(bxmesh, color = "black")
## ------------------------------------------------
## Method `cgalMesh$boundsVolume`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(tetrahedron3d())
mesh$boundsVolume() # TRUE
mesh$reverseOrientation()
mesh$boundsVolume() # TRUE
## ------------------------------------------------
## Method `cgalMesh$CatmullClark`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
hopfMesh <- HopfTorusMesh(nu = 80, nv = 40)
mesh <- cgalMesh$new(hopfMesh)
mesh$CatmullClark(iterations = 2)
mesh$computeNormals()
rmesh <- mesh$getMesh()
# plot
open3d(windowRect = 50 + c(0, 0, 800, 400))
mfrow3d(1, 2)
view3d(0, 0, zoom = 0.9)
shade3d(hopfMesh, color = "red")
wire3d(hopfMesh, color = "black")
next3d()
view3d(0, 0, zoom = 0.9)
shade3d(rmesh, color = "red")
wire3d(rmesh, color = "black")
## ------------------------------------------------
## Method `cgalMesh$centroid`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
mesh <- cgalMesh$new(icosahedron3d())
mesh$centroid()
## ------------------------------------------------
## Method `cgalMesh$clip`
## ------------------------------------------------
# cube clipped to sphere ####
library(cgalMeshes)
library(rgl)
mesh <- cgalMesh$new(cube3d())$triangulate()
clipper <- cgalMesh$new(sphereMesh(r= sqrt(2)))
mesh$assignFaceColors("blue")
clipper$assignFaceColors("red")
meshes <- mesh$clip(clipper, clipVolume = TRUE)
mesh1 <- meshes[[1]]
mesh2 <- meshes[[2]]
mesh2$computeNormals()
rglmesh1 <- mesh1$getMesh()
rglmesh2 <- mesh2$getMesh()
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(45, 45, zoom = 0.9)
shade3d(rglmesh1, meshColor = "faces")
shade3d(rglmesh2, meshColor = "faces")
# Togliatti surface clipped to a ball ####
library(rmarchingcubes)
library(rgl)
library(cgalMeshes)
# Togliatti surface equation: f(x,y,z) = 0
f <- function(x, y, z) {
64*(x-1) *
(x^4 - 4*x^3 - 10*x^2*y^2 - 4*x^2 + 16*x - 20*x*y^2 + 5*y^4 + 16 - 20*y^2) -
5*sqrt(5-sqrt(5))*(2*z - sqrt(5-sqrt(5))) *
(4*(x^2 + y^2 - z^2) + (1 + 3*sqrt(5)))^2
}
# grid
n <- 200L
x <- y <- seq(-5, 5, length.out = n)
z <- seq(-4, 4, length.out = n)
Grid <- expand.grid(X = x, Y = y, Z = z)
# calculate voxel
voxel <- array(with(Grid, f(X, Y, Z)), dim = c(n, n, n))
# calculate isosurface
contour_shape <- contour3d(
griddata = voxel, level = 0, x = x, y = y, z = z
)
# make rgl mesh (plotted later)
rglMesh <- tmesh3d(
vertices = t(contour_shape[["vertices"]]),
indices = t(contour_shape[["triangles"]]),
normals = contour_shape[["normals"]],
homogeneous = FALSE
)
# make CGAL mesh
mesh <- cgalMesh$new(rglMesh)
# clip to sphere of radius 4.8
sphere <- sphereMesh(r = 4.8)
clipper <- cgalMesh$new(sphere)
mesh$clip(clipper, clipVolume = FALSE)
rglClippedMesh <- mesh$getMesh()
# plot
open3d(windowRect = 50 + c(0, 0, 900, 450))
mfrow3d(1L, 2L)
view3d(0, -70, zoom = 0.8)
shade3d(rglMesh, color = "firebrick")
next3d()
view3d(0, -70, zoom = 0.8)
shade3d(rglClippedMesh, color = "firebrick")
shade3d(sphere, color = "yellow", alpha = 0.15)
## ------------------------------------------------
## Method `cgalMesh$clipToPlane`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
rmesh <- sphereMesh()
mesh <- cgalMesh$new(rmesh)
nfaces <- nrow(mesh$getFaces())
if(require("randomcoloR")) {
colors <-
randomColor(nfaces, hue = "random", luminosity = "dark")
} else {
colors <- rainbow(nfaces)
}
mesh$assignFaceColors(colors)
meshes <- mesh$clipToPlane(
planePoint = c(0, 0, 0),
planeNormal = c(0, 0, 1),
clipVolume = TRUE
)
mesh1 <- meshes[[1]]
mesh2 <- meshes[[2]]
mesh1$computeNormals()
rClippedMesh1 <- mesh1$getMesh()
rClippedMesh2 <- mesh2$getMesh()
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(70, 0)
shade3d(rClippedMesh1, meshColor = "faces")
shade3d(rClippedMesh2, color = "orange")
## ------------------------------------------------
## Method `cgalMesh$clipToIsoCuboid`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
rmesh <- HopfTorusMesh(nu = 200, nv = 200)
mesh <- cgalMesh$new(rmesh)
mesh$assignFaceColors("orangered")
lcorner <- c(-7, -7, -5)
ucorner <- c(7, 6, 5)
bxmesh <- isoCuboidMesh(lcorner, ucorner)
mesh$clipToIsoCuboid(
lcorner, ucorner, clipVolume = FALSE
)
mesh$computeNormals()
rClippedMesh <- mesh$getMesh()
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(-40, 0)
shade3d(rClippedMesh, meshColor = "faces")
shade3d(bxmesh, color = "cyan", alpha = 0.3)
## ------------------------------------------------
## Method `cgalMesh$connectedComponents`
## ------------------------------------------------
library(cgalMeshes)
library(rmarchingcubes)
# isosurface function (slice of a seven-dimensional toratope)
f <- function(x, y, z, a) {
(sqrt(
(sqrt((sqrt((x*sin(a))^2 + (z*cos(a))^2) - 5)^2 + (y*sin(a))^2) - 2.5)^2 +
(x*cos(a))^2) - 1.25
)^2 + (sqrt((sqrt((z*sin(a))^2 + (y*cos(a))^2) - 2.5)^2) - 1.25)^2
}
# make grid
n <- 200L
x <- seq(-10, 10, len = n)
y <- seq(-10, 10, len = n)
z <- seq(-10, 10, len = n)
Grid <- expand.grid(X = x, Y = y, Z = z)
# compute isosurface
voxel <- array(with(Grid, f(X, Y, Z, a = pi/2)), dim = c(n, n, n))
isosurface <- contour3d(voxel, level = 0.25, x = x, y = y, z = z)
# make CGAL mesh
mesh <- cgalMesh$new(
vertices = isosurface[["vertices"]],
faces = isosurface[["triangles"]],
normals = isosurface[["normals"]]
)
# connected components
components <- mesh$connectedComponents()
ncc <- length(components)
# plot
library(rgl)
colors <- rainbow(ncc)
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(30, 50)
for(i in 1L:ncc) {
rglMesh <- components[[i]]$getMesh()
shade3d(rglMesh, color = colors[i])
}
## ------------------------------------------------
## Method `cgalMesh$convexParts`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
mesh <- cgalMesh$new(pentagrammicPrism)$triangulate()
cxparts <- mesh$convexParts()
ncxparts <- length(cxparts)
colors <- hcl.colors(ncxparts, palette = "plasma")
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(20, -20, zoom = 0.8)
for(i in 1L:ncxparts) {
cxmesh <- cxparts[[i]]$getMesh()
shade3d(cxmesh, color = colors[i])
}
## ------------------------------------------------
## Method `cgalMesh$copy`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(cube3d())
tmesh <- mesh$copy()$triangulate()
tmesh$isTriangle() # TRUE
mesh$isTriangle() # FALSE
## ------------------------------------------------
## Method `cgalMesh$distance`
## ------------------------------------------------
# cube example ####
library(cgalMeshes)
mesh <- cgalMesh$new(rgl::cube3d())$triangulate()
points <- rbind(
c(0, 0, 0),
c(1, 1, 1)
)
mesh$distance(points) # should be 1 and 0
# cyclide example ####
library(cgalMeshes)
a <- 100; c <- 30; mu <- 80
mesh <- cgalMesh$new(cyclideMesh(a, c, mu, nu = 100L, nv = 100L))
O2 <- c(c, 0, 0)
# should be a - mu = 20 (see ?cyclideMesh):
mesh$distance(O2)
## ------------------------------------------------
## Method `cgalMesh$DooSabin`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
hopfMesh <- HopfTorusMesh(nu = 80, nv = 40)
mesh <- cgalMesh$new(hopfMesh)
mesh$DooSabin(iterations = 2)
mesh$triangulate()
mesh$computeNormals()
rmesh <- mesh$getMesh()
# plot
open3d(windowRect = 50 + c(0, 0, 800, 400))
mfrow3d(1, 2)
view3d(0, 0, zoom = 0.9)
shade3d(hopfMesh, color = "brown")
wire3d(hopfMesh, color = "black")
next3d()
view3d(0, 0, zoom = 0.9)
shade3d(rmesh, color = "brown")
wire3d(rmesh, color = "black")
## ------------------------------------------------
## Method `cgalMesh$fair`
## ------------------------------------------------
library(cgalMeshes)
rglHopf <- HopfTorusMesh(nu = 100, nv = 100)
hopf <- cgalMesh$new(rglHopf)
# squared norms of the vertices
normsq <- apply(hopf$getVertices(), 1L, crossprod)
# fair the region where the squared norm is > 19
indices <- which(normsq > 19)
hopf$fair(indices)
rglHopf_faired <- hopf$getMesh()
# plot
library(rgl)
open3d(windowRect = 50 + c(0, 0, 900, 450))
mfrow3d(1L, 2L)
view3d(0, 0, zoom = 0.8)
shade3d(rglHopf, color = "orangered")
next3d()
view3d(0, 0, zoom = 0.8)
shade3d(rglHopf_faired, color = "orangered")
## ------------------------------------------------
## Method `cgalMesh$fillBoundaryHole`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
# make a sphere
sphere <- sphereMesh()
mesh <- cgalMesh$new(sphere)
# make a hole in this sphere
mesh$clipToPlane(
planePoint = c(0.5, 0, 0),
planeNormal = c(1, 0, 0),
clipVolume = FALSE
)
mesh$computeNormals()
rmesh <- mesh$getMesh()
# fill the hole
hole <- mesh$fillBoundaryHole(1, fair = TRUE)
hole$computeNormals()
rhole <- hole$getMesh()
# plot
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(30, 30)
shade3d(rmesh, color = "red")
shade3d(rhole, color = "blue")
## ------------------------------------------------
## Method `cgalMesh$filterMesh`
## ------------------------------------------------
library(rgl)
library(cgalMeshes)
rmesh <- HopfTorusMesh(nu = 80, nv = 60)
mesh <- cgalMesh$new(rmesh)
areas <- mesh$getFacesInfo()[, "area"]
bigFaces <- which(areas > 1)
meshes <- mesh$filterMesh(bigFaces)
rmesh1 <- meshes[[1]]$getMesh()
rmesh2 <- meshes[[2]]$getMesh()
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(0, 0)
shade3d(rmesh1, color = "red")
shade3d(rmesh2, color = "blue")
wire3d(rmesh)
## ------------------------------------------------
## Method `cgalMesh$geoDists`
## ------------------------------------------------
# torus ####
library(cgalMeshes)
library(rgl)
rglmesh <- torusMesh(R = 3, r = 2, nu = 90, nv = 60)
mesh <- cgalMesh$new(rglmesh)
# estimated geodesic distances
geodists <- mesh$geoDists(1L)
# normalization to (0, 1)
geodists <- geodists / max(geodists)
# color each vertex according to its geodesic distance from the source
fcolor <- colorRamp(viridisLite::turbo(200L))
colors <- fcolor(geodists)
colors <- rgb(colors[, 1L], colors[, 2L], colors[, 3L], maxColorValue = 255)
rglmesh[["material"]] <- list("color" = colors)
# plot
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.8)
shade3d(rglmesh)
wire3d(rglmesh, color = "black")
if(!rgl.useNULL()) {
play3d(spin3d(axis = c(1, 1, 1), rpm = 5), duration = 20)
}
# a trefoil knot (taken from `?rgl::cylinder3d`) ####
library(cgalMeshes)
library(rgl)
theta <- seq(0, 2*pi, length.out = 50L)
knot <- cylinder3d(
center = cbind(
sin(theta) + 2*sin(2*theta),
2*sin(3*theta),
cos(theta) - 2*cos(2*theta)),
e1 = cbind(
cos(theta) + 4*cos(2*theta),
6*cos(3*theta),
sin(theta) + 4*sin(2*theta)),
radius = 0.8,
closed = TRUE)
knot <- subdivision3d(knot, depth = 2)
mesh <- cgalMesh$new(knot)$triangulate()
rglmesh <- mesh$getMesh()
# estimated geodesic distances
geodists <- mesh$geoDists(1L)
# normalization to (0, 1)
geodists <- geodists / max(geodists)
# color each vertex according to its geodesic distance from the source
fcolor <- colorRamp(viridisLite::inferno(200L))
colors <- fcolor(geodists)
colors <- rgb(colors[, 1L], colors[, 2L], colors[, 3L], maxColorValue = 255)
rglmesh[["material"]] <- list("color" = colors)
# plot
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.8)
shade3d(rglmesh)
if(!rgl.useNULL()) {
play3d(spin3d(axis = c(1, 1, 0), rpm = 5), duration = 20)
}
## ------------------------------------------------
## Method `cgalMesh$getBorders`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
# isosurface f=0
f <- function(x, y, z) {
sin_x <- sin(x)
sin_y <- sin(y)
sin_z <- sin(z)
cos_x <- cos(x)
cos_y <- cos(y)
cos_z <- cos(z)
d <- sqrt(
(-sin_x * sin_y + cos_x * cos_z) ** 2
+ (-sin_y * sin_z + cos_y * cos_x) ** 2
+ (-sin_z * sin_x + cos_z * cos_y) ** 2
)
(
cos(
x - (-sin_x * sin_y + cos_x * cos_z) / d
)
* sin(
y - (-sin_y * sin_z + cos_y * cos_x) / d
)
+ cos(
y - (-sin_y * sin_z + cos_y * cos_x) / d
)
* sin(
z - (-sin_z * sin_x + cos_z * cos_y)/ d
)
+ cos(
z - (-sin_z * sin_x + cos_z * cos_y) / d
)
* sin(
x - (-sin_x * sin_y + cos_x * cos_z) / d
)
) * (
(
cos(
x + (-sin_x * sin_y + cos_x * cos_z) / d
)
* sin(
y + (-sin_y * sin_z + cos_y * cos_x) / d
)
+ cos(
y + (-sin_y * sin_z + cos_y * cos_x) / d
)
* sin(
z + (-sin_z * sin_x + cos_z * cos_y) / d
)
+ cos(
z + (-sin_z * sin_x + cos_z * cos_y) / d
)
* sin(
x + (-sin_x * sin_y + cos_x * cos_z) / d
)
)
)
}
# construct the isosurface f=0
ngrid <- 200L
x <- y <- z <- seq(-8.1, 8.1, length.out = ngrid)
Grid <- expand.grid(X = x, Y = y, Z = z)
voxel <- array(
with(Grid, f(X, Y, Z)), dim = c(ngrid, ngrid, ngrid)
)
library(rmarchingcubes)
contour_shape <- contour3d(
griddata = voxel, level = 0,
x = x, y = y, z = z
)
# make mesh
mesh <- cgalMesh$new(
list(
"vertices" = contour_shape[["vertices"]],
"faces" = contour_shape[["triangles"]]
)
)
# clip the mesh to the ball of radius 8
spheremesh <- cgalMesh$new(sphereMesh(r = 8))
mesh$clip(spheremesh, clipVolume = FALSE)
# compute normals
mesh$computeNormals()
# we will plot the borders
borders <- mesh$getBorders()
# plot
rmesh <- mesh$getMesh()
open3d(windowRect = c(50, 50, 562, 562), zoom = 0.7)
shade3d(rmesh, color = "darkred")
vertices <- mesh$getVertices()
for(border in borders){
plotEdges(
vertices, border[, c("v1", "v2")], color = "gold",
lwd = 3, edgesAsTubes = FALSE, verticesAsSpheres = FALSE
)
}
## ------------------------------------------------
## Method `cgalMesh$getEdges`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(dodecahedron3d())
head(mesh$getEdges())
## ------------------------------------------------
## Method `cgalMesh$getMesh`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(cube3d())$triangulate()
mesh$getMesh()
## ------------------------------------------------
## Method `cgalMesh$intersection`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
# take two cubes
rglmesh1 <- cube3d()
rglmesh2 <- translate3d(cube3d(), 1, 1, 1)
mesh1 <- cgalMesh$new(rglmesh1)
mesh2 <- cgalMesh$new(rglmesh2)
# the two meshes must be triangle
mesh1$triangulate()
mesh2$triangulate()
# intersection
imesh <- mesh1$intersection(mesh2)
rglimesh <- imesh$getMesh()
# extract edges for plotting
extEdges <- exteriorEdges(imesh$getEdges())
# plot
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.9)
shade3d(rglimesh, color = "red")
plotEdges(imesh$getVertices(), extEdges)
shade3d(rglmesh1, color = "yellow", alpha = 0.2)
shade3d(rglmesh2, color = "cyan", alpha = 0.2)
## ------------------------------------------------
## Method `cgalMesh$isotropicRemeshing`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
mesh <- cgalMesh$new(HopfTorusMesh(nu = 80, nv = 50))
mesh$isotropicRemeshing(targetEdgeLength = 0.7)
# squared norms of the vertices
normsq <- apply(mesh$getVertices(), 1L, crossprod)
# fair the region where the squared norm is > 19
mesh$fair(which(normsq > 19))
# plot
mesh$computeNormals()
rmesh <- mesh$getMesh()
open3d(windowRect = 50 + c(0, 0, 512, 512))
view3d(0, 0)
shade3d(rmesh, color = "maroon")
wire3d(rmesh)
## ------------------------------------------------
## Method `cgalMesh$isOutwardOriented`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(tetrahedron3d())
mesh$isOutwardOriented() # TRUE
mesh$reverseOrientation()
mesh$isOutwardOriented() # FALSE
## ------------------------------------------------
## Method `cgalMesh$isTriangle`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(cube3d())
mesh$isTriangle()
## ------------------------------------------------
## Method `cgalMesh$LoopSubdivision`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
hopfMesh <- HopfTorusMesh(nu = 80, nv = 40)
mesh <- cgalMesh$new(hopfMesh)
mesh$LoopSubdivision(iterations = 2)
mesh$computeNormals()
rmesh <- mesh$getMesh()
# plot
open3d(windowRect = 50 + c(0, 0, 800, 400))
mfrow3d(1, 2)
view3d(0, 0, zoom = 0.9)
shade3d(hopfMesh, color = "gold")
wire3d(hopfMesh, color = "black")
next3d()
view3d(0, 0, zoom = 0.9)
shade3d(rmesh, color = "gold")
wire3d(rmesh, color = "black")
## ------------------------------------------------
## Method `cgalMesh$merge`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
mesh1 <- cgalMesh$new(sphereMesh())
mesh1$assignFaceColors("red")
mesh2 <- cgalMesh$new(sphereMesh(x = 3))
mesh2$assignFaceColors("blue")
mesh1$merge(mesh2)
rmesh <- mesh1$getMesh()
open3d(windowRect = c(50, 50, 562, 562))
shade3d(rmesh, meshColor = "faces")
## ------------------------------------------------
## Method `cgalMesh$orientToBoundVolume`
## ------------------------------------------------
# two disjoint tetrahedra ####
vertices <- rbind(
c(0, 0, 0),
c(2, 2, 0),
c(2, 0, 2),
c(0, 2, 2),
c(3, 3, 3),
c(5, 5, 3),
c(5, 3, 5),
c(3, 5, 5)
)
faces <- rbind(
c(3, 2, 1),
c(3, 4, 2),
c(1, 2, 4),
c(4, 3, 1),
c(5, 6, 7),
c(6, 8, 7),
c(8, 6, 5),
c(5, 7, 8)
)
mesh <- cgalMesh$new(vertices = vertices, faces = faces)
mesh$boundsVolume() # FALSE
mesh$orientToBoundVolume()
mesh$boundsVolume() # TRUE
## ------------------------------------------------
## Method `cgalMesh$reverseOrientation`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(tetrahedron3d())
mesh$isOutwardOriented() # TRUE
mesh$reverseOrientation()
mesh$isOutwardOriented() # FALSE
## ------------------------------------------------
## Method `cgalMesh$selfIntersects`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(dodecahedron3d())
mesh$selfIntersects()
## ------------------------------------------------
## Method `cgalMesh$sharpEdges`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
# astroidal ellipsoid
f <- function(u, v) {
rbind(
cos(u)^3 * cos(v)^3,
sin(u)^3 * cos(v)^3,
sin(v)^3
)
}
rmesh <- parametricMesh(
f, urange = c(0, 2*pi), vrange = c(0, 2*pi),
periodic = c(TRUE, TRUE), nu = 120, nv = 110
)
mesh <- cgalMesh$new(rmesh)
sharpEdges <- mesh$sharpEdges(30)
# plot
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.8)
shade3d(addNormals(rmesh), color = "chartreuse")
plotEdges(
mesh$getVertices(), sharpEdges[, c("v1", "v2")],
edgesAsTubes = FALSE, lwd = 5, verticesAsSpheres = FALSE
)
## ------------------------------------------------
## Method `cgalMesh$Sqrt3Subdivision`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
hopfMesh <- HopfTorusMesh(nu = 80, nv = 40)
mesh <- cgalMesh$new(hopfMesh)
mesh$Sqrt3Subdivision(iterations = 2)
mesh$computeNormals()
rmesh <- mesh$getMesh()
# plot
open3d(windowRect = 50 + c(0, 0, 800, 400))
mfrow3d(1, 2)
view3d(0, 0, zoom = 0.9)
shade3d(hopfMesh, color = "cyan")
wire3d(hopfMesh, color = "black")
next3d()
view3d(0, 0, zoom = 0.9)
shade3d(rmesh, color = "cyan")
wire3d(rmesh, color = "black")
## ------------------------------------------------
## Method `cgalMesh$subtract`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
# take two cubes
rglmesh1 <- cube3d()
rglmesh2 <- translate3d(cube3d(), 1, 1, 1)
mesh1 <- cgalMesh$new(rglmesh1)
mesh2 <- cgalMesh$new(rglmesh2)
# the two meshes must be triangle
mesh1$triangulate()
mesh2$triangulate()
# assign colors
mesh1$assignFaceColors("red")
mesh2$assignFaceColors("navy")
# difference
mesh <- mesh1$subtract(mesh2)
rglmesh <- mesh$getMesh()
# extract edges for plotting
extEdges <- exteriorEdges(mesh$getEdges())
# plot
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.9)
shade3d(rglmesh, meshColor = "faces")
plotEdges(mesh$getVertices(), extEdges)
shade3d(rglmesh2, color = "cyan", alpha = 0.2)
## ------------------------------------------------
## Method `cgalMesh$triangulate`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(cube3d())
mesh$isTriangle() # FALSE
# warning: triangulating the mesh modifies it
mesh$triangulate()
mesh$isTriangle() # TRUE
## ------------------------------------------------
## Method `cgalMesh$union`
## ------------------------------------------------
library(cgalMeshes)
library(rgl)
# take two cubes
rglmesh1 <- cube3d()
rglmesh2 <- translate3d(cube3d(), 1, 1, 1)
mesh1 <- cgalMesh$new(rglmesh1)
mesh2 <- cgalMesh$new(rglmesh2)
# the two meshes must be triangle
mesh1$triangulate()
mesh2$triangulate()
# assign a color to the faces; they will be retrieved in the union
mesh1$assignFaceColors("yellow")
mesh2$assignFaceColors("navy")
# union
umesh <- mesh1$union(mesh2)
rglumesh <- umesh$getMesh()
# extract edges for plotting
extEdges <- exteriorEdges(umesh$getEdges())
# plot
open3d(windowRect = 50 + c(0, 0, 512, 512), zoom = 0.9)
shade3d(rglumesh, meshColor = "faces")
plotEdges(umesh$getVertices(), extEdges)
## ------------------------------------------------
## Method `cgalMesh$volume`
## ------------------------------------------------
library(rgl)
mesh <- cgalMesh$new(cube3d())$triangulate()
mesh$volume()
## ------------------------------------------------
## Method `cgalMesh$whereIs`
## ------------------------------------------------
library(cgalMeshes)
mesh <- cgalMesh$new(sphereMesh())
pt1 <- c(0, 0, 0) # inside
pt2 <- c(2, 0, 0) # outside
mesh$whereIs(rbind(pt1, pt2))
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.