7
$\begingroup$

Importing STL files using Import results in a MeshRegion composed by the triangulation of the original file, and a similar ByteCount as the file in disk.

When trying to render interactive graphics using Manipulate, the time needed to render the visualization of the object is very high, not being able to be done in real time.

Is there a way to reduce the quality/size of the MeshRegion within Mathematica to reduce the size of the object and improve Manipulation speed?

I have tried using DiscretizeRegion and DiscretizeGraphics on the imported object, but it seems it does not work on MeshRegion.

I would like to find a way to do this in Mathematica, without having to rely on a CAD program to import and export the file again with a lower triangulation quality.

EDIT:

Here is an example of an object:

Link

The STL file can be downloaded here: STL file

$\endgroup$
5
  • $\begingroup$ Very good question. However, this is typically a very hard problem. As far as I know, Mathematica does not provide any solution for that. $\endgroup$ Feb 18, 2020 at 19:56
  • 1
    $\begingroup$ We can propose an algorithm, but we need an example of mesh. $\endgroup$ Feb 18, 2020 at 21:15
  • $\begingroup$ Edit with an example of the STL file. $\endgroup$ Feb 18, 2020 at 22:08
  • $\begingroup$ @HenrikSchumacher I think this might be possible via sampling like points = RandomPoint[Import["Link.STL"], 1000] and then using your Voronoi code. $\endgroup$ Feb 20, 2020 at 16:38
  • $\begingroup$ @VitaliyKaurov Oh, interesting. I completely forgot about that one. Hmmm... $\endgroup$ Feb 20, 2020 at 17:12

3 Answers 3

6
$\begingroup$

Decimation of mesh is not a trivial task if you want to preserve the visual features of the original mesh. If you want to tap into the efforts of people that have been working on the problem for many years, you could use the freely available MeshLab to perform the decimation with a script driven from Mathematica. Here is one possible workflow (Note: Uncompress to see the underlying MeshLab mlx script that drives the decimation):

SetDirectory[NotebookDirectory[]];
createDeciScript[deci_ : 0.1] := 
 StringTemplate[
   Uncompress[Import["https://pastebin.com/raw/Fsu2RNLt", "Text"]]][<|
   "d" -> deci|>]
fileName = "deci.mlx";
file = OpenWrite[fileName];
WriteString[file, createDeciScript[0.1]];
Close[file];
cmd = "\"C:\\Program Files\\VCG\\MeshLab\\meshlabserver.exe\" -i \
Link.stl -o LinkDeci.stl -s deci.mlx -om";
Run[cmd];
{stl, stlDeci} = {Import["Link.stl"], Import["LinkDeci.stl"]}

Decimation

The image on the right has 10x fewer triangles than the image on the left.

Decimation

$\endgroup$
2
  • $\begingroup$ @LCarvalho Interesting. That definitely appears to be the logo. I was just treating the source material as a Bag-Of-Triangles to be decimated. $\endgroup$
    – Tim Laska
    Oct 14, 2020 at 20:29
  • $\begingroup$ meshlabserver.exe was discontinued in favor of a python interface, see here: stackoverflow.com/questions/65825861/… $\endgroup$
    – Oscillon
    Aug 15, 2021 at 8:38
4
$\begingroup$

Well... (importing your .STL object):

obj = Import["Link.STL"]

enter image description here

...if nothing else a very poor man's solution for simple visual in an interactive interface is just random sampling of points (i know it is far from spectacular :-) but is very light):

pts=RandomPoint[obj,1000];
obj//ByteCount
Graphics3D[Point[pts]]//ByteCount

1808792

24792

Also I just would like to outline a strategy for this, and explain why it might be a good approach. I cannot run complete wonderful code by @HenrikSchumacher (tech difficulties), but people here I bet can figure it out. So now if we think of somehow roughening polygons to lower resolution we might run into a problem, depending on a case, and this case is a good example. Let's see how points are distributed in the original .STL object:

Graphics3D[MeshPrimitives[obj, 0]]

enter image description here

Do you see how many are dense in one region and sparse in another? So some blunt approach of locally down-sampling polygons might require a very complicated algorithm, but still be inefficient somehow due to highly non-uniform down-sampling. Now we can think of another approach. We have ability to randomly point-sample any high-res region:

pts=RandomPoint[obj,200];

and you can see how points now appear in the regions with low density of points in the original mesh:

Show[
    HighlightMesh[RegionBoundary[obj],{Style[2,Opacity[0.2]],Style[1,Opacity[0.4]]}],
    Graphics3D[{Red,Sphere[pts,1]}],
Boxed->True,Axes->True]

enter image description here

Now you can run wonderful code by @HenrikSchumacher and others seen in posts about VORONOI and GEODESICS to be ready to go, or maybe you can also think of applying a spline approach as an interesting alternative discussed HERE - but this might need more jumping through the hoops in terms of proper data for BSplineFunction.

$\endgroup$
3
  • $\begingroup$ It wasn't the preferred solution for the original question, but I have come back to find this useful in a different case. Thank you! $\endgroup$ Jun 18, 2020 at 10:19
  • $\begingroup$ I have been struggling to apply those codes to this example. How should I input this pts to the Voronoi and Geodesics code? Could you show how the last part is performed on this example? $\endgroup$ Jun 18, 2020 at 11:00
  • $\begingroup$ Could this perform better than computing a Concave Hull of the randomly selected points? $\endgroup$ Jun 23, 2020 at 14:15
2
$\begingroup$

I have been trying to do this calculating a Concave Hull using this approach:

obj = Import["Link.STL"];
pts = RandomPoint[obj, 10000];
tetrahedra = Level[MeshPrimitives[DelaunayMesh[pts], 3], {-3}];
radius[p_] := Check[Circumsphere[p][[2]], 10000];
radii = radius /@ tetrahedra;
alphashape[rmax_] := Pick[tetrahedra, radii, r_ /; r < rmax]
faces[tetras_] := Flatten[
   tetras /. {a_, b_, c_, d_} :> {{a, b, c}, {a, b, d}, {a, c, d}, {b, c, d}}, 1];
externalfaces[faces_] := Cases[Tally[Sort /@ faces], {face_, 1} :> face];
radiusmax = 50;
polys = externalfaces@faces@alphashape[radiusmax];
Graphics3D[
  {EdgeForm[{Thin, Opacity[1/30, Black]}], Polygon@polys},
  AxesLabel -> {"x", "y", "z"},
  Axes -> True,
  Boxed -> False,
  BoxRatios -> {1, 1, 1},
  ViewPoint -> 1000 {-1, 1, -1}
]

from: https://mathematica.stackexchange.com/a/201558/57063

But it seems to be difficult to modify the radiusmax parameter to obtain detail on edges without causing the hull to have gaps or holes.

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.