SOLVED 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