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!