• 0 Votes
    4 Posts
    871 Views
    M
    Hi @mp5gosu , I will set the topic as closed. Note that the fix will not come in the next update but don't worry we have it logged and it's on our list of things to fix in the future. Cheers, Maxime.
  • Polygon Islands Convenience Method?

    Cinema 4D SDK r23 python
    7
    1
    0 Votes
    7 Posts
    3k Views
    E
    Here is something I recently used to count UV Islands as well as get some other info import c4d from collections import defaultdict def get_uv_islands(obj, tol=1e-5): """ Compute UV islands for the given polygon object using its UVW tag. This version retrieves the UV dictionary for each polygon using uvTag.GetSlow(polyIndex), then groups connected polygons (sharing at least one UV coordinate) into islands using an iterative flood-fill algorithm. """ uvw_tag = obj.GetTag(c4d.Tuvw) if uvw_tag is None: c4d.gui.MessageDialog("The object does not have a UVW tag.") return None poly_count = obj.GetPolygonCount() # Build maps: # - face_to_uvs: mapping from polygon index to its set of rounded UV keys. # - uv_to_faces: reverse mapping from each UV key to the set of polygon indices using that UV. face_to_uvs = defaultdict(set) uv_to_faces = defaultdict(set) def uv_key(vec): # Round UV vector components to mitigate floating-point precision issues. return (round(vec.x, 5), round(vec.y, 5)) # Build connectivity maps based on each polygon's UV data. for poly_index in range(poly_count): poly = obj.GetPolygon(poly_index) uv_data = obj.GetTag(c4d.Tuvw).GetSlow(poly_index) # If the polygon is a triangle, remove the extraneous 'd' key. if poly.IsTriangle() and 'd' in uv_data: del uv_data['d'] for key in uv_data: uv_vec = uv_data[key] key_tuple = uv_key(uv_vec) face_to_uvs[poly_index].add(key_tuple) uv_to_faces[key_tuple].add(poly_index) # Use an iterative flood-fill to group connected faces. islands = [] faces_left = set(range(poly_count)) while faces_left: island = [] start_face = next(iter(faces_left)) # Pick an arbitrary face from unvisited ones. stack = [start_face] while stack: face_idx = stack.pop() if face_idx not in faces_left: continue faces_left.remove(face_idx) island.append(face_idx) # For every UV key in this face, add all neighboring faces. for uv_val in face_to_uvs[face_idx]: for neighbor in uv_to_faces[uv_val]: if neighbor in faces_left: stack.append(neighbor) islands.append(island) return islands def get_island_uv_center(obj, uvw_tag, island): """ Given a polygon object, its UVW tag, and an island (list of polygon indices), compute the UV bounding box and center. """ # Initialize min/max with infinities. min_u = float('inf') max_u = -float('inf') min_v = float('inf') max_v = -float('inf') # Gather unique UV coordinates from all faces in the island. unique_uvs = {} for face_idx in island: poly = obj.GetPolygon(face_idx) uv_data = uvw_tag.GetSlow(face_idx) if poly.IsTriangle() and 'd' in uv_data: del uv_data['d'] for key in uv_data: uv = uv_data[key] key_tuple = (round(uv.x, 6), round(uv.y, 6)) unique_uvs[key_tuple] = uv # Compute the bounding box. for uv in unique_uvs.values(): if uv.x < min_u: min_u = uv.x if uv.x > max_u: max_u = uv.x if uv.y < min_v: min_v = uv.y if uv.y > max_v: max_v = uv.y center_u = (min_u + max_u) / 2.0 # Invert V axis so the center is correct in UV space. center_v = 1.0 - ((min_v + max_v) / 2.0) return center_u, center_v, min_u, max_u, min_v, max_v def main(): doc = c4d.documents.GetActiveDocument() obj = doc.GetActiveObject() if obj is None: c4d.gui.MessageDialog("Please select a polygon object.") return uvw_tag = obj.GetTag(c4d.Tuvw) if uvw_tag is None: c4d.gui.MessageDialog("The object does not have a UVW tag!") return islands = get_uv_islands(obj) if islands is None: return num_islands = len(islands) print("Number of UV islands:", num_islands) for idx, island in enumerate(islands): center_u, center_v, min_u, max_u, min_v, max_v = get_island_uv_center(obj, uvw_tag, island) print("Island", idx, "has faces:", island) print("Island Num",idx," Bounding Box: U [{:.6f}, {:.6f}], V [{:.6f}, {:.6f}]".format(min_u, max_u, min_v, max_v)) print(" Center: U = {:.6f}, V = {:.6f}".format(center_u, center_v)) if __name__=='__main__': main() Output looks something like Number of UV islands: 2 Island 0 has faces: [0, 5, 3, 4] Island Num 0 Bounding Box: U [0.004902, 0.495098], V [0.004902, 0.740196] Center: U = 0.250000, V = 0.627451 Island 1 has faces: [1, 2] Island Num 1 Bounding Box: U [0.004902, 0.495098], V [0.750000, 0.995098] Center: U = 0.250000, V = 0.127451 Hope it is useful!
  • SSL TLSV1_ALERT_PROTOCOL_VERSION Error on Mac

    Cinema 4D SDK r19 python macos
    3
    0 Votes
    3 Posts
    1k Views
    ?
    @m_adam Thank you, Maxime! Have a good weekend.
  • Handles in R18

    Cinema 4D SDK python r19 windows
    3
    1
    0 Votes
    3 Posts
    795 Views
    ?
    Thank you for letting me know, @ferdinand !
  • 0 Votes
    6 Posts
    1k Views
    P
    forget about it. i removed the c4d.OBJECT_INPUT flag during development and forgot to add it back.
  • How to know baking is end with BakeTextureTag?

    Cinema 4D SDK python r19
    7
    0 Votes
    7 Posts
    2k Views
    M
    Hi @velbie with the latest update of Cinema 4D (R24 SP1), the BAKE_TEX_AO_VERTEXMAPS issue is fixed. Cheers, Maxime.
  • Querying and Storing Object Information

    Moved Cinema 4D SDK python
    9
    0 Votes
    9 Posts
    2k Views
    ferdinandF
    Hi @Sturdy_Penguin , without further questions or feedback, we will consider this thread as solved by Monday and flag it accordingly. Cheers, Ferdinand
  • 0 Votes
    8 Posts
    1k Views
    beatgramB
    @Cairyn Thank you so much for helping me again!
  • 0 Votes
    4 Posts
    1k Views
    M
    thank you for your help, I am trying to understand ... am I right in the assumption that this is not "clean code" in a pythonic sense ? kind regards
  • Gets the point weight of the Field object.

    Cinema 4D SDK
    2
    0 Votes
    2 Posts
    619 Views
    ferdinandF
    Hi @x_nerve, thank you for reaching out to us. The most straightforward way to sample a FieldObject is FieldObject.Sample; there are also other sample methods attached to the various fields related classes, most notably c4d.FieldList. We have two examples in the Python SDK examples which showcase field sampling, fieldlist_sampling_r20 and fieldobject_sampling_20. You also mention "Is there a way to get the weight of the cube field points?"; you are probably aware of this, but since your phrasing could imply otherwise, it seems noteworthy to point out that fields are not discrete. So in other words, there is no finite amount of points you can exhaustively sample for a field object, since the object is non-discrete. You have to pick a point or a set of points you want to sample for a field object, which can be any point in in the value range c4d.Vector can handle. If there are any questions left, please do not hesitate to ask. Cheers, Ferdinand
  • 0 Votes
    15 Posts
    2k Views
    beatgramB
    @m_adam Oh, that's a little update for many users but huge for tiny developers like me! Thank you so much for the heads up.
  • GroupBorderNoTitle change GUI or flags after user input

    Cinema 4D SDK
    4
    0 Votes
    4 Posts
    918 Views
    ferdinandF
    Hi @mogh, thank you for reaching out to us and thank you @mp5gosu for providing help. I think the most meaningful thing I can say is that GeDialog is pretty forgiving and not as strict as the sum of its methods might imply; at least that was my insight to be gained when I encountered the class first. Since you said you consider this to be still rough, here are some tips that might be helpful. All following method references are members of GeDialog. You can define and load file based resources for dialogs, just like it is implicitly done with descriptions, with LoadDialogResource. This helps to clean up GeDialog implementations from the inherent clutter that comes with complex interface definitions. You can also do this to some extent in a modular fashion, i.e., invoking LoadDialogResource multiple times will not replace the former content but instead append new content. CreateLayout is mostly a convenience method. Or in other words, there is nothing which does prevent you from modifying the resource of a dialog from anywhere else where you have access to the dialog instance (be careful with threading though). Resources are organized in groups and you can flush these groups with LayoutFlushGroup, for example to rebuild them on user interaction. Single arbitrary elements can be removed by invoking RemoveElement. The relevant methods are all grouped under Dialog Change Methods in the GeDialog documentation. If anything remains unclear, please do not hesitate to ask. Cheers, Ferdinand
  • Drawing to Multiple Views at Once

    Cinema 4D SDK r23 python windows
    5
    0 Votes
    5 Posts
    701 Views
    ?
    @ferdinand That's very helpful, thank you!
  • Thinking Particles- How to Set "Settings"

    Cinema 4D SDK r23 python
    5
    0 Votes
    5 Posts
    977 Views
    I
    Okay, thank you again.
  • Reflection Layer Settings

    Cinema 4D SDK python
    4
    1
    0 Votes
    4 Posts
    789 Views
    ferdinandF
    Hi @kosmos3d, without further questions or feedback, we will consider this thread as solved by Monday and flag it accordingly. Cheers, Ferdinand
  • Spline dynamics

    Cinema 4D SDK python r21 windows
    7
    0 Votes
    7 Posts
    2k Views
    bacaB
    @ferdinand you were clear and example is pretty good, I got the idea. No need to write code for me But it's not trivial overall, I just need to spend some time on this. Thanks again.
  • Global variable for Preferences Folder?

    Cinema 4D SDK r21 python
    7
    0 Votes
    7 Posts
    656 Views
    ferdinandF
    Hi @bentraje, hi @C4DS, you seem to have solved your problem yourself, so there is not much for me to add here apart from offering alternative solutions. One slightly dodgy way to get the preferences path is to use the path which is stored under c4d.PREF_MEMORY_PVHARDFOLDER in the world container of Cinema (it is the Memory>Cache Path attribute). A more elegant way is to use maxon.Application.GetUrl() which does properly handle the different paths under which the preferences can be stored (see example at the end of my posting for details). Cheers, Ferdinand """On how to iterate over the different preferences paths with the maxon API. """ import maxon def main(): """Entry point. """ for urlType in (maxon.APPLICATION_URLTYPE.GLOBALPREFS_DIR, maxon.APPLICATION_URLTYPE.PREFS_DIR, maxon.APPLICATION_URLTYPE.PREFS_DIR_STATIC): print (f"{urlType}:{maxon.Application.GetUrl(urlType)}") if __name__=='__main__': main()
  • 0 Votes
    5 Posts
    1k Views
    ferdinandF
    Hi @SolarPH, without further questions or feedback, we will consider this thread as solved by Monday and flag it accordingly. Cheers, Ferdinand
  • NodeData: How to get connected GeListNode

    Cinema 4D SDK python r20
    3
    0 Votes
    3 Posts
    539 Views
    M
    Thought so. No, there's nothing missing in inherited methods. Thought, it'd be convenient. However, storing it to a member variable on init or forwarding does the trick.