Shrinkwrapping complex geometry

Thanks for your super fast feedback @maje90 & @laurent_delrieu!

Laurent’s workflow seems to be more robust. It converges nicely for the whole model.

Your approach, Riccardo, falls apart with the smaller tower, where glass panes disappear.

And it took 5 minutes to complete:

[Edit] Ninja’d by Laurent in the above post.

Some geo are blocks… maybe are omitted from the meshing?
I haven’t tried…

Exploding and ungrouping everything doesn’t help.

image

Which is very weird since the same surfaces representing glass on the tall towers are grouped and instanced and work without issues…

Working with the smallest building blocks, there are some big elements that make the windows glass surface, but those are open.
Doing:

  • ExtractRenderMesh
  • Cap (this will close 200-ish open meshes, resulting in more closed windows)
  • Join
  • to GH:

    Still floors from 1 to 3 have opens windows, because the big geometry making that windows glass is open, and it doesn’t close with Cap command.

I think you should start with better and cleaner geometries, the beams of the windows have many wrong angles/orientations, and globally the geometry is very dirty.
You could replace the beam block with a simpler block, but that’s not the main problem.


Another solution is making a turntable animation in decent resolution and feed the images to a photogrammetry software…

1 Like

By intersecting 2 open meshes it should work, but I’m not sure if dendro is doing that:

What I thought of was something like:

  • create a 3d grid of points
  • measure distance to geometry for each point of the grid, values
  • do iso mesh surfacing with a value larger than 0 (this value will “heal” any opening)
  • pick the resulting mesh that follow the shape more correctly
  • offset that mesh back into position



Distance measurement is slow, and it’s dumb to do it in GH (huge lists, ultra slow).
Even by using millipede (which give the same result as my c# meshing), calculating the huge amount of distance values is a massive task for normal GH , it should be done, distance calc and meshing, all inside a single component, like dendro…

the actual signed-distance mesh iso surfacing of the starting 2 open meshes are actually many shells:


Hello Riccardo, nice experiments.
As Dendro is using OpenVdB I went to the documentation. The Mesh To Volume requires a closed mesh and is doing Signed Distance
https://www.openvdb.org/documentation/doxygen/MeshToVolume_8h.html#details
I make some experiments with BandWidth and Isovalue, if isovalue is more than Zero and Bandwidth > 1 it could capture surfaces but it doesn’t seem reliable.

I’m trying, but my iso meshing (signed distance… what is the correct name?), is actually failing 3/4 of the times…

The resulting shells:

You can see the distance results in a pseudo-fillet applied to everything… that “heals” gaps (and “eats” small details too)

Cells size of 2 units, I’m scared to going down to 0.2 like with dendro.
(rough math, it can easily take 4 hours doing the same… but it would surely fail somewhere…)
I am using some c# custom methods, dendro probably use some deeper and more efficient stuff (c/c++ maybe?)


The bottom mesh is very complex, Mesh.ClosestPoint method is probably not best approach.
(splitting the task in regions or other optimizations is needed).
This is 1.5 minutes with cell size of 2.3 units:

Thanks for these very interesting studies!

Doing some further testing, it seems that @laurent_delrieu’s approach with populating mesh faces with points works in a fairly-reliable manner. It breaks apart with highly-varying mesh faces, where some are very small and others really big.

I got around it by populating points based on area - 1 point per 1 square meter of each face. It results in more consistent point distribution. Random spacing is probably not the best approach for this case, though, and a regular point distribution could be more promising.

Still didn’t get a chance to compile Cgal and try the Alpha Wrapping approach suggested earlier in this thread. Will report here once I wrapped my head around it.

I modified your C# script to populate mesh faces in a uniform way based on user-defined spacing value. It comes at a slight performance penalty but helps in scenarios where mesh faces vary a lot in size.

dendro_building.gh (11.5 KB)

  HashSet<Point3d> PointsOnMeshFace(int meshfaceindex, Mesh m, double spacing, double spacingSquared)
  {
    List<Point3d> points = new  List<Point3d>();

    var a = m.Vertices[m.Faces[meshfaceindex].A];
    var b = m.Vertices[m.Faces[meshfaceindex].B];
    var c = m.Vertices[m.Faces[meshfaceindex].C];

    Vector3d ab = b - a;
    Vector3d bc = c - b;

    var abPoints = new List<Point3d>();
    var bcPoints = new List<Point3d>();
    var centerPoints = new List<Point3d>();
    var allPoints = new HashSet<Point3d>();

    SubdivideEdge(a, b, ab, spacing, spacingSquared, ref abPoints);
    SubdivideEdge(b, c, bc, spacing, spacingSquared, ref bcPoints);

    allPoints.UnionWith(abPoints);
    allPoints.UnionWith(bcPoints);

    if (abPoints.Count < bcPoints.Count)
    {
      for( int i = 0; i < abPoints.Count; i++)
      {
        var start = abPoints[i];
        var end = bcPoints[bcPoints.Count - 1 - i];
        SubdivideEdge(start, end, (end - start), spacing, spacingSquared, ref centerPoints);
      }
    } else
    {
      for( int i = 0; i < bcPoints.Count; i++)
      {
        var start = bcPoints[bcPoints.Count - 1 - i];
        var end = abPoints[i];
        SubdivideEdge(start, end, (end - start), spacing, spacingSquared, ref centerPoints);
      }
    }

    allPoints.UnionWith(centerPoints);


    return allPoints;
  }

  private void SubdivideEdge(Point3d start, Point3d end, Vector3d edge, double spacing, double spacingSquared, ref List<Point3d> pts)
  {
    edge.Unitize();
    pts.Add(start);
    while(start.DistanceToSquared(end) > spacingSquared)
    {
      start += edge * spacing;
      pts.Add(start);
    }
    pts.Add(end);
  }

[EDIT] Here is a completely different scene, where this modified approach comes in handy:



4 Likes

Maybe you could try to select the whole model and export as STL and allow open surfaces. Sure there maybe a few holes, then reimport into the CFD