Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Set Object Axis/Origin

    Scheduled Pinned Locked Moved PYTHON Development
    10 Posts 0 Posters 1.1k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Helper
      last edited by

      On 05/08/2017 at 13:31, xxxxxxxx wrote:

      Hi all

      I have objects (Meshes) that I import from OBJ-Files. The challenge is, that they are "somewhere", i.e. they're geometry is offset from the origin by some arbitrary value of x and z (that is done by the source generating the OBJ, I don't have control over this).

      I can get these values (there's probably a better way) :

        
      xmin = 100000  
      zmin = 100000  
                  
      for v in  obj.GetAllPoints() :  
         xmin = min(v.x, xmin)  
         zmin = min(v.z, zmin)  
                  
      obj.SetAbsPos(c4d.Vector(- xmin, 0, - zmin))  
      

      This puts the object at the center, however, it also moved the origin of the object way out into the goonies. I now want to reset the origin of the object to be at the absolute origin. How would I go about doing that as efficiently as possible?

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        On 05/08/2017 at 14:39, xxxxxxxx wrote:

        Hi;

        as I understand you, your object origin is initially okay, but the points are offset? In that case, you would need to correct the point positions relative to the object origin, not the object origin itself.

        Point positions are stored as offsets relative to the containing object. Here is an example of how to handle and change point positions in a point object:

          
        import c4d   
        from c4d import gui, Vector   
          
        def main() :   
            print "---------------------"   
            selectlist = doc.GetSelection()   
            for obj in selectlist:   
                print obj.GetName()   
                doc.StartUndo()   
                doc.AddUndo(c4d.UNDO_OBJECT, obj)   
                selected = obj.GetPointS()   
                maxelements = obj.GetPointCount()   
                counter = 0   
                average = Vector ()   
                for index, sel in enumerate (selected.GetAll(maxelements)) :   
                    if sel==1:   
                       average = average + obj.GetPoint(index)   
                       counter += 1   
                average = average / counter   
                for index, sel in enumerate (selected.GetAll(maxelements)) :   
                    if sel==1:   
                       obj.SetPoint(index, average)   
                obj.SetDirty(c4d.DIRTY_DATA)   
                doc.EndUndo()   
            c4d.EventAdd()   
          
        if __name__=='__main__':   
            main()   
        

        This code is repositioning all selected points in a (selected) point object to a common average (essentially collapsing a point set to one position). It shows how to set a point with SetPoint() but also how to handle a selection on point and object level, how to set the Dirty flag, and how to include Undo.

        In your case, you would not calculate an average but take the xmin, zmin values you already calculated in your code, and subtract that from each point position to affect the offset. The object itself would stay where it is, but all points would get moved.

        Alternatively, you could use this average to calculate the center of the object's point cloud, and use that to correct the offset. This would center the points to the object's own position; depending on the necessary type of correction.

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          On 06/08/2017 at 10:31, xxxxxxxx wrote:

          @Cairyn Thx! I kind of feared that that is the solution. It seems a bit inefficient to iterate through all points, but if that is the only way to do it, be it so 🙂

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            On 06/08/2017 at 12:01, xxxxxxxx wrote:

            Well, alternatively you could try to apply the frozen transformation in one step per object. This does not affect the coordinates of the object or the place where the axis is shown, but can revert the wrong point offsets.

            The frozen transformation is essentially an additional transformation matrix that is applied to the object ("Freeze Transformation" in the Coord tab of the polygon object). There are extra commands in Python to set that (and I am too lazy to look them up now).

            Personally, in this case I would rather correct the point coordinates though; it's just the cleaner solution and gives you better point values in the Structure Manager. Plus, the computer does all the menial hard work anyway, so why settle for second best.

            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              On 08/08/2017 at 04:09, xxxxxxxx wrote:

              I just found that modifying all points leads to a weird problem.

              Here's the code I use:

                
              ap = obj.GetAllPoints()  
                  
              for v in ap:  
                xmin = min(v.x, xmin)  
                zmin = min(v.z, zmin)  
                      
              mapoffset_x = - xmin  
              mapoffset_z = - zmin  
                
              #obj.SetAbsPos(c4d.Vector(mapoffset_x, 0, mapoffset_z))  
              for i,pt in enumerate(ap) :  
                obj.SetPoint(i, c4d.Vector(pt.x + mapoffset_x, pt.y, pt.z + mapoffset_z))  
              

              Now, the geometry behaves strangely in the viewport (when orbiting the camera it flickers in and out depending on the position of the camera) and it is still shown as being way out there (blue indicator arrow) despite being at the center...

              Here's what it looks like: http://35.io/media/c4d.mp4

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                On 08/08/2017 at 04:21, xxxxxxxx wrote:

                Did you set the Dirty flag and call EventAdd? Otherwise the internal bounding boxes may not get recalculated.

                1 Reply Last reply Reply Quote 0
                • H Offline
                  Helper
                  last edited by

                  On 08/08/2017 at 04:56, xxxxxxxx wrote:

                  Please, see the note on SetPoint(). You need to send a MSG_UPDATE after its use.

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    Helper
                    last edited by

                    On 08/08/2017 at 05:02, xxxxxxxx wrote:

                    I'm doing:

                      
                    obj.SetDirty(c4d.DIRTYFLAGS_MATRIX|c4d.DIRTYFLAGS_DATA|c4d.DIRTYFLAGS_SELECT|c4d.DIRTYFLAGS_CACHE)  
                    c4d.EventAdd()  
                    

                    Might have overdone the flags on SetDirty...

                    The tip about sending MSG_UPDATE was the clue. It works now! Thx!

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      Helper
                      last edited by

                      On 09/08/2017 at 03:39, xxxxxxxx wrote:

                      Hmm, didn't notice that, I need to update my samples. Maybe the code above works only because the averaging does not change the bounding box. Thanks for the hint.

                      1 Reply Last reply Reply Quote 0
                      • H Offline
                        Helper
                        last edited by

                        On 09/08/2017 at 03:44, xxxxxxxx wrote:

                        SetDirty is apparently not needed if you MSG_UPDATE. EventAdd is necessary though, or else the viewport will not update.

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post