clipMesh3d: Clip mesh or 'rgl' object to general region

Description Usage Arguments Details Value Author(s) References See Also Examples

View source: R/clipMesh3d.R

Description

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

Usage

1
2
3
4
5
clipMesh3d(mesh, fn, bound = 0, greater = TRUE, 
           minVertices = 0, plot = FALSE, keepValues = FALSE)
clipObj3d(ids, fn, bound = 0, greater = TRUE,
           minVertices = 0,
           replace = TRUE)

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.

bound

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

greater

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

minVertices

See Details below.

plot

Logical; whether or not to plot the mesh.

keepValues

Logical; whether to save the function values at each vertex when plot = FALSE.

ids

The rgl id value(s) of objects to clip.

replace

Should the ids objects be deleted after the clipped ones are drawn?

Details

These functions transform a mesh3d object or other rgl objects by removing parts where fn violates the bound.

For clipMesh3d the fn argument can be any of the following:

For clipObj3d any of the above except NULL may be used.

If fn is a numeric vector, with one value per vertex, those values will be used in the test. If it is a function with formal arguments x, y and z, it will receive the coordinates of vertices in those arguments, otherwise it will receive the coordinates in a single n x 3 matrix. The function should be vectorized and return one value per vertex, to check against the bound.

These operations are performed on the mesh:

First, all quads are converted to triangles.

Next, each vertex is checked against the condition.

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

Modifications to line segments are similar: the segment will be shortened if it crosses the boundary, or omitted if it is entirely out of bounds. Points, spheres, text and sprites will just be kept or rejected.

The minVertices argument is used to improve the approximation to the boundary when fn is a non-linear function. In that case, the interpolation described above can be inaccurate. If minVertices is set to a positive number (e.g. 10000), then each object is modified by subdivision to have at least that number of vertices, so that pieces are smaller and the linear interpolation is more accurate. In the clipObj3d function, minVertices can be a vector, with entries corresponding to each of the entries in ids.

Value

If plot = FALSE, clipMesh3d returns 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 (and if minVertices > 0, in the interior). If in addition keepValues = TRUE, a component named "values" will be added to the mesh containing the values for each vertex.

If plot = TRUE, the result will be plotted with shade3d and its result returned.

clipObj3d is called for the side effect of modifying the scene. It returns a list of new rgl id values corresponding to the ids passed as arguments.

Author(s)

Duncan Murdoch

References

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

See Also

See contourLines3d and filledContour3d for ways to display function values without clipping.

Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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))
  close3d()
  
  surf$normals <- NULL
  surf <- mergeVertices(surf)
  surf <- addNormals(surf)
  
  fn <- function(x, y, z) {
    x^2 + y^2 + z^2
  }
  
  open3d()
  shade3d(clipMesh3d(surf, fn, bound = 4.8^2,
                     greater = FALSE), col="red")
}

# Show the problem that minVertices solves:

cube <- cube3d(col = "red")

# This function only has one argument, so it will 
# be passed x, y and z in columns of a matrix
vecnorm <- function(vals) apply(vals, 1, function(row) sqrt(sum(row^2)))

open3d()
mfrow3d(2, 2, sharedMouse = TRUE)
id1 <- shade3d(cube)
# All vertices have norm sqrt(3), so this clips nothing:
clipObj3d(id1, fn = vecnorm, bound = sqrt(2))
next3d()
id2 <- wire3d(cube, lit = FALSE)
clipObj3d(id2, fn = vecnorm, bound = sqrt(2))

# This subdivides the cube, and does proper clipping:
next3d()
id3 <- shade3d(cube)
clipObj3d(id3, fn = vecnorm, bound = sqrt(2), minVertices = 200)
next3d()
id4 <- wire3d(cube, lit = FALSE)
clipObj3d(id4, fn = vecnorm, bound = sqrt(2), minVertices = 200)

rgl documentation built on Feb. 1, 2021, 3:01 a.m.