Creating Selection Tags



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 14/01/2012 at 10:07, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   12 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hey guys.
    There's all kinds of of good stuff in the archives on getting points and polygons from selection tags. But not one of them shows how to create the selection tag itself.

    I'm trying to use AutoAlloc. And I'm getting all kinds of crashing problems.

        BaseDocument *doc = GetActiveDocument();  
      BaseObject *obj = doc->GetActiveObject();    //Start out using BaseObject to grab the polygon object  
      PolygonObject *pobj = ToPoly(obj);          //Cast the BaseObject type to a PolygonObject type and assign it to a variable "pobj"  
      
      AutoAlloc<SelectionTag> st(Tpolygonselection); //Create a selection tag  
      
      /// Up to this point. Everything seems to work properly ///  
      
      pobj->InsertTag(st,NULL); // <--OUCH!! crashes C4D!
    

    I also tried to use MakeTag() and that crashes too.
    I'm missing something really simple. But I can't see it.
    How do I insert the tag on the object properly?

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 14/01/2012 at 13:11, xxxxxxxx wrote:

    After some hair pulling. I managed to figure it out using MakeTag() :

        BaseDocument *doc = GetActiveDocument();  
      BaseObject *obj = doc->GetActiveObject();    //Start out using BaseObject to grab the polygon object  
      if(!obj) return FALSE;  
      PolygonObject *pobj = ToPoly(obj);          //Cast the BaseObject type to a PolygonObject type and assign it to a variable "pobj"  
      if(!pobj) return FALSE;  
      
      LONG count = pobj->GetPolygonCount();       //Now you can use that variable as a polygon object, and all of the polygon class functions  
      
      BaseSelect *sel = pobj->GetPolygonS();      //Store the selected polygons  
        
      BaseTag *polytag = pobj->MakeTag(Tpolygonselection, NULL); //Create a new polygon selection tag      
      BaseTag *newpolytag = pobj->GetFirstTag();                 //Find the new tag and give it a new variable  
      if(newpolytag->GetType() &Tpolygonselection)  
      {  
        BaseSelect *select= static_cast<SelectionTag*>(newpolytag)->GetBaseSelect(); //Convert the BaseTag to a BaseSelect tag so we can edit it's contents   
        sel->CopyTo(select);       //Now that we have a BaseSelect for the tag. We can dump the selected polygons into that tag  
      }  
      
      pobj->Message(MSG_UPDATE); //Update any changes made to the object
    

    I would still really like to know how to do this same thing using AutoAlloc<> though.
    I need to understand why it crashes on me when I use InsertTag().
    Can anyone tell me how to use it properly?

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 14/01/2012 at 23:06, xxxxxxxx wrote:

    When the tag is inserted, ownership of the tag is passed to the object. AutoAlloc is attempting to free the tag when exiting the scope.

    Instead, you can use:

      
    SelectionTag* st = SelectionTag::Alloc(Tpolygonselection);   
    


  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/01/2012 at 08:04, xxxxxxxx wrote:

    Thanks for the help David.
    This is the second time I've run into this issue with AutoAlloc killing itself before I wanted it to.
    It seems to be very tricky to use properly in many cases. And there's not much documentation on it.

    I'd like to avoid using Alloc() as much as possible because of the manual freeing it requires me to do.
    But since AutoAlloc<> is so difficult to keep from killing itself prematurely. I might have to give up on it. And just handle all of the memory freeing myself.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/01/2012 at 09:31, xxxxxxxx wrote:

    You can use AutoAlloc in the class declaration, so it will be freed automatically only when the class terminates. So if you were writing a particle modifier with falloff, for example, you can do this:

      
    class MyModifier: public ObjectData   
    {   
         INSTANCEOF(MyModifier, ObjectData);   
    private:   
         AutoAlloc<C4D_Falloff>falloff;   
      
    public:   
    // all the public functions etc.   
    };   
    

    Of course then the item will be a class-level variable, which might or might not be an issue.

    Steve



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/01/2012 at 10:19, xxxxxxxx wrote:

    Thanks Steve.

    I think I've just got the wrong impression about AutoAlloc. And how/when to use it.
    The documentation is very limited about it. And leaves a lot of it's interpretation up to the developer.
    Which is a bad thing in my case. Because I'm still cutting my teeth, and I need to know EXACTLY how and why things work.
    When I'm forced to interpret things from the docs. That's where I make the most mistakes.

    Basically. I need to stop thinking of AutoAlloc<> as a shortcut to cheat memory handling for every situation. Because it's not really the best choice for every situation like I interpreted it from the docs.
    If I'm creating things with a command plugin for example. Then AutoAlloc<> won't work because it's tied to the life of my code...Not the life of the current document.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/01/2012 at 12:56, xxxxxxxx wrote:

    In this situation you don't use Free() because the object has ownership of the tag.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/01/2012 at 14:35, xxxxxxxx wrote:

    Ok. Thanks David.

    As a test I tried using AutoAlloc<> in a tag situation where it should always be running and live. And not delete the selection tag. But even in this situation where I use a button click in a message method. It kills the tag right after it creates it. And never gets created. While using Alloc() works just fine:

    Bool SimpleTag::Message(GeListNode *node, LONG type, void *data)  
    {  
      if (type == MSG_DESCRIPTION_CHECKDRAGANDDROP)  
      {  
        DescriptionCheckDragAndDrop *LNK = static_cast<DescriptionCheckDragAndDrop*>(data);  
        switch (LNK->id[0].id)   
        {  
        case MY_LINK:  
        case SPLINERAILOBJECT_SPLINE1:        
        GePrint(LongToString(LNK->result));  
      
        return TRUE;  
        }  
      }  
      
      BaseDocument *doc = GetActiveDocument();  
      BaseObject *obj = doc->GetActiveObject();    //Start out using BaseObject to grab the polygon object  
      if(!obj) return FALSE;  
      PolygonObject *pobj = ToPoly(obj);          //Cast the BaseObject type to a PolygonObject type and assign it to a variable "pobj"  
      if(!pobj) return FALSE;  
      
      LONG count = pobj->GetPolygonCount();       //Now you can use that variable as a polygon object, and all of the polygon class functions  
      
      BaseSelect *sel = pobj->GetPolygonS();      //Store the selected polygons  
      
      //AutoAlloc<SelectionTag> st(Tpolygonselection);            //<---Does not work...It kills the tag  
      SelectionTag* st = SelectionTag::Alloc(Tpolygonselection); //Works fine  
      
      switch (type)  
        {          
         case MSG_DESCRIPTION_COMMAND: // MSG_DESCRIPTION_COMMAND is send when button is clicked  
          {              
              DescriptionCommand *dc = (DescriptionCommand* )data; // data contains the description ID of the button             
              LONG button = dc->id[0].id; // get the ID of the button  
                            
              switch (button) // check for different button IDs  
              {  
                  case BUTTON1:   
                      pobj->InsertTag(st,NULL);  
                          pobj->GetFirstTag();  //Find the new tag and give it a new variable  
                          if(pobj->GetFirstTag()->GetType() &Tpolygonselection)  
                           {  
                            BaseSelect *select= static_cast<SelectionTag*>(pobj->GetFirstTag())->GetBaseSelect(); //Convert the BaseTag to a BaseSelect tag so we can edit it's contents   
                            sel->CopyTo(select);       //Now that we have a BaseSelect for the tag. We can dump the selected polygons into that tag  
                           }  
                      break;  
      
                  case BUTTON2:  
                      GePrint("Button2 was pushed");  
                      break;  
              }  
          }  
        }  
      
      
      return TRUE;  
    }
    

    I'm sure there's a good reason why AutoAlloc<> is not working in this example. But it just illustrates how confusing it is to use it.
    You have to use in a very specific way. And if you don't. It's a monster that eats the villagers.😂

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/01/2012 at 16:14, xxxxxxxx wrote:

    Yes, that will never work. Think about what happens. Message() is called and you create a SelectionTag using AutoAlloc. The critical thing is this: once the object goes out of scope, it will automatically be freed. And it will go out of scope the moment Message() comes to an end.

    It's really that simple. When using AutoAlloc just think about where you call it and when that function will terminate. If it terminates before you're ready to lose the object that was created, don't use AutoAlloc in that function. (Or do use it, but then use Release() to get a pointer to the object, and store that.)

    In this case you can create a class-level variable and free it up when the tag terminates (e.g. is deleted by the user). You can either use AutoAlloc for that as I showed earlier or use Alloc then free it yourself in the tag's Free() function (note: that's a virtual function derived from NodeData, not the same as the Free() you would call to release an object you create).

    Edit: in fact, thinking about it a little more, once you insert the tag into the document, it's my understanding that Cinema takes over the inserted object and will free it when the tag or object it's attached to is deleted. But I could be wrong about that.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/01/2012 at 16:53, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Edit: in fact, thinking about it a little more, once you insert the tag into the document, it's my understanding that Cinema takes over the inserted object and will free it when the tag or object it's attached to is deleted. But I could be wrong about that.

    This is what I was saying above. When I use AutoAlloc or Alloc() with Free(), the tag disappears immediately after creation.

    Using Alloc() only, the tag is retained with the debug console reporting no memory leaks.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/01/2012 at 17:20, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Message() is called and you create a SelectionTag using AutoAlloc. The critical thing is this: once the object goes out of scope, it will automatically be freed. And it will go out of scope the moment Message() comes to an end.

    That's what I thought.
    But because Message() executes continuously while C4D is running. I wasn't really 100% sure about how&when Message() went out of scope.
    Your explanation helped to clear that up for me.
    The class member variable work flow is something I'll try out in the future.

    I think I have a better understanding of it now.
    I'm sure I haven't conquered it completely, and I will probably wrestle with it again. But the help you guys have posted has helped clear it up a little bit. And given me some useful notes to use the next time I try to use AutoAlloc<> on something.

    Thanks guys.🍺

    -ScottA


Log in to reply