For an exciting personal project, I’ve been exploring remeshing techniques using Grasshopper. Typically, I rely on @DanielPiker 's Remesh by Color - a fantastic component that’s been essential to my workflow (see an example here). However, for this project, I decided to look beyond the usual and integrate Gmsh, a popular finite element mesh generator, into Grasshopper. Surprisingly, incorporating Gmsh was a smooth process, thanks to the new Python script which now supports Python 3. Here’s my code. It’s quite basic and there’s room for improvement. The key part is converting a Gmsh mesh into a Rhino mesh.
#r: gmsh
import gmsh
import Rhino.Geometry as rg
import numpy as np
gmsh.initialize()
gmsh.clear()
gmsh.option.setNumber("Mesh.CharacteristicLengthMin", length.Min)
gmsh.option.setNumber("Mesh.CharacteristicLengthMax", length.Max)
def create_loop(pts):
p_tags = [gmsh.model.geo.add_point(p.X, p.Y, 0.0, p.Z+0.01) for p in pts]
p_tags.append(p_tags[0])
l_tags = [gmsh.model.geo.add_line(pt1, pt2) for pt1, pt2 in zip(p_tags, p_tags[1:])]
return gmsh.model.geo.add_curve_loop(l_tags)
loops = [create_loop(outer)]
loops.extend(create_loop(inner) for inner in inners.Branches)
plane_surface = gmsh.model.geo.add_plane_surface(loops)
if nodes != None:
p_tags = [gmsh.model.geo.add_point(n.X, n.Y, n.Z) for n in nodes]
field = gmsh.model.mesh.field.add("Distance")
gmsh.model.mesh.field.setNumbers(field, "PointsList", p_tags)
threshold_field = gmsh.model.mesh.field.add("Threshold")
gmsh.model.mesh.field.setNumber(threshold_field, "IField", field)
gmsh.model.mesh.field.setNumber(threshold_field, "LcMin", length.Min / 50)
gmsh.model.mesh.field.setNumber(threshold_field, "LcMax", length.Max * 2)
gmsh.model.mesh.field.setNumber(threshold_field, "DistMin", length.Min * 2)
gmsh.model.mesh.field.setNumber(
threshold_field, "DistMax", length.Min * 10 + length.Max * 10
)
gmsh.model.mesh.field.setAsBackgroundMesh(threshold_field)
if quad:
gmsh.model.geo.mesh.setRecombine(2, 1)
gmsh.model.geo.synchronize()
gmsh.model.mesh.generate(2) # 2 for 2D mesh
coords = np.array(gmsh.model.mesh.getNodes()[1]).reshape(-1, 3)
faces = np.array((gmsh.model.mesh.getElements()[2][1]) - 1).reshape(
-1, 4 if quad else 3
)
gmsh.finalize()
mesh = rg.Mesh()
for point in coords:
mesh.Vertices.Add(*point)
for face in faces:
mesh.Faces.AddFace(*[int(v) for v in face])
mesh.RebuildNormals()
mesh.Compact()
a = mesh
Gmsh.gh (14.5 KB)
P.S. I’m aware of the Iguana plugin, which also utilizes GMSH. However, for this project, I wanted more direct control over the remeshing process, which led me to take this approach.






