# Best way to get vertices from a point

On 05/12/2017 at 03:04, xxxxxxxx wrote:

I'm looking for a "best-practice" approach to this problem. I need to read out an object and convert it to its vertex positions (not point positions! vertices.). As for the why: this appears to be the only way to retain UV coordinates for each vertex (using points' UVs will cause issues because a point is shared between multiple polygons, usually). So far it looks like making it editable and calling Disconnect on it seems like the only way to do this - however I was wondering whether there might be a more elegant solution whereby I could get the vertices per point?

Cheers
Michael

On 05/12/2017 at 04:10, xxxxxxxx wrote:

For some understanding purpose, and to be sure we talk about the same.

Polygon is define by his edge.

Edge is 2 Vertexs.

c4d.CPolygon actually represent a polygon.
c4d.CPolygon get in maximum 4 points (a, b, c, d) if it's triangle c and d are egual.
c4d.CPolygon vertex (a,b,c,d presented in the last sentence) are VertexID
c4d.PolygonObject inherite from c4d.PointObject
VertexID are shared accross the PointObject
UVVertexID are shared accross CPolygon

To get position of a specific point you have to do

``````#op is c4d.PolygonObject
localPointPos = op.GetPoint(0) # Get the local position of the VertexID 0
globalPointPos = op.GetPoint(0) * op.GetMg() # Get the world position of the VertexID 0
``````

If you want to go from PolygonID to VertexID

``````#op is c4d.PolygonObject
poly = op.GetPolygon(0) #Get the c4d.CPolygon with the polygonID 0
localPointPos = op.GetPoint(poly.a) # Get the local position of the first VertexID inside CPolygon (called Cpolygon.a)
``````

About UV since they belong to CPolygon you have to use GetPointPolys to find all the shared CPolygon accross a given VertexID. Then for each CPolygon you have to iterate over (a,b,c,d) to get the desired VertexID. Then you have to move it using SetSlow.

I hope it's andwerd your question.

On 05/12/2017 at 04:26, xxxxxxxx wrote:

Hi,

no, it's not quite it. I'm aware of all the steps to get UVs and Points from the geometry. The problem is that in Cinema all the points usually are treated as shared points. So if you have two polygons next to each other, their bordering points (on the same edge) are shared point IDs.

1 - 2 - 3
|    |    |
4 - 5 - 6

So you get CPolygon with 1245 and 2356. Now if you UV map a texture onto this, with a repeating UV for example, you end up with these UV coordinates for _each_ of the two polygons.

(0,0) - (1,0)(0,0) - (1,0)
|              |             |
(0,1) - (1,1)(0,1) - (1,1)

This results in point 2, for example, having two UVs: (1,0) (from the left polygon) and (0,0) from the right polygon.

To properly handle this, you need to have two vertices (or more, depending on how many polygons share this point), where each vertex stores the position of the Point and also its individual UV (and normal).

This is something that apparently is handled entirely internally in Cinema - my question now is, can I get this data through the means of the Python API somehow, without jumping through hoops for it (e.g. Make Editable, then Triangulate, the Disconnect (which may even screw up the normals?)).

Michael

On 05/12/2017 at 05:04, xxxxxxxx wrote:

Originally posted by xxxxxxxx

To properly handle this, you need to have two vertices (or more, depending on how many polygons share this point), where each vertex stores the position of the Point and also its individual UV (and normal).

It's actually the case since as said in my previous post, UVVertexID belong to CPolygon vertex(a,b,c,d). Maybe I missunderstand something about how you do your UV stuff but basicly here is a code that show you that you have 2 UVVertexID for VertexID 1 (2 in your schema, since ID start at 0 and not 1)

``````import c4d

def CreateObject() :
obj  = c4d.BaseObject(c4d.Opolygon)

points = [c4d.Vector(0, 0, -100), # Coordonnées des points
c4d.Vector(0, 0, 0),
c4d.Vector(0, 0, 100),
c4d.Vector(100, 0, -100),
c4d.Vector(100, 0, 0),
c4d.Vector(100, 0, 100)]

polys = [c4d.CPolygon(0, 1, 4, 3), # Points ABCD du polygone
c4d.CPolygon(1, 2, 5, 4)]

obj.ResizeObject(len(points), len(polys))

obj.SetAllPoints(points)

for i, p in enumerate(polys) :
obj.SetPolygon(i, p)

obj.Message(c4d.MSG_UPDATE)
doc.InsertObject(obj)

return obj

def CreateUVTag(obj) :
tag = c4d.UVWTag(obj.GetPolygonCount())
obj.InsertTag(tag)

return tag

def main() :
obj = CreateObject()
if not obj: return

uvTag = CreateUVTag(obj)
if not uvTag: return

# Now everything is setup, let's change VertexID 1 (2 in your schema, since ID start at 0 and not 1)
nbr = c4d.utils.Neighbor()
nbr.Init(obj)

polys = nbr.GetPointPolys(1) # Get all the PolygonID shared with vertexID 1
polys_data = obj.GetAllPolygons()

# Loop for each CPolygon and add to list_id, the PolygonID["poly_id"], and the actual CPolygon vertex ID (a,b,c,d are mapped to 0,1,2,3)["pt_num"]
list_id = list()
for poly_id in polys:
poly = polys_data[poly_id]
found_id = poly.Find(1) # here we search for want VertexID 1

if found_id != c4d.NOTOK:
buffer_data = dict()
buffer_data["poly_id"] = poly_id
buffer_data["pt_num"] = found_id

list_id.append(buffer_data)

# Now we get list of all Cpolygon with the corresponding (a,b,c,d) that are equal to VertexID 1
for pt in list_id:
buffer_uv = uvTag.GetSlow(pt["poly_id"])

list_uv = [buffer_uv["a"],
buffer_uv["b"],
buffer_uv["c"],
buffer_uv["d"]]

# change the value only for the corresponding CPolygon vertexID look comment at line 48
list_uv[pt["pt_num"]] = c4d.Vector(0.5, 0.0, 0.0)

# Set the point where you want
uvTag.SetSlow(pt["poly_id"],
list_uv,
list_uv,
list_uv,
list_uv
)

if __name__=='__main__':
main()
``````

Please take a look at my script linked in my previous post

But maybe I complettly missunderstand your question and someone else get it ! On 05/12/2017 at 05:17, xxxxxxxx wrote:

No, it's not a complete misunderstanding, but it's not the result I'm looking for What I am looking for is simply a simple way to say "for Point X, return an Array of Vertices and their UVs" but I think it's just not there and I'll write my own.

Thanks anyway On 07/12/2017 at 14:06, xxxxxxxx wrote:

Hi Michael, thanks for writing us.

if I correctly understood your request, the following code should satisfy your need.

``````
import c4d

def main() :
obj = doc.GetActiveObject()

# check something is active
if obj is None:
print "No object selected"
return

# check the object to be an editable polygon object
if obj.GetType() != c4d.Opolygon:
print "Selected object is a generator, please make it editable"
return

# attempt to retrive a UVWTag
uvwTag = obj.GetTag(c4d.Tuvw)
if uvwTag is None:
print "uvwTag doesn't exists"
return

# attempt to access points and polygons lists
points = obj.GetAllPoints()
polygons = obj.GetAllPolygons()
if polygons is None or points is None:
print "points or polygons don't exist"
return

# store the polygons count
polyCnt = len(polygons)

# preallocate the list containing the final pos and uvw data
alldata = [None] * polyCnt

# loop through the polygons
for i in xrange(polyCnt) :
polygon = polygons[i]
# access the UVW data for the current polygon
uvwPolygon = uvwTag.GetSlow(i)
# check whatever the polygon has three or four vertices
if polygon.IsTriangle() :
# cycle over all the poiygon data and store in alldata
pos = points[polygon.a]
uvw = uvwPolygon["a"]
data = [[pos, uvw]]
pos = points[polygon.b]
uvw = uvwPolygon["b"]
data.append([pos, uvw])
pos = points[polygon.c]
uvw = uvwPolygon["c"]
data.append([pos, uvw])
alldata[i] = data
else:
pos = points[polygon.a]
uvw = uvwPolygon["a"]
data = [[pos, uvw]]
pos = points[polygon.b]
uvw = uvwPolygon["b"]
data.append([pos, uvw])
pos = points[polygon.c]
uvw = uvwPolygon["c"]
data.append([pos, uvw])
pos = points[polygon.d]
uvw = uvwPolygon["d"]
data.append([pos, uvw])
alldata[i] = data

# just print out to check the result
for j in xrange(len(alldata)) :
data = alldata[j]
print "Polygon["+str(j) +"]"
for k in xrange(len(data)) :
spacer = " ---> vtx [" + str (k) + "]"
posString = " pos:[" + str(data[k].x) + ", " + str(data[k].y) +", "+ str(data[k].z) + "]"
uvwString = " uvw:[" + str(data[k].x) + ", " + str(data[k].y) +", "+ str(data[k].z) + "]"
print spacer, posString, uvwString

if __name__=='__main__':
main()
``````

Best, Riccardo