8
$\begingroup$

In a recent project, I found out that there is a big limitation when using Graphics3D to construct objects - it lacks the ability to construct objects with holes in them. For example, we can get a regular wall-like Graphics3D object with the Cuboid primitive, but we can not get a wall with a window. Like this one enter image description here

Naturally, a Boolean operation is the way to go. But, in Mathematica the functions belonging to Boolean operations class, like RegionUnion and RegionIntersection can not be used in Graphics3D

Is there a way to construct Graphics3D objects with holes in them ?

$\endgroup$
5

2 Answers 2

8
$\begingroup$

This is a repost of Wolfram Community answer


Let's start from your code:

cub1 = Cuboid[{0, 0, 0}, {20, 2, 20}];
cub2 = Cuboid[{12, 0, 8}, {17, 2, 17}];
Graphics3D[{cub1, cub2}];
reg = DiscretizeRegion[RegionDifference[cub1, cub2]]

You have a lot of tetrahedrons:

MeshCells[reg, 3] // Length

10093

And a lot of polygons:

MeshCells[reg, 2] // Length  

22096

You do not need all that for visual, - so get the surface (boundary):

surface = BoundaryDiscretizeRegion[reg];
polygons = MeshCells[surface, 2];
polygons // Length

3820

Now so few polygons! Get the coordinates of the mesh too:

points = MeshCoordinates[surface];
points // Length
> 1910

And here you go:

Graphics3D[{EdgeForm[Gray], 
  GraphicsComplex[points, Polygon[polygons /. Polygon[x_] -> x]]}, 
 Boxed -> False, Lighting -> "Neutral"]

enter image description here

$\endgroup$
3
  • $\begingroup$ Why not use BoundaryDiscretizeRegion instead of DiscretizeRegion? (You get even fewer polygons.) $\endgroup$
    – Michael E2
    Commented Jan 28, 2015 at 14:33
  • $\begingroup$ @MichaelE2 sure just was in a Rush ;) $\endgroup$ Commented Jan 28, 2015 at 14:59
  • $\begingroup$ This is not working in MM 12.1.1 I get an error "A non-degenerate region is expected at position..." Any thoughts? $\endgroup$
    – Lou
    Commented Jun 23, 2020 at 12:33
8
$\begingroup$

Here's one way.

I'm going to use the contourRegionPlot3D function from here. I include the function definition here for convenience:

contourRegionPlot3D[region_, {x_, x0_, x1_}, {y_, y0_, y1_}, {z_, z0_, z1_}, 
  opts : OptionsPattern[]] := Module[{reg, preds},
  reg = LogicalExpand[region && x0 <= x <= x1 && y0 <= y <= y1 && z0 <= z <= z1];
  preds = Union@Cases[reg, _Greater | _GreaterEqual | _Less | _LessEqual, -1];
  Show @ Table[ContourPlot3D[
     Evaluate[Equal @@ p], {x, x0, x1}, {y, y0, y1}, {z, z0, z1}, 
     RegionFunction -> Function @@ {{x, y, z}, Refine[reg, p] && Refine[! reg, ! p]},
     opts], {p, preds}]]

Now create a region from the Graphics3D objects:

c1 = Cuboid[{0, 0, 0}, {20, 2, 20}];
c2 = Cuboid[{12, 0, 8}, {17, 2, 17}];
c3 = Cylinder[{{5, -1, 10}, {5, 2, 10}}, 3];
reg = Fold[RegionDifference, c1, {c2, c3}];

Use RegionMember to turn this into inequalities:

ineqs = Rest @ RegionMember[reg, {x, y, z}]

0 <= x <= 20 && 0 <= y <= 2 && 0 <= z <= 20 && ! (12 <= x <= 17 && 0 <= y <= 2 && 8 <= z <= 17) && ! (0 <= (1 + y)/3 <= 1 && (-5 + x)^2 + (-10 + z)^2 <= 9)

And then:

contourRegionPlot3D[ineqs, {x, 0, 20}, {y, 0, 2}, {z, 0, 20}, 
 Mesh -> None, BoxRatios -> Automatic, PlotRange -> All, Boxed -> False, Axes -> False]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.