Axis Center Tool - python

On 13/11/2017 at 18:14, xxxxxxxx wrote:

Hello,

I was just wondering if someone can explain, how the axis center tool (ACT) functions, its such a useful tool and I would really like to use it in an automated manner on multiple objects. Is it originally a python script?

e.g. I am especially interested in centering and aligning the object axis to a selected edge.

Thanks!

On 14/11/2017 at 08:30, xxxxxxxx wrote:

Hi NNenov, thanks for writing us.

Actually the Axis Center Tool, does nothing fancy but simply compensate the space position and orientation of the points used in the mesh by a certain amount which is then back-compensated using a transformation matrix which places the mesh in the position it was supposed to be.

I've prepared below a basic script which make this "wizardry" for selected points or selected edges. Basically from the selection I retrieve the new axis position (I basically compute the centroid starting from all the selected entities), then change the points position by this amount and, in the end, move the object back to the right position to compensate the displace I've forced on the vertexes.

  
import c4d  
  
def GetSelectedEdgesList(op) :  
  # check passed parameter  
  if op is None:  
      return None  
    
  # retrieve the polygons  
  polys = op.GetAllPolygons()  
  if polys is None:  
      return None  
    
  # evaluate the total number of polygons  
  polysCnt = len(polys)  
        
  # get the BaseSelect object responsible for  
  # storing the information on selected edges  
  edgeS = op.GetEdgeS()  
  if edgeS is None:  
      return None  
  
  # check the at least one edge is selected  
  if edgeS.GetCount() == 0:  
      return None  
    
  # return the list representing the selection status of an edge  
  return edgeS.GetAll(4 * polysCnt)  
  
def GetSelectedPointsList(op) :  
  # check passed parameter  
  if op is None:  
      return None  
    
  # retrieve the points   
  points = op.GetAllPoints()  
  if points is None:  
      return None  
  
  # evaluate the total number of points  
  pointsCnt = len(points)  
        
  # get the BaseSelect object responsible for  
  # storing the information on selected points  
  pointS = op.GetPointS()  
  if pointS is None:  
      return None  
    
  # check that at least one point is selected  
  if pointS.GetCount() == 0:  
      return None  
    
  # return the list representing the selection status of a point  
  return pointS.GetAll(pointsCnt)  
  
def CalcBaryFromSelectedEdges(selEdges, polys, points) :  
    
  # check the passed parameters  
  if selEdges is None or polys is None or points is None:  
      return None  
    
  # initialize samples count to compute the final avarage value and the centroid  
  i = 0  
  bary = c4d.Vector(0)  
    
  for index, poly in enumerate(polys) :  
      for j in range(0,4) :  
          # check the selected status of the edge  
          if selEdges[index*4+j] == 0: continue  
          # and in case sum the points representing the edge extremes   
          # to the variable used to store the centroid value  
          bary += points[poly.EdgePoints(j)[0]]  
          bary += points[poly.EdgePoints(j)[1]]  
          # increase the sample counter  
          i += 2       
            
  # compute the avarage values assuming that each sample has the same weight  
  bary = bary / i  
    
  return bary  
  
def CalcBaryFromSelectedPoints(selPoints, points) :  
  # check the passed parameters  
  if selPoints is None or points is None:  
      return c4d.Vector(0)  
    
  # initialize samples count to compute the final avarage value and the centroid  
  i = 0  
  bary = c4d.Vector(0)  
        
  # loop through all the points  
  for index, selected in enumerate(selPoints) :  
      # check the selected status of the point  
      if not selected: continue  
      # and in case sum it to the variable used to store the centroid value  
      bary += points[index]  
      # increase the sample counter  
      i += 1  
    
  # compute the avarage values assuming that each sample has the same weight      
  bary = bary / i  
    
  return bary  
  
def main() :  
  if op is None:  
      return  
    
  # retrieve points, polys and the current transformation matrix  
  points = op.GetAllPoints()      
  polys = op.GetAllPolygons()  
  currentMg = op.GetMg()  
  
  # retrieve the list representing the points selection status   
  selPoints = GetSelectedPointsList(op)  
    
  # retrieve the list representing the edges selection status  
  selEdges = GetSelectedEdgesList(op)  
    
  #init the centroid  
  bary = c4d.Vector(0)  
    
  # if points are selected use them to compute the new axis-position  
  if selPoints is not None:  
      bary = CalcBaryFromSelectedPoints(selPoints, points)  
  elif selEdges is not None:  
      bary = CalcBaryFromSelectedEdges(selEdges, polys, points)      
    
  # move the points by the amount represented by the new axis center  
  for index, point in enumerate(points) :  
      point -= bary  
      op.SetPoint(index, point)  
    
  # notify about the points repositioning  
  op.Message(c4d.MSG_UPDATE)  
        
  # adjust the matrix offset component accordingly  
  currentMg.off += bary  
    
  # reposition the object in the space  
  op.SetMg(currentMg)  
    
  c4d.EventAdd()  
    
    
if __name__=='__main__':  
  main()  

The code is far from being perfect (for example it doesn't consider re-orienting the axis) but extending the code to make it happen shouldn't be that complex.

Best, Riccardo

On 14/11/2017 at 20:50, xxxxxxxx wrote:

Thanks so much Ric,
This is such a useful bit of code, I actually did something similar a few months ago but forgot it all, I remember you have to transform and then reverse transform as you said.
What I knew in advance would really stump me is aligning the axis, e.g. getting the orientation( Alignment?) of a selected edge along a specific axis. But as you said I can probably figure it out if I look into it more thoroughly, I'm crap at maths!