Message Boards Message Boards

2
|
3634 Views
|
7 Replies
|
8 Total Likes
View groups...
Share
Share this post:

Colorizing region intersections

I am trying to build this image in Mathematica using regions:

wikipedia constructive solid geometry

The components are here:

Graphics3D[
 {
  Red,
  Cuboid[-{.5, .5, .5}, {.5, .5, .5}],
  Blue, Sphere[{0, 0, 0}, .65],
  Green,
  {#, GeometricTransformation[#, RotationMatrix[Pi/2, {0, 1, 0}]],
     GeometricTransformation[#, RotationMatrix[Pi/2, {1, 0, 0}]]} & [
   Cylinder[{{0, 0, -.8}, {0, 0, .8}}, .3]]

  }, Boxed -> False
 ]

output 1

I can generate the region using the following code:

RegionDifference[
 RegionIntersection[
  BoundaryDiscretizeGraphics[Cuboid[-{.5, .5, .5}, {.5, .5, .5}]],
  BoundaryDiscretizeGraphics[Ball[{0, 0, 0}, .65], 
   MaxCellMeasure -> 0.0005]
  ],
 RegionUnion[
  BoundaryDiscretizeGraphics[Cylinder[{{0, 0, -.8}, {0, 0, .8}}, .3], 
   MaxCellMeasure -> 0.0005],
  Region[TransformedRegion[
    BoundaryDiscretizeGraphics[
     Cylinder[{{0, 0, -.8}, {0, 0, .8}}, .3], 
     MaxCellMeasure -> 0.0005], RotationTransform[Pi/2, {0, 1, 0}]]],
  TransformedRegion[
   BoundaryDiscretizeGraphics[Cylinder[{{0, 0, -.8}, {0, 0, .8}}, .3],
     MaxCellMeasure -> 0.0005], RotationTransform[Pi/2, {1, 0, 0}]]
  ]
 ]

Output 2

But I have not figured out how to get the proper surfaces colored properly. Any idea?

Thank you, Luc

POSTED BY: Luc Barthelet
7 Replies
Posted 2 years ago

You could Map a color over the region

reg = Luc's code above
Style[#, Red] & /@ reg

enter image description here

POSTED BY: Hans Milton

Luc,

if it is just for the coloring here is a simple and straightforward way. The code should be self-explanatory.

(* your calculated region: *)
reg = 
 RegionDifference[
  RegionIntersection[
   BoundaryDiscretizeGraphics[Cuboid[-{.5, .5, .5}, {.5, .5, .5}]], 
   BoundaryDiscretizeGraphics[Ball[{0, 0, 0}, .65], 
    MaxCellMeasure -> 0.0005]], 
  RegionUnion[
   BoundaryDiscretizeGraphics[Cylinder[{{0, 0, -.8}, {0, 0, .8}}, .3],
     MaxCellMeasure -> 0.0005], 
   Region[TransformedRegion[
     BoundaryDiscretizeGraphics[
      Cylinder[{{0, 0, -.8}, {0, 0, .8}}, .3], 
      MaxCellMeasure -> 0.0005], RotationTransform[Pi/2, {0, 1, 0}]]],
    TransformedRegion[
    BoundaryDiscretizeGraphics[
     Cylinder[{{0, 0, -.8}, {0, 0, .8}}, .3], 
     MaxCellMeasure -> 0.0005], RotationTransform[Pi/2, {1, 0, 0}]]]]

(* make it a BoundaryMeshRegion: *)
 breg = BoundaryDiscretizeRegion[reg];

(* calculate all polygons: *)
polygs = MeshPrimitives[breg, 2];

(* selection of polygons according to coordinates (maximal values or on a sphere): *)
redPolygs = Select[polygs, Total[Max /@ Abs @@ #] == 1.5 &];
bluePolygs = Select[polygs, Total[Norm /@ First[#]] > 1.94 &];
greenPolygs = Complement[polygs, redPolygs, bluePolygs];

Graphics3D[{Red, redPolygs, Blue, bluePolygs, Green, greenPolygs}, Boxed -> False]

enter image description here

Addendum: I could not resist playing around a little bit:

(* your outer graphics: *)
    gout = Graphics3D[{Red, Cuboid[-{.5, .5, .5}, {.5, .5, .5}], Blue, 
    Sphere[{0, 0, 0}, .65], 
    Green, {#, 
       GeometricTransformation[#, RotationMatrix[Pi/2, {0, 1, 0}]], 
       GeometricTransformation[#, RotationMatrix[Pi/2, {1, 0, 0}]]} &[
     Cylinder[{{0, 0, -.8}, {0, 0, .8}}, .3]]}, Boxed -> False];

(* my "inner" graphics from above: *)    
gin = Graphics3D[{Red, redPolygs, Blue, bluePolygs, Green, greenPolygs}, Boxed -> False];

gouto[op_] := (gout /. Graphics3D[p__] :> Graphics3D[{Opacity[op], p}])
gino[op_] := (gin /. Graphics3D[p__] :> Graphics3D[{Opacity[op], p}])

frames = Table[Show[gouto[1 - op], gino[op], Boxed -> False], {op, 0, 1, .05}];
Export["reg.gif", Join[frames, Reverse[frames]]]

enter image description here

Nice things you are doing! Regards -- Henrik

POSTED BY: Henrik Schachner

Henrik,

Thank you so much for solving for this canonic example, and so quickly.

I am wondering how we could get the surface to be identified by the binary operation, as unfortunately, I will have to deal with much more complex shapes soon.

Luc

POSTED BY: Luc Barthelet

Luc,

... I will have to deal with much more complex shapes soon.

OK, here is a more general approach - the idea is to use RegionDistance (no more fiddling around with coordinates!). Here is a minimal example where a "green cylinder" is cut out of a "red ball" in a less symmetric configuration. The situation is like this:

redGr = Ball[];
greenGr = Cylinder[{{.5, 1.5, .1}, {.5, -1.5, .1}}, .4];
Graphics3D[{Red, redGr, Green, greenGr}, Boxed -> False]

enter image description here

Now it is as simple as that:

(* defining the regions: *)
redReg = BoundaryDiscretizeGraphics[redGr];
greenReg = BoundaryDiscretizeGraphics[greenGr];

(* calculation the difference: *)
reg = RegionDifference[redReg, greenReg];

(* get all polygons defining the surface: *)
polygs = MeshPrimitives[reg, 2];

(* defining a distance function to the green cylinder: *)
greendist = RegionDistance[greenReg];

(* selecting all polygons next to the cylinder: *)
greenPolygs = Select[polygs, Total[greendist /@ First[#]] < .01 &];
redPolygs = Complement[polygs, greenPolygs];
Graphics3D[{Red, redPolygs, Green, greenPolygs}, Boxed -> False]

enter image description here

Does that help? Regards -- Henrik

POSTED BY: Henrik Schachner

Thank you Henrik for your latest reply. Unfortunately, it only help in a trivial case, because in the end you select the polygons, by using a Mathematica representation of the cylinder. In real cases, it will be a region for which the mathematical representation will only be known by Mathematica. We need Mathematica to tag those polygon when it does the operation, or we end up rebuilding that code ourselves. Does that make sense? Maybe we need @Roger Germundsson to explain how to do that...

POSTED BY: Luc Barthelet

In real cases, it will be a region for which the mathematical representation will only be known by Mathematica.

Well, according to my understanding in my example the cylinder is not a cylinder but a region - as such it could be anything, e.g.

greenReg = ConvexHullMesh[RandomPoint[Ball[{.5, .5, .5}], 150]]

with this I get without any further changes:

enter image description here

If this does not work for you then you should show a realistic example.

POSTED BY: Henrik Schachner

Henrik, you are correct, I was wrong in pointing out that you were using the mathematical representation of the cylinder, when in fact you are using RegionDistance, which is generic. Let me study this and build my complete example and see if I can make it work. Very much appreciated. Luc

POSTED BY: Luc Barthelet
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract