rgl (version 0.100.50)

clipMesh3d: Clip mesh to general region

Description

Modifies a mesh3d object so that values of a function are bounded.

Usage

clipMesh3d(mesh, fn, bound = 0, greater = TRUE, 
           attribute = "vertices")

Arguments

mesh

A mesh3d object.

fn

A function used to determine clipping, or a vector of values from such a function, with one value per vertex in the mesh.

bound

The value(s) of fn on the clipping boundary.

greater

Logical; whether to keep fn >= bound or not.

attribute

Which attribute(s) to pass to fn? Possible values are c("vertices", "normals", "texcoords", "index").

Value

A new mesh3d object in which all vertices (approximately) satisfy the clipping condition. Note that the order of vertices will likely differ from the original order, and new vertices will be added near the boundary.

Details

This function transforms a mesh3d object.

First, all quads are converted to triangles.

Next, each vertex is checked against the condition. If fn is a numeric vector, with one value per vertex, those values will be used in the test. If it is a function, it will be passed a matrix, whose columns are the specified attribute(s), with one row per vertex. It should return a vector of values, one per vertex, to check against the bound. The "vertices" and "normals" values will be converted to Euclidean coordinates. "index" will be an integer from 1 to the number of vertices.

Modifications to the triangles depend on how many of the vertices satisfy the condition (fn >= bound or fn <= bound, depending on greater) for inclusion.

  • If no vertices in a triangle satisfy the condition, the triangle is omitted.

  • If one vertex satisfies the condition, the other two vertices in that triangle are shrunk towards it by assuming fn is locally linear.

  • If two vertices satisfy the condition, the third vertex is shrunk along each edge towards each other vertex, forming a quadrilateral made of two new triangles.

  • If all vertices satisfy the condition, they are included with no modifications.

References

See https://stackoverflow.com/q/56242470/2554330 for the motivating example.

Examples

Run this code
# NOT RUN {
if (requireNamespace("misc3d")) {
  # Togliatti surface equation: f(x,y,z) = 0
  # Due to Stephane Laurent
  f <- function(x,y,z){
    w <- 1
    64*(x-w)*
      (x^4-4*x^3*w-10*x^2*y^2-4*x^2*w^2+16*x*w^3-20*x*y^2*w+5*y^4+16*w^4-20*y^2*w^2) -
      5*sqrt(5-sqrt(5))*(2*z-sqrt(5-sqrt(5))*w)*(4*(x^2+y^2-z^2)+(1+3*sqrt(5))*w^2)^2
  }
  # make grid
  # The original had 220 instead of 20, this is coarse to be quicker
  nx <- 20; ny <- 20; nz <- 20
  x <- seq(-5, 5, length=nx)
  y <- seq(-5, 5, length=ny)
  z <- seq(-4, 4, length=nz)
  g <- expand.grid(x=x, y=y, z=z)
  # calculate voxel
  voxel <- array(with(g, f(x,y,z)), dim = c(nx,ny,nz))
  
  # compute isosurface
  open3d(useNULL = TRUE)
  surf <- as.mesh3d(misc3d::contour3d(voxel, maxvol=max(voxel), level=0, x=x, y=y, z=z))
  rgl.close()
  
  surf$normals <- NULL
  surf <- mergeVertices(surf)
  surf <- addNormals(surf)
  
  fn <- function(x) {
    rowSums(x^2)
  }
  
  open3d()
  shade3d(clipMesh3d(surf, fn, bound = 4.8^2,
                     greater = FALSE), col="red")
}
# }

Run the code above in your browser using DataCamp Workspace