Navigation

    • Register
    • Login
    • Search
    • Categories
    1. Home
    2. ferdinand
    3. Posts
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    Posts made by ferdinand

    • RE: BaseContainer Sort broken?

      Hi @mp5gosu,

      I can ask, but I doubt that this will added, because it is ultimately something that can be "fixed" relatively easily from the user side (see end of posting for example). The only meaningful explanation I can give is that BaseContainer.Sort was implemented for a very specific reason. BaseContainer is not really meant to be a replacement for a sortable collection data type.

      Cheers,
      Ferdinand

      """A little workaround for the somewhat odd BaseContainer sorting behavior.
      """
      
      import c4d
      
      def cleanSort(bc):
          """A little helper for BaseContainer.Sort().
          """
          # Sort the container.
          bc.Sort()
          # Get out when the IDs 0 and 1 are not of type string.
          if (bc.GetType(0) != c4d.DA_STRING or
              bc.GetType(1) != c4d.DA_STRING):
              return bc
          # Save the value of ID 1
          valIdOne = bc[1]
          # Remove the ID 1 and reinsert it in the "right" place.
          if bc.GetIndexId(0) == 1 and bc.RemoveIndex(0):
              bc.InsDataAfter(1, valIdOne, bc.GetDataPointer(0))
          return bc
      
      def main():
          """
          """
          data = {3: "d", 1: "b", 2: "c", 0:"a"}
          bc = c4d.BaseContainer()
          for eid, value in data.items():
              bc.SetString(eid, value)
      
          print ("Before:")
          for eid, value in bc:
              print(f"id: {eid}, value:{value}")
          print ("")
      
          bc = cleanSort(bc)
      
          print ("After:")
          for eid, value in bc:
              print(f"id: {eid}, value:{value}")
      
      
      if __name__=='__main__':
          main()
      
      posted in Cinema 4D Development
      ferdinand
    • RE: BaseContainer Sort broken?

      Hi @mp5gosu,

      thank you for reaching out to us and thank you for pointing out this behaviour. However, this is not a bug, but an intentional feature which is linked to the fact the sub-menu titles will be stored under the ID 1 in a BaseContainer. Because of that the method will not be fixed and it is also very unlikely that we will update the documentation, as explaining the reason for this behaviour would require revealing more of the non-public API than we are currently comfortable with.

      However, since this is an intentional behaviour, you can rely on the fact that this will only happen with the ID 1. I.e., when you place your BaseContainer IDs in the range [1, +MAX_INT32], the sort method should work like intended.

      Thank you for your understanding,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: SceneHook and object caches

      Hi @C4DS,

      sorry, I was probably a bit cryptic when I talked about a "shift in design". The reason why I was so cryptic is that such design decisions formally fall out of the scope of support (see Forum Guidelines: Scope of Support). It is not because we are lazy, but such decisions often come with a certain vagueness and uncertainty which makes is either very hard or impossible to give reliable answers. So please take my following ideas with a grain of salt.

      I would look at it from the standpoint of reducing complexity. The major problems seems to be the ambiguity of caches. One way to circumvent this could be moving from a SceneHook to a ObjectData plugin. The idea would be to write a thin wrapper around Cinema's SDS object. In GVO you could just collapse all the input objects into a single polygon object and then just return that collapsed object as a child of a SDS-object. In Draw you could then just evaluate this very simple cache of your object (the input would already be taken care of due to the collapsing), i.e. you could directly draw your vertex-to-vertex relations. This would of course come with a considerable amount of overhead due to the collapsing.

      Another approach could be to try to introduce tags as markers which will allow the user to guide your plugin what is considered to be the original. I cannot say you anymore than this without doing it myself (which falls out of the scope of support). The small insight would be here that for humans that decision what is the "original" might often be trivial.

      For the SDS/subdivision vertex-to-vertex relations: My first instinct was that Cinema's subdivisions do not change anything about the index order of the source vertices (i.e., the vertices object that is going to be subdivided) due to the unnecessary overhead that would be introduced by inserting the new topological connected points in the index neighborhood of an "old" vertex. A quick test seems to confirm that, both for the SDS object as well as the "subdivide" command. If you want more clarity on this subject, I would have to ask you to open a new topic on that, so that we can keep topics in a single subject order.

      7c914f63-2a58-4ef9-bed3-9811749d5d50-image.png
      The selected vertices are all of index 8, the object in the middle was the source for the objects on the left and right.

      Thank you for your understanding and cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: CCurve.FindPrevUnmuted & CCurve.FindNextUnmuted

      Hi @blastframe,

      thank you for reaching out to us. And again you are right, the documentation is here unfortunately also not the greatest. As a somewhat immediate fix, you could do this:

      prevKey = curveY.FindPrevUnmuted(keyDict["nidx"] - 1)
      nextKey = curveY.FindNextUnmuted(keyDict["nidx"] + 1)
      

      I.e., you cannot include in the key index of the key you want to search from, because the logic here will be otherwise: "Well, the next/prev unmuted key to the passed key is the key itself, since it is a unmuted one). Which is being reflected in the argument description:

      index (int) – The key index to start the search from: 0 <= idx < GetKeyCount()

      but does not mesh very well with the method name. We are also going to fix also the documentation on this one (here including C++). And just for clarity, you can always iterate over the keys of a CCurve, i.e., just access them by their index:

      for eid in range(curveY.GetKeyCount()):
          key = curveY.GetKey(eid)
          print(eid, key)
      

      I am sorry, I understand your CCurve documentation experience was probably not the greatest, but we try to improve.

      Thank you for your understanding,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: Description & Example in Documentation for CCurve.AddKey

      Hi @blastframe,

      thank you for reaching out to us and for reporting these errors in the documentation. We will fix both the erroneously attributed short description of AddKey as well as the code example in an upcoming update of the C4D SDK Python docs.

      Cheers and happy coding,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: Creating a Keyframe similar to Ctrl-Clicking the Curve

      Hi @blastframe,

      thank you for reaching out to us. One built in solution you could use is CCurve.AddKeyAdaptTangent() instead of CCurve.AddKey(). It will allow you to insert a smoothly interpolated key between two other keys and the result will look something like the attached image. I also attached a modified github ctrack_create_keys_r13.py example at the end. You only have to read the snip parts, everything else is unchanged.

      2798b905-ec91-4bc1-8363-ad0d65577044-image.png

      I hope this helps, if not, I would have to ask you to restate your goals.

      Cheers,
      Ferdinand

      """
      Copyright: MAXON Computer GmbH
      Author: Manuel MAGALHAES
      Description:
          - Creates position Y tracks.
          - Adds two keyframes.
          - Sets their value and interpolation.
      Class/method highlighted:
          - CKey.SetInterpolation()
          - CKey.SetKeyDefault()
      Compatible:
          - Win / Mac
          - R13, R14 R15, R16, R17, R18, R19, R20, R21, S22, R23
      """
      
      import c4d
      
      
      def CreateKey(curve, time, value, interpolation):
          """
          Creates a Key on the given curve at the given time with a given value and with the given interpolation.
          :param curve: The Curve where to add the keyframe.
          :type curve: c4d.CCurve
          :param time: The time of the keyframe.
          :type time: c4d.BaseTime
          :param value: The value of the keyframe.
          :type value: float
          :param interpolation: The interpolation of the key along the curve.
          :type interpolation: c4d.CINTERPOLATION_XXX
          :return: They key and the index of the key in the CCurve.
          :rtype: tuple(c4d.Ckey, int)
          :raise MemoryError: If for some reason, it was not possible to create the key.
          """
          # Adds the key
          keyDict = curve.AddKey(time)
      
          # Checks if the key have been added
          if keyDict is None:
              raise MemoryError("Failed to create a key")
      
          # Retrieves the inserted key
          key = keyDict["key"]
          keyIndex = keyDict["nidx"]
      
          # Sets the value of the key
          key.SetValue(curve, value)
      
          # Mandatory: Fill the key with default settings
          curve.SetKeyDefault(doc, keyIndex)
      
          # Changes it's interpolation
          key.SetInterpolation(curve, interpolation)
      
          return key, keyIndex
      
      
      def main():
          # Creates the object in memory
          obj = c4d.BaseObject(c4d.Ocube)
      
          # Creates the track in memory. Defined by it's DescID
          trackY = c4d.CTrack(obj, c4d.DescID(c4d.DescLevel(c4d.ID_BASEOBJECT_POSITION, c4d.DTYPE_VECTOR, 0),
                                              c4d.DescLevel(c4d.VECTOR_Y, c4d.DTYPE_REAL, 0)))
      
          # Gets curves for the track
          curveY = trackY.GetCurve()
      
          # Creates a key in the Y curve with value 0 at 0 frame with a spline interpolation
          keyA, keyAIndex = CreateKey(curveY, c4d.BaseTime(0), value=0, interpolation=c4d.CINTERPOLATION_SPLINE)
      
          # Retrieves time at frame 10
          keyBTime = c4d.BaseTime(10, doc.GetFps())
      
          # Creates another key in the Y curve with value 100 at 10 frame with a spline interpolation
          keyB, keyBIndex = CreateKey(curveY, keyBTime, value=100, interpolation=c4d.CINTERPOLATION_SPLINE)
          
          # --- snip ---
          
          # Add key in between the keys A and B.
          bt = c4d.BaseTime(5, doc.GetFps())
          curveY.AddKeyAdaptTangent(bt, True, True)
          
          # --- snip ---
      
          # Inserts the track containing the Y curve to the object
          obj.InsertTrackSorted(trackY)
      
          # Inserts the object in document
          doc.InsertObject(obj)
      
          # Pushes an update event to Cinema 4D
          c4d.EventAdd()
      
      
      # Execute main()
      if __name__ == '__main__':
          main()
      posted in Cinema 4D Development
      ferdinand
    • RE: Turn Bezier spline to linear spline

      Hi @Yaroslav,

      yes, you are right, LineObject are not meant to be presented to the user directly, but are the underlying discrete geometry of a spline. In case you do not mind a little overhead, you can also use SendModelingCommand, specifically with MCOMMAND_CURRENTSTATETOOBJECT (link to example), to get "a linear version of the spline". The advantage here is that you do not have to worry so much about the details, but at the cost of a little bit of overhead.

      Cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: Turn Bezier spline to linear spline

      Hi @Yaroslav,

      thank you for reaching out to us and thank you @mp5gosu for providing an answer.

      However, and I might be mistaken here, I think this is not what @Yaroslav was asking for; feel free to correct me when I am wrong. Cinema's splines are all parametric, even the editable ones, so changing the interpolation type from SPLINEOBJECT_TYPE_BEZIER to SPLINEOBJECT_TYPE_LINEAR will give you something linear, but also a vastly different curve geometry (depending on the input).

      To resample a spline in Python, you can use c4d.utils.SplineHelp, specifically SplineHelp.GetPosition(). Or you can use SplineHelp.GetLineObject() to get the underlying LineObject of a spline. In C++ you also have SplineObject::GetLineObject.

      In case you are actually interested in changing the interpolation type of a spline object (and not resample it), then @mp5gosu did provide the correct answer for you.

      Please also note that we require postings to be tagged with essential meta information regarding the OS, Cinema 4D version and programming environment for the question. You can read more about the tagging feature here.

      Cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: SceneHook and object caches

      Hi @C4DS,

      so we talked a bit about it and there is unfortunately no way to do this with built in functionalities of the SDK. I do not fully understand your solution in all detail, but you seem to have to come to the right conclusion that this will have its limits for array-like generators where the caches can get very complex. This ambiguity of what is then "original" is ultimately also why Cinema does/can not offer this functionality.

      I cannot tell you anymore than that and depending on what you are trying to do, a general shift of design might be necessary when you run into major problems.

      Cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: ShowPopupDialog Freezes Cinema R21

      Hi @AndreAnjos,

      it is great that you found the issue. A few points:

      1. Just for clarity: The world container is not document related, but rather the global container used by a Cinema 4D installation. Documents have their own container(s) to store data in.
      2. Before trying to investigate if this is indeed a somehow corrupted container, I would first try if this is not an issue of ownership (probably should have mentioned that first). There is no guarantee that this will work, but it might be worth a shot. So instead of retrieving the world container instance via c4d.GetWorldContainerInstance() get a copy of it via c4d.GetWorldContainer(). When your code then does run, you can try to write back your modifications of the world container via c4d.SetWorldContainer().
      3. If all this fails, I would recommend reinstalling Cinema 4D, because a corrupted world container is not really something you can fix or really want.
      4. When you had to take the route of point 3., I would also recommend using Get/SetWorldContainer(), to avoid any further problems.
      5. Regarding a file based solution: This is of course possible, but comes with on plethora of problems and drawbacks (R/W access and speed of operations), so I would try to avoid it as long as possible.

      Cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: SceneHook and object caches

      Hi @C4DS,

      well, in scenario two the sds IS your cache parent, so this is kind of to be expected. I understand your line of thinking, that the Cube is somehow the meat of this of this generator/input object pair, but in the end it is just another scenario than a deformer deformed object pair. You said it yourself, deformation is not the right term for SDS.

      Anyways, we will talk about it on Monday and someone else or maybe I have a light-bulb moment then. But for now I do not see a built in functionality to do that (you can of course cobble your own logic together by fetching the control-objects, but this probably going to be a bit messy).

      Have a nice weekend and cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: ShowPopupDialog Freezes Cinema R21

      Hi @AndreAnjos,

      well are you sure that ShowPopupDialog() is actually the culprit? Because it would be my last guess at the moment and in the end just replacing one buggy part with another feature is not really our understanding of good support here ;) Since we cannot reproduce your problem, you have to do the debugging unfortunately yourself. What I would propose is:

      1. Copy your plugin code into an editor which does not have "fancy features", i.e., something like windows notepad, and save it with that editor as a txt file and rename it back to my_plugin.pyp again. So to make sure that you do not have any weird unicode-mishaps in your file.
      2. Reinstall Cinema 4D from scratch. I know this one sucks, but in the end you have to do it anyways, when you have exhausted all other options, so you might also just get it out of the way in the beginning.
      3. Sprinkle in some print statements to see which parts of your code are reached before Cinema does freeze (although you should not put to much faith into this, due to the way Python does unravel its console output, but trying does not hurt).
      4. Remove the GetTimer() implementation form your AOMessage and remove the body of CoreMessage() except for the return statement.
      5. Reintroduce in blocks your code, you could for example first add everything up to active_mat= ... and then up to result =.
      6. With the results of 4. try to pinpoint the call/statement which does cause Cinema 4D to freeze.

      For each step you have to check if it did change anything about the freezing.

      Your code in general is rather inconspicuous, so at least I cannot point anything out that would be the obvious culprit. The fact that you start and close an undo-block without using it is a bit weird, but should not freeze Cinema 4D. One rather far-fetched reason could be that you somehow corrupted the world-container of your installation permanently and now accessing it will freeze Cinema 4D. But then this should normally happen all the time, because Cinema 4D does access it all the time (and also in your SceneLoaderData plugin, since it does access the same part of the world container.

      So at least from my side this is all mostly speculation. The unfortunate truth of debugging is that you are always samerter after figuring it out ;)

      Cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: ShowPopupDialog Freezes Cinema R21

      Hi @AndreAnjos, hi @m_adam,

      @AndreAnjos said in ShowPopupDialog Freezes Cinema R21:

      @m_adam
      Morning Maxime,

      Yes, it freezes with the code I provided.
      I've also tried the way that you mention above by running the c4d.SpecialEventAdd(1055684) and the same happens, as per my video below.

      https://drive.google.com/file/d/1v4A9xXKb79Z1TlMnlSdZ-tk9WJFldsv7/view?usp=sharing

      Let me know if you need any other information.

      Thank you!

      Andre

      I just tried it too on R21.207 and it does not freeze for me either (I just added the message id as a print out, not knowing there was already that "finished" statement).

      93d7cbc5-136f-4a1f-bdf5-cfae9d61b757-image.png

      One thing you could do is to try to remove other plugins or scripts that are loaded by your Cinema 4D R21 installation, to make sure sure none of them is interfering with the plugin. When you have done this, you could also test, if opening a popup dialog in general, so something like this in the script manager,

      import c4d
      
      def main():
          """
          """
          MENU_ADD_ASSETS = c4d.FIRST_POPUP_ID
          MENU_ADD_MATERIALS = c4d.FIRST_POPUP_ID + 1
          MENU_REPLACE_ASSETS = c4d.FIRST_POPUP_ID + 2
          MENU_REPLACE_MATERIALS = c4d.FIRST_POPUP_ID + 3
          MENU_REPLACE_TAG = c4d.FIRST_POPUP_ID + 4
      
          menu = c4d.BaseContainer()
          menu.InsData(MENU_REPLACE_ASSETS, 'Replace Asset(s)')
          menu.InsData(MENU_REPLACE_MATERIALS, 'Replace Material(s)')
          menu.InsData(MENU_REPLACE_TAG, 'Replace Texture Tag(s)')
          result = c4d.gui.ShowPopupDialog(cd=None, bc=menu, x=c4d.MOUSEPOS, y=c4d.MOUSEPOS)
      
      if __name__ == '__main__':
          main()
      

      will freeze your installation.

      Cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: SceneHook and object caches

      Hi @C4DS,

      thank you for reaching out to us. I had some trouble understanding the finer details of your question. Your DoRecursion method looks correct to me. One thing noteworthy pointing out for a SceneHook context is that one does not have the guarantee that the caches always have been built or are up-to-date, depending on where and when the SceneHook does intercept.

      What I do not quite understand is why you do bundle up deformer and SDS ("... including the original input object for the deformation/SDS ...", I assume SDS does stand for Subdivision Surfaces), since an SDS-object does not write its output to the deformed cache but the cache. Generally speaking, caches can be quite complex in Cinema, since you often use generators. And in this case the deformed caches can be buried deep within the cache of the generator. You can use either the C++ SDK examples ActiveObject plugin to get a better sense of the full complexity of Cinema's scene graph:

      1.png

      or use a little script I did post here, which only does focus on printing the expanded BaseObject scene graph tree with caches to the console, which can be a bit easier to read on large caches.

      This seems to work, except that I ignore any polygon object which is not an input of a deform/SDS. So, how to distinguish between a polygon object which is an input and one which isn't an input for deform/SDS?

      Well, you use BIT_CONTROLOBJECT like you do in your code. It will be set by ObjectData nodes (registered with the correct flag) on the object they govern or are governed by. Generators will mark their input objects and themselves in this fashion and deformers will not mark themselves but the objects they deform. So for this scenario here:

      2.png

      The expanded tree of the top null would look like this (the output is from my script):

      Null/Null (BIT_CONTROLOBJECT: False)
      	Null/Null returns 'None' for GetCache.
      	Null/Null returns 'None' for GetDeformCache.
      	children of Null/Null:
      		Polygon/Cube (BIT_CONTROLOBJECT: True)
      			Polygon/Cube returns 'None' for GetCache.
      			Polygon/Cube returns for GetDeformCache:
                                      # This is Polygon/Cube deformed by the deformer Bend/Bend.
      				Polygon/Cube (BIT_CONTROLOBJECT: False)
      					Polygon/Cube returns 'None' for GetCache.
      					Polygon/Cube returns 'None' for GetDeformCache.
      					Polygon/Cube has no children.
      			Polygon/Cube has no children.
      		Bend/Bend (BIT_CONTROLOBJECT: False)
      			Bend/Bend returns 'None' for GetCache.
      			Bend/Bend returns 'None' for GetDeformCache.
      			Bend/Bend has no children.
      

      This will get even more complex once you do include generators.

      How to find back the relation "original object" <-> "deformed object".

      It depends on what you would consider to be a "original object". Raw polygon objects, i.e. nodes of type Opolygon, will always directly hold their deformed cache, even if the deformer is not a direct child of them (see previous example) or when you have multiple consecutive levels of deformation. For generators this is not so easy, and I would say it is a bit a matter of opinion there what you would consider to be the original and what not. The important point here is that deformed caches then will be buried within the cache of the generator, since only editable point objects are processed for deformers (i.e., something that is hidden in the cache for a generator).

      As already stated, I am not quite sure what you are asking exactly for. So I hope this helps a bit. If I missed your point, I would kindly ask you to explain again what your goals are.

      Cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: How to get all elements from BaseSelect

      Hi @orestiskon,

      thank you for reaching out to us. The problem with your code is that you pass the number of selected elements as the second argument to BaseSelect.GetRange(). But the method actually does expect the maximum index there, i.e., the total number of points for a point selection. While this method via .GetRange() is a bit more performant, in Python you can also use .GetAll() and list comprehensions. For details see the attached example.

      Cheers,
      Ferdinand

      """A simple example for how to iterate over point selections.
      
      As discussed in:
          https://plugincafe.maxon.net/topic/13115
      """
      
      import c4d
      
      
      def main():
          """Iterates over the selected objects and accesses their point selection.
          """
          # Iterate over the selected objects.
          for obj in doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE):
              # Step over non-point objects.
              if not isinstance(obj, c4d.PointObject):
                  continue
      
              # All the points of the point object.
              points = obj.GetAllPoints()
              # And their count.
              pointCount = obj.GetPointCount()
              # The point selection.
              selection = obj.GetPointS()
      
              # The selection state of all elements in the BaseSelect. This is
              # a list of booleans, e.g., [True, False, False, False] for a polygon
              # object with just one quad and the first point in it being
              # selected.
              state = selection.GetAll(pointCount)
              # We have to manually convert this to indices.
              indices = [eid for eid, value in enumerate(state) if value]
              # I.e., you can get all selected indices like this in one go:
              # [eid for eid, val in enumerate(selection.GetAll(pointCount)) if val]
      
              # Print some stuff out.
              print("Object:", obj.GetName())
              print("Indices of selected points:", indices)
              print("The corresponding points:", [points[i] for i in indices])
              # The number of selected elements in the selection.
              print ("selection.GetCount():", selection.GetCount())
              # The segments in the selection, this has nothing to do with the
              # topology, but is rather the number of consecutive selection index
              # "strips". E.g.: [True, True, False, True, True] would be two
              # segments.
              print ("selection.GetSegments():", selection.GetSegments())
              # You can also access the selected elements like you tried to.
              for segment in range(selection.GetSegments()):
                  # But you have to pass in here the point count, i.e., the number
                  # of total total possible indices, not the number of selected
                  # elements.
                  print(selection.GetRange(segment, pointCount))
              print("-"*79)
      
      
      if __name__ == '__main__':
          main()
      
      posted in Cinema 4D Development
      ferdinand
    • RE: A GetClone problem about takes

      Hi @delizade,

      thank you for reaching out to us. There are two problems with your code:

      1. You are using C4DAtom.GetClone() and GeListNode.InsertUnder() to add and clone a take. You should instead use TakeData.AddTake() which also provides a cloneFrom argument (Link for AddTake).
      2. You are cloning and inserting the main take, which leads in Python to hiccups. Because even when you do it correctly, like discussed in this thread via AddTake, it will insert a second "main take" into a document. I.e., one which has no "inherit from parent" and "default cemara/rendersettings" icons.

      According to one our devs, No. 2 seems to be a Python bug and not a limitation, we will investigate that. For now you would have to clone the two child takes under the main take manually in Python (and add a parent take beforehand if you want this structure). Because otherwise you will end up with two "root/main" takes in your document, confusing Cinema 4D ;)

      Cheers,
      Ferdinand

      posted in General Programming & Plugin Discussions
      ferdinand
    • RE: Python: "Frame Selected" Within a Thread

      Hi @flewis,

      sorry, there has been some mix-up with access rights, you should be now able to access the page. About your fix: It does not really matter if you do it manually or not. While you can decouple the modification of the node attributes - which is allowed from within a thread - from the redraw event, to carry out that newly computed camera transform, you still will have to invoke a redraw, which you cannot do from within your threaded environment. When you invoke such redraw event, the first thing the internal code does, is to check if its running on the main thread and if not, it just gets out. So there is not much won by doing it manually, at least for what from my understanding is the premise of your problem: To constantly frame the viewport to the object that is currently processed by your async code.

      Cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: Python: "Frame Selected" Within a Thread

      Hi @flewis,

      welcome to the forum and the Cinema 4D development community. Thank you for reaching out to us. The reason why you cannot frame a camera form within your thread is that you are there ultimately caught in its thread environment and these come with certain limitations; specifically to carry out anything GUI related and adding events, which you will need when trying to frame an object.

      The solution to your problem would be to decouple your asynchronous from the interface layer, i.e., move the framing of objects into the main thread where you can do this. However, depending on the design of your code this might result in you having to wait so often for the main thread within your custom thread, that it might be more reasonable to:

      1. just either implement everything in the main thread or
      2. alternatively scrap the "constant live updating"-feature of your code in favour of running it asynchronously to the main thread (which has it limitations in Python anyways).

      An alternative could be to try to use pipes or semaphores, i.e., something that is being shared between threads to convey information, but that can be tricky to be done from scratch and the ones provided by Python and intended for its asynchronous features probably won't work with Cinema 4D's threads (have not tried yet, I might be wrong). You might also be able to just get away with a carefully used BaseContainer as a signal object, but this is pure speculation on my side.

      Please also note, that we require users on this forum to tag their postings with support relevant tags like the version of Cinema, the used language and more. The feature is explained in the Forum Guildines. I have done some of it for you here, but you still need to add your Cinema version and OS.

      Cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: PYTHON - FIND ANY ID PORT

      Hi @Hugo-BATTISTELLA,

      regarding your screenshot,

      32e2926e-d518-4b9f-ab43-297b8b4e55ff-image.png

      "it does not work" is usually not a very good starting point to pin point for us what is going wrong, and so I also do struggle here a bit with what you do mean by that. Because when I run/inspect that passage on R21.207, it works as I would expect it to work. So I would have to ask you to please clarify what you do mean by "not working".

          # Addding a Motion Graphics Data node.
          mo_donnee = master.CreateNode(master.GetRoot(),1019010,None,250,100)
          mo_donnee_out = mo_donnee.GetOutPorts()
          mo_donnee_out = mo_donnee_out[0] if mo_donnee_out else None
          # The name of the first out port is: Count
          print (mo_donnee_out.GetName(mo_donnee))
      

      Will print:

      Count
      

      Regarding the addition of ports, I see three .AddPort calls in your code and the resulting nodes will contain these ports in R21.207 as shown in your screenshot in the previous posting. So I am also confused about what you mean by "I still can't create ports on nodes" and would have to ask you to also clarify this. Our forum guide has also section on how to ask "good" questions, the "Structure of a Question: Detailed Description" section might be useful for you. You should line out what you do expect to happen and what happens instead.

      So I cannot really say anything helpful for now, sorry,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand
    • RE: Request: Combobox Icons

      @blastframe said in Request: Combobox Icons:

      @zipit "it would be impossible for a developer to know otherwise from just the documentation."

      Hi @blastframe,

      I was just a bit cheeky ;) The C++ GeDialog Manual shows how to embed an icon via its address (which works similarly), but is not a replacement for the Python docs and explaining it properly in one place. So no worries, I agree with you that this should be improved upon.

      Cheers,
      Ferdinand

      posted in Cinema 4D Development
      ferdinand