clipMesh3d {rgl}R Documentation

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").

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.

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.

Author(s)

Duncan Murdoch

References

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

Examples

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")
}

[Package rgl version 0.100.27 Index]