meshmash / Plankton

A C# half-edge mesh data structure, and components for using this in Grasshopper/Rhino
http://meshmash.github.io/Plankton
GNU Lesser General Public License v3.0
216 stars 66 forks source link

Dual supports open meshes #23

Closed davestasiuk closed 9 years ago

davestasiuk commented 9 years ago

PlanktonMesh.PlanktonDual() now handles open meshes by including boundaries, and works cleanly with closed meshes. To be added is additional functionality for removing boundaries if desired. Also, boundary points are currently calculated as midpoints of the primal halfedges...making these perpendicular to the new face centers could be desirable.

Resolves #22.

pearswj commented 9 years ago

Dave, thanks for this! Glad my instructions were easy to follow. My immediate thought is that we should consolidate these two functions into one Dual function. Perhaps we could use optional parameters for the handling of boundaries (I think the default behaviour should ignore boundary vertices when creating dual faces).

davestasiuk commented 9 years ago

I think those are good ideas on both counts. The two ways I wrote the dual - this one, without the boundaries, and the other one, with - are quite different in a few key places. I suppose that we could just keep them both, and then just gate between them with an optional RetainBoundary bool...but as you pointed out in the other one, the means of sorting the naked edges wasn't particularly good, and in any event, it doesn't seem particularly elegant to double up on so much, though.

pearswj commented 9 years ago

@davestasiuk We should add some tests for this also, checking global feature counts (i.e. do we have the right number of "active" halfedges in the dual) and perhaps some local checks too, around boundaries especially, to check everything has been linked up correctly.

pearswj commented 9 years ago

As an aside, I've moved the automated builds to http://pearswj.co.uk/builds/plankton (look for Branch Ref: pr/23).

pearswj commented 9 years ago

I still think we should consolidate these two methods into one Dual function, with optional boundary edge treatment. Can we hold back on shouting about the PlanktonDual method so that we don't cause too many problems when we come to deprecate it?

/cc @Dan-Piker @davestasiuk

Dan-Piker commented 9 years ago

Agreed. I put it in because I wanted be able to use this on open meshes, but after testing it seems that there are actually some problems with this PlanktonDual method where the PrevHalfedge is not correctly assigned. So let's revert the merge until finding what the problem is, and then make it just a single Dual method that works for both.

davestasiuk commented 9 years ago

Hey guys- I'll be happy to have a look at this, hopefully a bit later on in the week. We are into production mode on our current project, so I am underwater with that. It's been a goal of mine though to get to this. I also will send you a note on a separate Plankton topic I've been thinking about.

harrilewis commented 7 years ago

Hi @davestasiuk I'm using your PlanktonMesh.PlanktonDual method. Did you ever figure out the issue @Dan-Piker found with the PrevHalfEdge not being assigned?

I'm available to help debug if an extra pair of eyes would be useful.

pearswj commented 7 years ago

Hey @harrilewis, PlanktonMesh.Dual() does work on open meshes. The current method is much more simplistic than Dave's contribution. It produces the same output as Weaverbird's "DualGraph", i.e. no dual-faces for boundary vertices on the primal mesh. Check out the code below for something that handles those boundary faces...

"""Plankton dual (creates faces for boundary vertices).
    Inputs:
        m: mesh as Rhino Mesh
    Output:
        a: dual mesh as Polylines
        b: dual mesh as PlanktonMesh"""

__author__ = "will"

import rhinoscriptsyntax as rs

import Grasshopper
appdata = Grasshopper.Folders.DefaultAssemblyFolder

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

import Plankton
import PlanktonGh

clr.ImportExtensions(PlanktonGh.RhinoSupport)

m = x.ToPlanktonMesh()
#a = m.Dual().ToPolylines()

if not m.IsClosed():
    dual = Plankton.PlanktonMesh()

    # create vertices from face centers
    for i in range(m.Faces.Count):
        fc = m.Faces.GetFaceCenter(i)
        dual.Vertices.Add(fc.X, fc.Y, fc.Z)

    # create boundary vertices
    for i in range(0, m.Halfedges.Count, 2):
        v0 = m.Halfedges[i].StartVertex
        v1 = m.Halfedges[m.Halfedges.GetPairHalfedge(i)].StartVertex
        mid = (m.Vertices[v1].ToXYZ() + m.Vertices[v0].ToXYZ())
        dual.Vertices.Add(mid.X * 0.5, mid.Y * 0.5, mid.Z * 0.5)

    # create faces from the adjacent face indices of non-boundary vertices
    for i in range(m.Vertices.Count):
        if (m.Vertices.IsBoundary(i)):
            hs = m.Vertices.GetHalfedges(i)
            vs = []
            for j in hs: # clockwise
                if m.Halfedges[j].AdjacentFace > -1:
                    vs.append(m.Halfedges[j].AdjacentFace)
                else:
                    # add extra vertices for dual-faces created from boundary vertices
                    k = m.Halfedges[j].PrevHalfedge
                    vs.append(int((k - (k % 2)) / 2) + m.Faces.Count)
                    vs.append(int((j - (j % 2)) / 2) + m.Faces.Count)
            dual.Faces.AddFace(vs)
        else:
            dual.Faces.AddFace(m.Vertices.GetVertexFaces(i))
    # dual.Compact()
else:
    # use built-in Dual for closed meshes
    dual = m.Dual()

a = dual.ToPolylines()
b = dual

Let me know if this is useful!

harrilewis commented 7 years ago

Hi @pearswj thanks for the above - very useful!

I was getting some funny runaway edges - I think the line:

j = m.Halfedges[j].NextHalfedge

should be removed - j should remain as the index of the halfedge in question.

pearswj commented 7 years ago

@harrilewis you're totally right. Not sure how that crept in there; It's not in the script that I'm actually using! 🤷‍♂️ I'll edit it...