10
$\begingroup$

I have a simple geometry that consists of a few rotated rectangles

Graphics[Table[
  Rotate[Rectangle[{-(1/5), .55}, {1/5, .95}], x, {0, 0}], {x, π/
   8, 2 π, π/4}]]

enter image description here

I would like to convert this into a 2D boundary mesh. The standard workflow is the discretize the graphics elements then use ToBoundaryMesh. Or just put a RegionUnion straight into ToBoundaryMesh.

Here's what happens

DiscretizeGraphics[%]
(*EmptyRegion[2]*)

Here's a fun example that shows this issue in a bit of a simpler way

ToBoundaryMesh[Rectangle[]]
(*ElementMesh[{{0., 1.}, {0., 1.}}, Automatic]*)
ToBoundaryMesh[Rotate[Rectangle[], Pi/8]]

enter image description here

DiscretizeGraphics[Rectangle[]]

enter image description here

DiscretizeGraphics[Rotate[Rectangle[], Pi/8]]

enter image description here

So it seems that rotate only works when called inside Graphics? This seems to me like a bug unless im missing something. (I also tried GeometricTransformation with no luck)

My only terrible solution is this

(Graphics[
       Table[Rotate[Rectangle[{-(1/5), .55}, {1/5, .95}], 
         x, {0, 0}], {x, π/8, 2 π, π/4}]] // Rasterize // 
     ColorNegate // ImageMesh // ToBoundaryMesh)["Wireframe"]

enter image description here

Another thing I thought I'd mention is RoundingRadius gives some very strange results.

GraphicsRow[({Graphics[#1], DiscretizeGraphics[#1], 
     ToElementMesh[#1]["Wireframe"]} &)[
  Graphics[Rectangle[{0, 0}, {1, 1}, RoundingRadius -> .1]]]]

enter image description here

Or better yet, change the rectangle to default size

GraphicsRow[({Graphics[#1], DiscretizeGraphics[#1], 
     ToElementMesh[#1]["Wireframe"]} &)[
  Graphics[Rectangle[RoundingRadius -> .1]]]]

enter image description here

And while I'm talking about bugs. Has anyone else noticed that when you call RandomPolyhedra with no argumnents the UI gets mad but the code runs just fine. enter image description here

Also the documentations indicates nothing about a default option. enter image description here

I guess I hold Mathematica to too high a standard, but it's a shame when stiff doesn't work as expected.

$\endgroup$
  • $\begingroup$ According to the documentation for Rotate, it should be possible to use Normal to obtain a version of the graphics primitive where Rotate has been replaced by a version of the graphics primitive that is rotated. But for some reason, it doesn't work for rectangles. $\endgroup$ – C. E. Nov 14 at 21:23
  • 1
    $\begingroup$ Graphics[Table[Rectangle[{-1/5,.55},{1/5,.95}]//RotationTransform[x,{0,0}],{x,π/8,2 π,π/4}]]//DiscretizeGraphics works. $\endgroup$ – chyanog Nov 15 at 10:20
11
$\begingroup$

I think the failure to discretize your first Graphics object is a bug.

But, instead of creating graphics objects and then converting them to MeshRegion objects with DiscretizeGraphics, I think it is simpler to use Region functionality instead, since Rectangle is already a Region primitive. When working with Region primitives you need to use TransformedRegion instead of GeometricTransformation or Rotate. Then, to convert Region primitives to MeshRegion objects, you need to use DiscretizeRegion or BoundaryDiscretizeRegion.

The following rotates a rectangle and converts it into a MeshRegion object:

BoundaryDiscretizeRegion @ TransformedRegion[Rectangle[], RotationTransform[Pi/8]]

enter image description here

You can create your desired ElementMesh output with:

Needs["NDSolve`FEM`"]
mesh = ToBoundaryMesh @ BoundaryDiscretizeRegion @ RegionUnion[
    Table[
        TransformedRegion[Rectangle[{-(1/5), .55}, {1/5, .95}], RotationTransform[θ]],
        {θ, Pi/8, 2Pi, Pi/4}
    ]
];
mesh["Wireframe"]

enter image description here

$\endgroup$
  • $\begingroup$ Thanks so much this works! $\endgroup$ – user2757771 Nov 14 at 21:18
  • $\begingroup$ Another solution I found is to discretize first then rotate. DiscretizeGraphics@ Table[Rotate[DiscretizeGraphics[Rectangle[{-1/6, 1/2}, {1/6, 1}]], x, {0, 0}], {x, Pi/8, 2*Pi, Pi/4}] $\endgroup$ – user2757771 Nov 15 at 6:16
10
$\begingroup$

As an alternative you can use BoundaryElementMeshRotate (and a few other Boolean operations) for boundary element meshes that are part of the FEMAddOns paclet. The installation of the paclet is now very easy since the installation can be done via the FEMAddOnsInstall resource function.

Install and load the paclet:

ResourceFunction["FEMAddOnsInstall"][]
Needs["FEMAddOns`"]
(* Paclet[FEMAddOns, 1.3.2] *)

Now, generate the boundary mesh for the rectangle as usual.

bmesh1 = ToBoundaryMesh[Rectangle[{-(1/5), .55}, {1/5, .95}]];

And rotate it to your hart's content:

bms = Table[
   BoundaryElementMeshRotation[bmesh1, RotationMatrix[theta]], {theta,
     Pi/8, 2 Pi, Pi/4}];

You can put everything in a single boundary element mesh:

bm = BoundaryElementMeshJoin @@ bms;
bm["Wireframe"]

enter image description here

For more information on the BoundaryElementMesh-xyz functions please see the documentation of the paclet.

To mesh the geometry use:

ToElementMesh[bm]["Wireframe"]

enter image description here

If this is too fine on the boundary you can create a coarse boundary mesh and rotate that with:

bmesh1 = ToBoundaryMesh[Rectangle[{-(1/5), .55}, {1/5, .95}], 
   MaxCellMeasure -> Infinity];

Which will then lead too:

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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