Get edges segments in a polygon object



  • Hi!
    I'm trying to find the selected edges segments in a polygon object, like the one below:
    alt text

    I want to get each segment separated, so I can create some functions like the example below:

    for segment in segmentlist:
        MoveInUvSpace()
    

    I've tried a lot of things with BaseSelect, Neighbor and PolygonObject classes, but no success...

    here's my testing code, I was able to get the total edge count, get the ammount of edges selected edges and get the the selected edge with its index.

    import c4d
    
    def main():
        
        op = doc.GetActiveObject()
        
        nb = c4d.utils.Neighbor()
        nb.Init(op)
        
        seledges = op.GetSelectedEdges(nb,c4d.EDGESELECTIONTYPE_SELECTION) #base select
        print seledges.GetSegments()
        print seledges.GetCount()
        print seledges.GetRange(1,nb.GetEdgeCount())
        print "total edges", nb.GetEdgeCount()
        
        
        notselected = []
        selectededge = []
        bs = op.GetEdgeS()
        sel = bs.GetAll(nb.GetEdgeCount())
        for index, selected in enumerate(sel):
            if not selected: continue
            print "Index", index, "is selected"
            selectededge.append(selected)
        print notselected
        print selected
        
    
    if __name__=='__main__':
        main()
        
    

    if anyone have any hint in how I could achieve this, I would be very happy!

    Flavio Diniz



  • hello,

    i gave it a try and came with that "solution", i just ran some test on a plane but that should give you some idea.
    this would need some polish like ordering the points in the result and it can probably be optimized.

    I've set this thread to "ask a question" please set it as solved if you think your question as been replied (even if there's no solution :p)

    Of course this will consider a "cross" as one single segment

    import c4d
    from c4d import gui
    # Welcome to the world of Python
    
    
    
    class MySegments (object):
        def __init__(self, op):
            if op is None:
                raise ValueError("can't initialize class with a None object")
            if op.IsInstanceOf(c4d.Opolygon) != True:
                raise ValueError("class only work with polygon object")
    
            self.op = op
            self.nb = c4d.utils.Neighbor()
            self.nb.Init(op)
            self.polys = op.GetAllPolygons()
            self.edgeSelected = op.GetEdgeS()
            self.ces = self.edgeSelected.GetClone()
            self.segments = []
    
        def CreateSegment(self, polyAid, edgeAid):
            """
            Recursive function that will check if any neighbor edge is selected
            If so, it will recurse with the new edge.
            """
            # first deselect edge so we are sure we are not adding this edge twice
            self.DeselectEdge(polyAid, edgeAid)
            # retrieves the points of this edge
            points = self.polys[polyAid].EdgePoints(edgeAid)
            # add this edge to the last segment
            self.segments[-1].append(points)
            # for each point, check if any attached edge is selected
            for point in points:
                neibPolysIds = self.nb.GetPointPolys(point)
                for polyBid in neibPolysIds:
                    for edgeBid in xrange(4):
                        if self.ces.IsSelected(4 * polyBid + edgeBid):
                            # checks if any point are in common
                            if self.PointInCommon(polyAid, edgeAid, polyBid, edgeBid):
                                # this edge must be added to the last segment and check for the next edges.
                                self.CreateSegment(polyBid, edgeBid)
    
        def PointInCommon(self, polyAid, edgeAid, polyBid, edgeBid):
            """ this function check if two edge have some point in common"""
            polyA = self.op.GetPolygon(polyAid)
            polyB = self.op.GetPolygon(polyBid)
    
            edgeAPoints = polyA.EdgePoints(edgeAid)
            edgeBPoints = polyB.EdgePoints(edgeBid)
            if edgeAPoints[0] == edgeBPoints[0] or edgeAPoints[0] == edgeBPoints[1]:
                return True
            if edgeAPoints[1] == edgeBPoints[0] or edgeAPoints[1] == edgeBPoints[1]:
                return True
            return False
    
    
        def ComparePoints(self, pointsA, pointsB):
            """
             This function compare if two array of points are equals
            """
            if pointsA[0] == pointsB[0] and pointsA[1] == pointsB[1]:
                return True
            if pointsA[1] == pointsB[0] and pointsA[0] == pointsB[1]:
                return True
            return False
    
    
        def DeselectEdge(self, polyAid, edgeAid):
            """
            The BaseSelect we got from GetEdgeS will have two entry for one selected edge (on per polygon)
            we must retrieve the other polygon and find the edge in common to deselect it.
            """
            # Deselect the first edge.
            self.ces.Deselect(4 * polyAid + edgeAid)
            # Gets the poinfs from edge A id
            pointsA = self.polys[polyAid].EdgePoints(edgeAid)
            # Retrieves the polygin ID of the polygon on the other side of the edge
            polyBid = self.nb.GetNeighbor(pointsA[0], pointsA[1], polyAid)
            #checks if there's no polygon on the other side
            if polyBid == -1:
                return 
            # Get the polygon Structure
            polyB = self.op.GetPolygon(polyBid)
            # Check each edge if it's the same than the firt edge and deselect it.
            for edgeBid in xrange(4):
                pointsB = polyB.EdgePoints(edgeBid)
                if self.ComparePoints(pointsA, pointsB):
                    self.ces.Deselect(4 * polyBid + edgeBid)
    
    
    
        def Execute(self):
            segments = []
            polycnt = self.op.GetPolygonCount()
    
            for polyid in xrange(polycnt):
                for edgeid in xrange(4):
                    element = 4 * polyid + edgeid
                    # checks if the edge is selected
                    if self.ces.IsSelected(element):
                        # create a new segment for this edge
                        self.segments.append([])
                        # the function CreateSegment will add this edge and search for any other edge attached to that edge.
                        self.CreateSegment(polyid, edgeid)
            print self.segments
    
    
    
    def main():
        if op is None:
            raise ValueError("select at least one object")
    
        mySegments = MySegments(op)
        mySegments.Execute()
    
    
    # Execute main()
    if __name__=='__main__':
        main()
    

    cheers,
    Manuel



  • I don't think there is such a thing as a "edge segment". There are only individually selected edges. How such single edges are combined to a "segment" is up to you.

    I also think one would probably need the GetOriginalEdgePoints() function of the Modeling class, which is not available in Python.



  • As far as I know your only option would be to collect your "segments" yourself. At least, that is how I have been doing it.



  • @PluginStudent @C4DS
    ah, so I think this is more complex than I thought 🤔

    I guess I have to make a function to compare the edges by using their points...
    if two edges shares the same point, it means these two edges are a single segment. So create a BaseSelect of these edges and use it in a for loop.
    It may cause some bugs depending how the geometry is... but at least is a starting point and a tough one for me xD

    Thank you guys!

    Flavio Diniz



  • hello,

    i gave it a try and came with that "solution", i just ran some test on a plane but that should give you some idea.
    this would need some polish like ordering the points in the result and it can probably be optimized.

    I've set this thread to "ask a question" please set it as solved if you think your question as been replied (even if there's no solution :p)

    Of course this will consider a "cross" as one single segment

    import c4d
    from c4d import gui
    # Welcome to the world of Python
    
    
    
    class MySegments (object):
        def __init__(self, op):
            if op is None:
                raise ValueError("can't initialize class with a None object")
            if op.IsInstanceOf(c4d.Opolygon) != True:
                raise ValueError("class only work with polygon object")
    
            self.op = op
            self.nb = c4d.utils.Neighbor()
            self.nb.Init(op)
            self.polys = op.GetAllPolygons()
            self.edgeSelected = op.GetEdgeS()
            self.ces = self.edgeSelected.GetClone()
            self.segments = []
    
        def CreateSegment(self, polyAid, edgeAid):
            """
            Recursive function that will check if any neighbor edge is selected
            If so, it will recurse with the new edge.
            """
            # first deselect edge so we are sure we are not adding this edge twice
            self.DeselectEdge(polyAid, edgeAid)
            # retrieves the points of this edge
            points = self.polys[polyAid].EdgePoints(edgeAid)
            # add this edge to the last segment
            self.segments[-1].append(points)
            # for each point, check if any attached edge is selected
            for point in points:
                neibPolysIds = self.nb.GetPointPolys(point)
                for polyBid in neibPolysIds:
                    for edgeBid in xrange(4):
                        if self.ces.IsSelected(4 * polyBid + edgeBid):
                            # checks if any point are in common
                            if self.PointInCommon(polyAid, edgeAid, polyBid, edgeBid):
                                # this edge must be added to the last segment and check for the next edges.
                                self.CreateSegment(polyBid, edgeBid)
    
        def PointInCommon(self, polyAid, edgeAid, polyBid, edgeBid):
            """ this function check if two edge have some point in common"""
            polyA = self.op.GetPolygon(polyAid)
            polyB = self.op.GetPolygon(polyBid)
    
            edgeAPoints = polyA.EdgePoints(edgeAid)
            edgeBPoints = polyB.EdgePoints(edgeBid)
            if edgeAPoints[0] == edgeBPoints[0] or edgeAPoints[0] == edgeBPoints[1]:
                return True
            if edgeAPoints[1] == edgeBPoints[0] or edgeAPoints[1] == edgeBPoints[1]:
                return True
            return False
    
    
        def ComparePoints(self, pointsA, pointsB):
            """
             This function compare if two array of points are equals
            """
            if pointsA[0] == pointsB[0] and pointsA[1] == pointsB[1]:
                return True
            if pointsA[1] == pointsB[0] and pointsA[0] == pointsB[1]:
                return True
            return False
    
    
        def DeselectEdge(self, polyAid, edgeAid):
            """
            The BaseSelect we got from GetEdgeS will have two entry for one selected edge (on per polygon)
            we must retrieve the other polygon and find the edge in common to deselect it.
            """
            # Deselect the first edge.
            self.ces.Deselect(4 * polyAid + edgeAid)
            # Gets the poinfs from edge A id
            pointsA = self.polys[polyAid].EdgePoints(edgeAid)
            # Retrieves the polygin ID of the polygon on the other side of the edge
            polyBid = self.nb.GetNeighbor(pointsA[0], pointsA[1], polyAid)
            #checks if there's no polygon on the other side
            if polyBid == -1:
                return 
            # Get the polygon Structure
            polyB = self.op.GetPolygon(polyBid)
            # Check each edge if it's the same than the firt edge and deselect it.
            for edgeBid in xrange(4):
                pointsB = polyB.EdgePoints(edgeBid)
                if self.ComparePoints(pointsA, pointsB):
                    self.ces.Deselect(4 * polyBid + edgeBid)
    
    
    
        def Execute(self):
            segments = []
            polycnt = self.op.GetPolygonCount()
    
            for polyid in xrange(polycnt):
                for edgeid in xrange(4):
                    element = 4 * polyid + edgeid
                    # checks if the edge is selected
                    if self.ces.IsSelected(element):
                        # create a new segment for this edge
                        self.segments.append([])
                        # the function CreateSegment will add this edge and search for any other edge attached to that edge.
                        self.CreateSegment(polyid, edgeid)
            print self.segments
    
    
    
    def main():
        if op is None:
            raise ValueError("select at least one object")
    
        mySegments = MySegments(op)
        mySegments.Execute()
    
    
    # Execute main()
    if __name__=='__main__':
        main()
    

    cheers,
    Manuel



  • Fantastic @m_magalhaes !
    works very well! and for the use I'm planning, I will always be using parallel selection segments, so cross selections isn't a issue 🙂 !

    there's an small error, I guess it's happening because there's no polygons to the left to be checked.
    alt text

    I haven't had time to fully read your code yet, but it's already very helpful!
    I'll try to solve this error by modifying your code or building another use using you as base.

    Thank you!

    (I'll let it unsolved for today, in case someone wants to post something else, then I'll change to solved)

    Flavio Diniz



  • hi,

    right, if you are at a border there's not polygon on the other side:

    i've update my code on the other post with this

     if polyBid == -1:
                return 
    

    Cheers,
    Manuel



  • Awesome @m_magalhaes, works perfect now!
    Thank very much!

    Flavio


Log in to reply