7
$\begingroup$

The end of the Star Wars saga is near, so I feel compelled to design a Mouse Droid. Based upon the Paul Murphy's schematics I've reconstructed the outline of the top shell:

enter image description here

Since my goal is to create a 3D-printable object, I'd like to carve out the inside of the shell, and this objective has tested the limits of my trigonometry knowledge.

The goal is to create an identical shape (excluding the brim) that is scaled to provide an arbitrary thickness in the x,y,z directions (in practice, the x and y thicknesses will be identical and typically thinner than the z thickness). Because the object will be 3D printed, thickness must be defined in the [x,y,z] dimensions, so the approach I'm using is to assign the z thickness, find points in a new plan that intersect with the shell outline, and translate as appropriate in the x and y directions to get the coordinates for the cutout. I'm stuck here:

pts = {{1.53685, 1, 0.6}, {2.77444, 2.81657, 7.6187}, {15.5486, 2.81657, 
  7.6187}, {20.4632, 1, 0.6}, {1.53685, 11.25, 0.6}, {2.77444, 
  9.43343, 7.6187}, {15.5486, 9.43343, 7.6187}, {20.4632, 11.25, 
  0.6}, {0, 0, 0}, {0, 12.25, 0}, {22, 12.25, 0}, {22, 0, 0}, {0, 0, 
  0.6}, {0, 12.25, 0.6}, {22, 12.25, 0.6}, {22, 0, 0.6}};
pl1 = pts[[{0, 4, 7, 3} + 1]];
pl2 = pts[[{1, 5, 6, 2} + 1]];
Graphics3D[{
  Red, Thick, MapThread[Line[{#1, #2}] &, {pl1, pl2}],
  Red, Opacity[0.1], Polygon[pl1],
  Blue, Opacity[0.1], Polygon[pl2],
  Black, Polygon[# + {0, 0, 5.6187} & /@ pl1]
  }, Boxed -> False, 
 PlotLabel -> 
  "What is the point on red line that intersects black plane?"]

enter image description here

Given the 8 points on two parallel planes and a third parallel plane of some known distance (2 units in this case) from the top plane, how to I find the four points where the red lines intersect the black plane? The internal angles of the Mouse Droid are 80 and 55 degrees around x and 75 degrees around y.

$\endgroup$
3
  • 3
    $\begingroup$ Just by the way, have you checked out ShellRegion? $\endgroup$
    – Carl Lange
    Dec 14, 2019 at 15:51
  • $\begingroup$ @CarlLange I was not aware of that function and it may be useful in the future. At the moment, I am using MMA for the math but then move to a different program for CAD design that generates STLs that work nicely with my 3D Printer. $\endgroup$ Dec 14, 2019 at 15:57
  • 1
    $\begingroup$ Yes, I've also found that that's the best workflow for my own 3D printing projects. Mathematica for the first 90% and then Blender or openSCAD for the second 90% 😀 $\endgroup$
    – Carl Lange
    Dec 14, 2019 at 16:48

3 Answers 3

2
$\begingroup$
lines = MapThread[Line[{#1, #2}] &, {pl1, pl2}];
plane = Polygon[# + {0, 0, 5.6187} & /@ pl1];
intersections = (RegionIntersection[plane, #] & /@ lines)[[All, 1, 1]];

Graphics3D[{Red, Thick, lines, Opacity[0.1], Polygon[pl1], 
  Blue, Polygon[pl2], Black, plane, Green, Polygon@intersections, 
  Opacity[1], Sphere[#, .3] & /@ intersections}, Boxed -> False]

enter image description here

Update: An alternative approach to find the intersections:

scale = Rescale[.6 + 5.6187, MinMax[{pl1[[1, -1]], pl2[[1, -1]]}], {0, 1}];
intersections2 = pl1 + scale (pl2 - pl1) ;

intersections2 == intersections

True

Graphics3D[{Red, Thick, lines, Opacity[.1],  Blue, Hexahedron[pts], 
  Black, plane, Green, Polygon@intersections2, Opacity[1], 
  Sphere[#, .2] & /@ intersections2}, Boxed -> False]

enter image description here

Update 2: A purely graphical approach using ParametricPlot3D (as in Cesareo's answer) with MeshFunctions and Mesh options to find the desired intersections:

Show[ParametricPlot3D[pl1 + λ (pl2 - pl1), {λ, 0, 1}, 
   PlotStyle -> Directive[Red, Thick], 
   MeshFunctions -> {#3 &}, 
   Mesh -> {{.06 + 5.6187}},
   MeshStyle -> ({Green, Sphere[#, .2] & @@ #} &)],
 Graphics3D[{Opacity[0.1], Red, Polygon[pl1], Blue, Polygon[pl2], Black, plane}], 
 Boxed -> False, Axes -> False]

enter image description here

$\endgroup$
1
  • $\begingroup$ I like the very Mathematica approach of the first answer, although I suspect the 2nd is going to be more useful as it can be more easily translated into something that works with my CAD software (openSCAD). $\endgroup$ Dec 15, 2019 at 13:07
3
$\begingroup$

If the planes defined by pl1, pl2 are parallel then with the following procedure, we can construct parallel intermediate planes for each lambda value.

gr1 = Table[ParametricPlot3D[pl1[[k]] + lambda (pl2[[k]] - pl1[[k]]), {lambda, 0, 1}, PlotStyle -> {Thick, Red}], {k, 1,4}];
gr2 = Table[Graphics3D[Polygon[{pl1[[1]] + lambda (pl2[[1]] - pl1[[1]]), pl1[[2]] + lambda (pl2[[2]] - pl1[[2]]), pl1[[3]] + lambda (pl2[[3]] - pl1[[3]]), pl1[[4]] + lambda (pl2[[4]] - pl1[[4]])}]], {lambda, 0, 1, 0.2}];
Show[gr1, gr2, PlotRange -> All]

enter image description here

NOTE

Given a plane defined by three points like

pts = {{2.15565, 1.90829, 4.10935}, {2.15565, 10.3417, 4.10935}, {18.0059, 10.3417, 4.10935}};

and a segment

seg = {{1.53685, 1, 0.6}, {2.77444, 2.81657, 7.6187}};

the intersection point is calculated as pint the solution lambda for

sol = NSolve[(seg[[1]]+lambda(seg[[2]]-seg[[1]])-pts[[3]]).Cross[pts[[1]]-pts[[3]],pts[[2]]-pts[[3]]] == 0,lambda][[1]]
If[0 <= (lambda /. sol) <= 1, pint = seg[[1]] + lambda (seg[[2]] - seg[[1]]) /. sol, Print["No intersection"]]

If[0 <= (lambda /. sol) <= 1,
    gr1 = ParametricPlot3D[seg[[1]] + lambda (seg[[2]] - seg[[1]]),{lambda, 0, 1}, PlotStyle -> {Red, Thick}];
    gr2 = Graphics3D[{Green, Sphere[pint, 0.1]}];
    gr3 = Graphics3D[Polygon[pts]];
    Show[gr1, gr2, gr3, PlotRange -> {{pint[[1]] - 2, pint[[1]] + 2}, {pint[[2]] - 2, pint[[2]] + 2}, {pint[[3]] - 2, pint[[3]] + 2}}]
]

enter image description here

$\endgroup$
2
  • $\begingroup$ An interesting approach; how does one extract the desired points where the lines intersect a given plane? $\endgroup$ Dec 15, 2019 at 13:02
  • $\begingroup$ Please. See attached note. $\endgroup$
    – Cesareo
    Dec 15, 2019 at 14:42
2
$\begingroup$

I'm recording my approach to this problem to (a) have a repository for when I inevitably forget how to do this and (b) to avoid muddying up the question which others have provided helpful answers to.

Here's my somewhat ugly approach having learned that knowing the length (via Norm) and direction (via Normalize) of the edges, I can construct a parallel edge with a shorter length that can be readily translated in the x and y directions.

th = {1, .5, 2};
dir = {{1, 1}, {1, -1}, {-1, -1}, {-1, 1}};
pl1 = pts[[{0, 4, 7, 3} + 1]];
pl2 = pts[[{1, 5, 6, 2} + 1]];
tr[pt_, th_, d_] := Module[{v = Last@pt - First@pt, u},
   u = (1 - th[[3]]/v[[3]]) Norm@v Normalize@v;
   u = # + {d[[1]], d[[2]], 0} th & /@ {First@pt, u + First@pt}
   ];
Graphics3D[{Thick,
  Red, MapThread[Line[{#1, #2}] &, {pl1, pl2}],
  {Opacity[0.1], Polygon[pl1], Polygon[pl2]},
  Blue, MapThread[Line[tr[{#1, #2}, th, #3]] &, {pl1, pl2, dir}]
  }]

enter image description here

Hexagon was new to me, which makes drawing the shell and cutout regions fairly straightforward. RegionDifference works like a charm on these shapes.

cutout = Region@
  Hexahedron@
   Flatten[MapThread[tr[{#1, #2}, th, #3] &, {pl1, pl2, dir}], {2, 1}]
shell = Region[Hexahedron[pts[[1 ;; 8]]]]
RegionDifference[shell, cutout]

enter image description here

$\endgroup$

Your Answer

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

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