Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mesh from closed polylines #16

Open
pearswj opened this issue Jan 31, 2014 · 19 comments
Open

Mesh from closed polylines #16

pearswj opened this issue Jan 31, 2014 · 19 comments

Comments

@pearswj
Copy link
Contributor

pearswj commented Jan 31, 2014

Create a mesh from a number of closed polylines.

A mesh from a closed polyline is straightforward:

  1. Add polyline vertices to mesh
  2. add a face with vertex indices 1...n where n is the number of vertices.

Creating a mesh from several polylines could be done in the same way with a secondary procedure to merge duplicate vertices. Duplicates could be merged either before (faster) or after (more flexible) the faces are added.

@pearswj pearswj added this to the 0.3.4 milestone Feb 7, 2014
@pearswj
Copy link
Contributor Author

pearswj commented Jul 23, 2014

Starling's pmDecompose component works pretty well for the purpose of creating a Plankton mesh from several polylines. Perhaps we should add a simple component that wraps up the code below?

image

# V: list of Point3d
# F: tree of int

import clr
clr.AddReferenceToFile("Plankton.dll")

import Plankton

pmesh = Plankton.PlanktonMesh()

for pt in V:
    pmesh.Vertices.Add(pt.X, pt.Y, pt.Z)

for face in F.Branches:
    face = list(face)[:-1] # see comment below
    pmesh.Faces.AddFace(face)

@pearswj pearswj modified the milestones: 0.4.0, 0.3.4 Jul 23, 2014
@pearswj
Copy link
Contributor Author

pearswj commented Jul 23, 2014

Actually there's a bug in the Starling component. It counts all the vertices in a closed polyline (where the first vertex appears again at the end).

@harrilewis
Copy link

I'm doing some rough and ready plankton.

image

Is there a function to merge vertices within a tolerance?

@pearswj
Copy link
Contributor Author

pearswj commented Oct 24, 2014

Not currently. The above definition using Starling was the best solution I've achieved so far.

@danhambleton
Copy link

Provided the vertices are exactly coincident, I've been using:

        PlanktonMesh PMeshFromPolylines(List<Polyline> faces)
        {
            var pMesh = new PlanktonMesh();
            //add n-gon faces
            var verts = new List<Point3d>();
            for (int i = 0; i < faces.Count; i++)
            {
                var currFace = new List<int>();

                for (int j = 0; j < faces[i].Count - 1; j++)
                {
                    var currPt = faces[i].PointAt(j);
                    var id = verts.IndexOf(currPt);
                    if (id < 0)
                    {
                        //push a vertex to list
                        //push that index to current face
                        pMesh.Vertices.Add(currPt.X, currPt.Y, currPt.Z);
                        verts.Add(currPt);
                        currFace.Add(pMesh.Vertices.Count - 1);
                    }
                    else
                    {
                        //push this index to current face
                        currFace.Add(id);
                    }
                }

                pMesh.Faces.AddFace(currFace);
            }

            return pMesh;
        }

And to convert a PlanktonMesh to polylines:

        List<Polyline> PolylinesFromPMesh(PlanktonMesh pMesh)
        {

            var faces = new List<Polyline>();
            for (int i = 0; i < pMesh.Faces.Count; i++)
            {
                var tmpCurve = new Polyline();
                var faceCirculator = pMesh.Halfedges.GetFaceCirculator(pMesh.Faces[i].FirstHalfedge);
                foreach (var id in faceCirculator)
                {
                    var idx = pMesh.Halfedges[id].StartVertex;
                    var tmpPt = new Point3d(pMesh.Vertices[idx].X, pMesh.Vertices[idx].Y, pMesh.Vertices[idx].Z);
                    tmpCurve.Add(tmpPt);
                }

                //close the curve
                tmpCurve.Add(tmpCurve.PointAt(0));
                faces.Add(tmpCurve);
            }

            return faces;
        }

@danhambleton
Copy link

Just found the ToPolyline method....I guess that works too ;)

@mikeheiss
Copy link

Hi @pearswj, I attempted to duplicate your example using GhPython, but I got the error "Data conversion failed from Goo to PlanktonMesh" on the output. Any ideas? Within the Python window I can print pmesh.Vertices[0].X for example and it works fine.

plankton script

After I get this quad example working, I would like to attempt with ngon faces >4 sides.

@pearswj
Copy link
Contributor Author

pearswj commented Nov 2, 2016

Hey @viper4049, I just tried this again in Rhino 5, Rhino WIP and Rhino WIP for Mac. Only in Rhino WIP for Windows do I see your error. I'll pass this on to @piac as he's responsible for the new Python script component in Grasshopper 1.0.

@pearswj
Copy link
Contributor Author

pearswj commented Nov 2, 2016

@viper4049, I've moved this particular issue to youtrack.

@pearswj pearswj modified the milestones: 0.4.0, future Nov 2, 2016
@piac
Copy link

piac commented Nov 2, 2016

@pearswj Check what happens in your public override bool CastFrom(object source) method in meshmash. I think this method is incomplete, as it looks like it lacks the IGH_Goo implementation. What object do you get there?
https://github.com/meshmash/Plankton/blob/master/src/PlanktonGh/GH_PlanktonMesh.cs#L267

@piac
Copy link

piac commented Nov 2, 2016

One addition that I think is required is this one:

var cast_as = source as IGH_Goo;
if (cast_as != null)
{
//do stuff with cast_as.CastTo<PlanktonMesh>(out pm);
}

Also, I think this needs to happen at the beginning of your code.

@pearswj
Copy link
Contributor Author

pearswj commented Nov 2, 2016

@viper4049, just to keep you in the loop... I managed to get this working by making sure that the python script was referencing the same Plankton.dll that Grasshopper loads*.

clr.AddReferenceToFileAndPath("C:\Users\Will\AppData\Roaming\Grasshopper\Libraries\Plankton.dll")

*Actually, Grasshopper loads Plankton.gha, which in turn references Plankton.dll. But you get the idea...

@pearswj
Copy link
Contributor Author

pearswj commented Nov 2, 2016

You can also try the following if, like me, hard coded paths make you shiver:

import Grasshopper
appdata = Grasshopper.Folders.DefaultAssemblyFolder

import clr
clr.AddReferenceToFileAndPath(appdata + "Plankton.dll")

@mikeheiss
Copy link

Excellent, thanks - the python script now works! This ability to build ngon pmeshes was exactly what I was looking for.

Using predefined cells from LunchBox everything works fine. However when I attempt to make my own mesh edge loops, only parts of the pmesh are created. My end goal is to be able to feed any polyline graph (simply connected, not in loops) and create an ngon pmesh. I'm using curves splitting a surface to get the connected mesh edge loops, then creating a tree of polylines to feed pmDecompose.

If you have time, would you be able to check if you see the same behavior? If not, I can try updating my libraries. If so, any ideas? When I bake the polylines going into pmDecompose everything looks well behaved (even in the areas where the pmesh isn't created). Perhaps it's a tolerance issue with the vertices not lining up perfectly? I tried Topologizer with a tolerance but that didn't help anything.

pmesh test
build pmesh

Here's the link to my GH file (for some reason it wouldn't let me upload).
(https://dl.dropboxusercontent.com/u/15647695/Build%20pmesh%20test.gh)

@pearswj
Copy link
Contributor Author

pearswj commented Nov 3, 2016

@viper4049, it's the face winding directions that are causing the problem. Plankton only handles manifold meshes, i.e. meshes which have a front and a back. This orientation is determined by the "right-hand rule" i.e. if the vertices of a face are ordered counter-clockwise then the face normal will be out of the page/screen.

screen shot 2016-11-03 at 10 17 20

You could try the following:

if pmesh.Faces.AddFace(face) < 0: # AddFace returns -1 if the face couldn't be added
        pmesh.Faces.AddFace(reversed(face)) # try adding the opposite face

But, this won't work all the time. To do this properly, you need to make the face-winding uniform before building the mesh:

screen shot 2016-11-03 at 11 12 31

I did this here by comparing the normal of the original surface (sampled from the centroid of each face polyline) with the cross product of the first two edges of each face polyline. The comparison uses the dot product which will be either positive or negative, depending on whether the winding of the face polyline agrees with the right hand rule, or not.

untitled

@piac
Copy link

piac commented Nov 3, 2016

make the face-winding uniform

You can also use Weaverbird's Unify Face Windings for that. It works also on polylines that meet at vertices.

@pearswj
Copy link
Contributor Author

pearswj commented Nov 3, 2016

Yes, do that! @piac you're a genius 😎.

@mikeheiss
Copy link

Perfect, simpler the better! Thanks so much for your help, I learned a lot through this exercise.

@mikeheiss
Copy link

I wrote up this example here in case anyone else was looking for the same thing.

http://www.grasshopper3d.com/group/plankton/forum/topics/cytoskeleton?commentId=2985220%3AComment%3A1633831&groupId=2985220%3AGroup%3A875392

@pearswj pearswj mentioned this issue Feb 23, 2017
@pearswj pearswj removed this from the future milestone Feb 23, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants