Set Object Axis/Origin



  • 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?



  • 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.



  • 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 :)



  • 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.



  • 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



  • 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.



  • 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.



  • 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!



  • 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.



  • 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.


Log in to reply