4
$\begingroup$

Consider these two simple Polyhedrons which share a sub-face:

p1 = Polyhedron[
    {{0, 0, 0}, {2, 0, 0}, {2, 1, 0}, {0, 1, 0}, {0, 0, 1}, {2, 0, 1}, {2, 1, 1}, {0, 1, 1}},
    {{1, 2, 3, 4}, {5, 6, 7, 8}, {1, 2, 6, 5}, {2, 3, 7, 6}, {3, 4, 8, 7}, {4, 1, 5, 8}}];

p2 =  TransformedRegion[p1, TranslationTransform[{1, 0, 1}]];

enter image description here

I wish to produce a third Polyhedron which describes the union of these shapes, as suggested by the Region admitted by RegionUnion:

enter image description here

Unfortunately the Polyhedron produced by RegionUnion has not merged the 'side faces' but has actually split up previous individual faces!

enter image description here

It seems like MeshCells[] is unable to return a single Polyhedron describing the full volume.

MeshCells[RegionUnion[p1, p2], 3]

>>> MeshCells: There is no simple cell representation for the specified cells of the BoundaryMeshRegion

My issues with the generated polyhedron do not appear to constitute mesh defects:

enter image description here

In principle, I can obtain a list of all the individual faces admitted by RegionUnion...

p3 = RegionUnion[p1, p2];
coords = First[p3];
faces = MeshCells[p3, 2] /. i_Integer :> coords[[i]];

and attempt to stitch them myself into "clean" polyhedron faces by unifying co-planar edge-intersecting faces (using e.g. Not @ RegionDisjoint[faces[[i]], faces[[j]]). This appears to require rotating co-planar faces into 2D Polygon, merging them and rotating back - quite a pain for one might expect as a basic Mathematica function!

Is there a way to achieve a simple unified Polyhedron like the one I have constructed below by hand:

p3 = Polyhedron[{
    {0, 0, 0}, {2, 0, 0}, {2, 0, 1}, {3, 0, 1}, {3, 0, 2}, {1, 0, 2}, {1, 0, 1}, {0, 0, 1},
    {0, 1, 0}, {2, 1, 0}, {2, 1, 1}, {3, 1, 1}, {3, 1, 2}, {1, 1, 2}, {1, 1, 1}, {0, 1, 1}
}, {
    Range[8], 8 + Range[8],
    {1, 8,  16 , 9},
    Sequence @@ Table[i + {0, 1, 9, 8}, {i, 7}]
}]

enter image description here

Adverserial example for cvgmt's solution

The proposed solution of

BoundaryDiscretizeRegion @ RegionUnion[{p1,p2}] // Region`Mesh`MergeCells

has some issues for longer lists of more complicated Polyhedron.

For example:

vols = {Polyhedron[{{202., 277.22222222222223`, 40}, {300., 250., 
      40}, {300., 296., 40}, {202., 296., 40}, {202., 
      277.22222222222223`, 52}, {300., 250., 52}, {300., 296., 
      52}, {202., 296., 52}}, {{1, 2, 3, 4}, {5, 6, 7, 8}, {1, 2, 6, 
    5}, {2, 3, 7, 6}, {3, 4, 8, 7}, {4, 1, 5, 8}}], 
   Polyhedron[{{400., 257.77777777777777`, 40}, {400., 
      222.22222222222223`, 40}, {480., 200., 40}, {400., 
      257.77777777777777`, 52}, {400., 222.22222222222223`, 
      52}, {480., 200., 52}}, {{1, 2, 3}, {4, 5, 6}, {1, 2, 5, 4}, {2,
      3, 6, 5}, {3, 1, 4, 6}}], 
   Polyhedron[{{400., 257.77777777777777`, 0}, {300., 330., 0}, {150.,
       350., 0}, {120., 300., 0}, {202., 277.22222222222223`, 
      0}, {202., 296., 0}, {300., 296., 0}, {300., 250., 0}, {400., 
      222.22222222222223`, 0}, {400., 257.77777777777777`, 12}, {300.,
       330., 12}, {150., 350., 12}, {120., 300., 12}, {202., 
      277.22222222222223`, 12}, {202., 296., 12}, {300., 296., 
      12}, {300., 250., 12}, {400., 222.22222222222223`, 12}}, {{1, 2,
      3, 4, 5, 6, 7, 8, 9}, {10, 11, 12, 13, 14, 15, 16, 17, 18}, {1, 
     2, 11, 10}, {2, 3, 12, 11}, {3, 4, 13, 12}, {4, 5, 14, 13}, {5, 
     6, 15, 14}, {6, 7, 16, 15}, {7, 8, 17, 16}, {8, 9, 18, 17}, {9, 
     1, 10, 18}}], 
   Polyhedron[{{312., 246.66667169012294`, 12}, {312., 308., 
      12}, {190., 308., 12}, {190., 280.55554604499355`, 12}, {202., 
      277.22222222222223`, 12}, {202., 296., 12}, {300., 296., 
      12}, {300., 250., 12}, {312., 246.66667169012294`, 52}, {312., 
      308., 52}, {190., 308., 52}, {190., 280.55554604499355`, 
      52}, {202., 277.22222222222223`, 52}, {202., 296., 52}, {300., 
      296., 52}, {300., 250., 52}}, {{1, 2, 3, 4, 5, 6, 7, 8}, {9, 10,
      11, 12, 13, 14, 15, 16}, {1, 2, 10, 9}, {2, 3, 11, 10}, {3, 4, 
     12, 11}, {4, 5, 13, 12}, {5, 6, 14, 13}, {6, 7, 15, 14}, {7, 8, 
     16, 15}, {8, 1, 9, 16}}], 
   Polyhedron[{{388., 266.444472098731, 12}, {388., 
      225.55554579605914`, 12}, {400., 222.22222222222223`, 
      12}, {400., 257.77777777777777`, 12}, {388., 266.444472098731, 
      52}, {388., 225.55554579605914`, 52}, {400., 
      222.22222222222223`, 52}, {400., 257.77777777777777`, 52}}, {{1,
     2, 3, 4}, {5, 6, 7, 8}, {1, 2, 6, 5}, {2, 3, 7, 6}, {3, 4, 8, 
    7}, {4, 1, 5, 8}}]};

enter image description here

(* doesn't evaluate *)
BoundaryDiscretizeRegion @ RegionUnion[vols]

>>> BoundaryDiscretizeRegion[BooleanRegion[#1 || #2 || #3 || #4 || #5 &, {vols}]]


% // Region`Mesh`MergeCells

>>> Region`Mesh`MergeCells[ BoundaryDiscretizeRegion[ ... ] ]

We could discretise first to avoid BooleanRegion as per this question...

(* evaluates to a BoundaryMeshRegion *)
reg = RegionUnion[BoundaryDiscretizeRegion /@ testvols]

enter image description here

Alas, now calling MergeCells[reg] throws an error:

>>> BoundaryMeshRegion::bsuncl: The boundary surface is not closed because the edges Line[{{34,36},{37,35},{36,37},{35,34}}] only come from a single face.

It is also not clear to me how to extract a Polyhedron from the resulting BoundaryMeshRegion when this technique does work.

Another strange adverserial example

Consider the list of polyhedrons:

vols = {InputForm[
Polyhedron[{{300., 164.53571428571428`, 10}, {202., 
      163.36904761904762`, 10}, {202., -44.66666666666667, 
      10}, {249., -76., 10}, {300., -44.125, 10}, {300., 
      164.53571428571428`, 20}, {202., 163.36904761904762`, 
      20}, {202., -44.66666666666667, 20}, {249., -76., 
      20}, {300., -44.125, 20}}, {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {
     1, 2, 7, 6}, {2, 3, 8, 7}, {3, 4, 9, 8}, {4, 5, 10, 9}, {5, 1, 6,
      10}}]], InputForm[
Polyhedron[{{300., -44.125, 0}, {249., -76., 
      0}, {202., -44.66666666666667, 0}, {202., -200., 
      0}, {300., -200., 0}, {300., -44.125, 10}, {249., -76., 
      10}, {202., -44.66666666666667, 10}, {202., -200., 
      10}, {300., -200., 10}}, {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {1,
      2, 7, 6}, {2, 3, 8, 7}, {3, 4, 9, 8}, {4, 5, 10, 9}, {5, 1, 6, 
     10}}]], InputForm[
Polyhedron[{{202., 296., 0}, {202., 163.36904761904762`, 0}, {300., 
      164.53571428571428`, 0}, {300., 296., 0}, {202., 296., 
      10}, {202., 163.36904761904762`, 10}, {300., 
      164.53571428571428`, 10}, {300., 296., 10}}, {{1, 2, 3, 4}, {5, 
    6, 7, 8}, {1, 2, 6, 5}, {2, 3, 7, 6}, {3, 4, 8, 7}, {4, 1, 5, 
    8}}]], InputForm[
Polyhedron[{{300.00000220959214`, -55.91747503407568, 
      10}, {300., -44.125, 10}, {249., -76., 
      10}, {202., -44.66666666666667, 
      10}, {202.00000237873843`, -56.68517250403892, 
      10}, {248.82501070724447`, -87.90184472304296, 
      10}, {300.00000220959214`, -55.91747503407568, 
      20}, {300., -44.125, 20}, {249., -76., 
      20}, {202., -44.66666666666667, 
      20}, {202.00000237873843`, -56.68517250403892, 
      20}, {248.82501070724447`, -87.90184472304296, 20}}, {{1, 2, 3, 
     4, 5, 6}, {7, 8, 9, 10, 11, 12}, {1, 2, 8, 7}, {2, 3, 9, 8}, {3, 
     4, 10, 9}, {4, 5, 11, 10}, {5, 6, 12, 11}, {6, 1, 7, 12}}]], 
  InputForm[
Polyhedron[{{300., 174.5364228773892, 10}, {202., 173.36975621072256`,
       10}, {202., 163.36904761904762`, 10}, {300., 
      164.53571428571428`, 10}, {300., 174.5364228773892, 20}, {202., 
      173.36975621072256`, 20}, {202., 163.36904761904762`, 
      20}, {300., 164.53571428571428`, 20}}, {{1, 2, 3, 4}, {5, 6, 7, 
    8}, {1, 2, 6, 5}, {2, 3, 7, 6}, {3, 4, 8, 7}, {4, 1, 5, 8}}]]}

Attempting to merge these volumes by the same technique above makes two of the faces (and the bounded volume in-between) disappear!

enter image description here

$\endgroup$
6
  • $\begingroup$ I have provide three methods,but you still down vote my answer. So I will never answer all of your question! $\endgroup$
    – cvgmt
    Commented Oct 29, 2022 at 23:05
  • $\begingroup$ Three methods with no explanatory text, which didn't work for my examples, and which didn't address my request for obtaining a Polyhedron. I hardly think you got to 43k rep doing that $\endgroup$
    – Anti Earth
    Commented Oct 29, 2022 at 23:08
  • $\begingroup$ What is the reason that you want a single polyhedron? $\endgroup$
    – user21
    Commented Oct 31, 2022 at 15:56
  • $\begingroup$ @user21 the final single Polyhedron is exported to use in other software $\endgroup$
    – Anti Earth
    Commented Oct 31, 2022 at 20:51
  • $\begingroup$ @cvgmt I have your original answer, and it made no mention of returning Polyhedron. What's your game here? $\endgroup$
    – Anti Earth
    Commented Nov 2, 2022 at 17:27

3 Answers 3

4
$\begingroup$

This is a comment not an answer. This should be more robust:

Needs["OpenCascadeLink`"]
r = RegionUnion @@ vols;
shape = OpenCascadeShape[r];
bmesh = OpenCascadeShapeSurfaceMeshToBoundaryMesh[shape];
mr = MeshRegion[bmesh];
Region`Mesh`MergeCells[mr]

enter image description here

$\endgroup$
2
$\begingroup$

I did not read all the details of the question but I noticed that taking the complement of the complement of the union of the polygons reduces the number of faces and so it might be what you are looking for:

poly = RegionUnion[p1, p2];

Number of faces : 18 (seen in the Polyhedron box image)

boundr = RegionUnion[p1, p2] // BoundingRegion;
RegionDifference[boundr, RegionDifference[boundr, poly]];

Number of faces : 16

$\endgroup$
1
  • 1
    $\begingroup$ BoundingRegion doesn't work on RegionUnion[vols] since the latter is a BooleanRegion $\endgroup$
    – Anti Earth
    Commented Nov 2, 2022 at 18:00
1
$\begingroup$

Perhaps this may be useful.

extrude is a function I wrote to avoid a problem in RegionProduct. I have reported that issue to Wolfram support already. The problem appears as beveled corners and edges.

First the images and then the code:

Mathematica graphics

Mathematica graphics

Mathematica graphics

Graphics[{EdgeForm[Black], FaceForm[None], 
   polygon1 = Rectangle[{0, 0}, {2, 1}], 
   polygon2 = Translate[polygon1, {1, 1}]}, 
  AspectRatio -> Automatic]
  
MeshRegion[polygon1]

MeshRegion[polygon2]

shape = First[MeshPrimitives[CanonicalizeRegion[
     RegionUnion[MeshRegion[polygon1], MeshRegion[polygon2]]], 
    2]]
    
extrude = Function[{interval, polygon}, 
    Block[{span, canonical, bottom, top, edges, i, j, k, 
      points, faces}, span = Sort[interval]; 
      canonical = CanonicalizePolygon[polygon]; 
      points = Union[Sort[Join[(Append[#1, span[[1,1]]] & ) /@ 
           canonical[[1]], (Append[#1, span[[1,2]]] & ) /@ 
           canonical[[1]]]]]; bottom = 
       (Append[canonical[[1,#1]], span[[1,1]]] & ) /@ 
        Reverse[canonical[[2]]]; bottom = 
       First[Flatten[(Position[points, #1] & ) /@ bottom, 
         {2, 3}]]; top = (Append[canonical[[1,#1]], 
          span[[1,2]]] & ) /@ canonical[[2]]; 
      top = First[Flatten[(Position[points, #1] & ) /@ top, 
         {2, 3}]]; edges = Table[j = top[[i]]; 
         k = top[[Mod[i + 1, Length[top], 1]]]; 
         {j - 1, k - 1, k, j}, {i, Length[top]}]; 
      faces = Join[{bottom, top}, edges]; 
      CanonicalizePolyhedron[Polyhedron @@ {points, faces}]]]; 
      
InputForm[Rationalize[shape]]

Region[extrude[Interval[{0, 1}], shape]]

Region[RegionProduct[Interval[{0, 1}], shape]]
Wed 22 Mar 2023 19:49:53GMT-4
13.2.1 for Microsoft Windows (64-bit) (January 27, 2023)
Microsoft Windows 10 Pro  10.0.19045  
{DisplayVersion,22H2}
Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz  
{NumberOfCores,8}
{Capacity     DeviceLocator   PartNumber        Speed,
 17179869184  ChannelA-DIMM0  F4-3200C16-16GVK  3200,
 17179869184  ChannelA-DIMM1  F4-3200C16-16GVK  3200,
 17179869184  ChannelB-DIMM0  F4-3200C16-16GVK  3200,
 17179869184  ChannelB-DIMM1  F4-3200C16-16GVK  3200}

Of course, I may have missed something.

$\endgroup$
2
  • $\begingroup$ You can use OpenCascadeLink to extrude, no need to write a function. $\endgroup$
    – user21
    Commented Mar 23, 2023 at 4:40
  • $\begingroup$ Thank you for the information. I had "extrude" already on hand; it was written several months again and long before I heard of OpenCascadeLink. And, this way "the how it was done" is visible. $\endgroup$
    – anon
    Commented Mar 23, 2023 at 20:37

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.