Python maya.OpenMaya.MVector() Examples

The following are 30 code examples of maya.OpenMaya.MVector(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module maya.OpenMaya , or try the search function .
Example #1
Source File: rigutils.py    From DynRigBuilder with MIT License 6 votes vote down vote up
def buildJointChain(prefix, suffix, startPos, endPos, jointNum, orientJoint="xyz", saoType="yup"):
    """
    Build a straight joint chain defined by start and end position.
    :param prefix: `string` prefix string in joint name
    :param suffix: `string` suffix string in joint name
    :param startPos: `list` [x,y,z] start position in the world space
    :param endPos: `list` [x,y,z] end position in the world space
    :param jointNum: number of joints in the joint chain
    :param orientJoint: `string` orient joint flag
    :param saoType: `string` secondary axis orient flag
    :return: `list` list of joint nodes in the joint chain. sorted by hierarchy.
    """
    pm.select(d=1)
    step = (om.MVector(*endPos)-om.MVector(*startPos))/(jointNum-1.0)
    jnts = []
    for i in range(jointNum):
        crtPos = om.MVector(*startPos)+step*i
        crtSuffix = suffix#suffix[1] if i==jointNum-1 else suffix[0]
        jnts.append(pm.joint(p=(crtPos.x, crtPos.y, crtPos.z), n="{0}_{1:0>2d}_{2}".format(prefix, i, crtSuffix)))
    pm.joint(jnts, e=True, oj=orientJoint, sao=saoType)
    return jnts 
Example #2
Source File: mesh_utils.py    From spore with MIT License 6 votes vote down vote up
def get_tangent(normal):
    """ return a normalized tangent for the given normal I
    :param normal MVector: normal vector
    :return MVector: tangent """

    if isinstance(normal, om.MVector):
        u = normal ^ om.MVector(0, 0, 1)
        v = normal ^ om.MVector(0, 1, 0)

        if u.length() > v.length():
            tangent = u.normal()
        else:
            tangent = v.normal()

        return (normal ^ tangent).normal()

    else:
        raise TypeError('Input must be of type MVector, is: {}'.format(type(normal))) 
Example #3
Source File: mesh_utils.py    From spore with MIT License 6 votes vote down vote up
def get_closest_point_and_normal(point, target):
    """ find the closest point and normal to the given point
    :return: closest point
             closest normal
             distance to the closest point """

    closest_point = None
    closest_normal = None
    #  shortest_distance = None

    #  for target in targets:
    mesh_fn = get_mesh_fn(target)
    out_point = om.MPoint()
    out_normal = om.MVector()
    mesh_fn.getClosestPointAndNormal(point, out_point, out_normal, om.MSpace.kWorld)
    #  out_tangent = get_tangent(normal)

    return out_point, out_normal 
Example #4
Source File: mesh_utils.py    From spore with MIT License 6 votes vote down vote up
def hit_test(target, x, y, invert_y=True):

    origin = om.MPoint()
    direction = om.MVector()
    view = window_utils.active_view()

    if invert_y:
        y = view.portHeight() - y

    view.viewToWorld(x, y, origin, direction)
    mesh_fn = get_mesh_fn(target)

    if mesh_fn:
        points = om.MPointArray()
        intersect = mesh_fn.intersect(origin, direction, points, 1.0e-3, om.MSpace.kWorld)
        if intersect:
            point = points[0]
            normal = om.MVector()
            mesh_fn.getClosestNormal(point, normal, om.MSpace.kWorld)
            tangent = get_tangent(normal)

            position = (point.x, point.y, point.z)
            tangent = (tangent.x, tangent.y, tangent.z)
            normal = (normal.x, normal.y, normal.z)
            return (position, normal, tangent) 
Example #5
Source File: spore_context.py    From spore with MIT License 6 votes vote down vote up
def get_scale(self, flag, index=0):
        """ get scale values for the currently saved point at the given index """

        # when we in drag mode we want to maintain old scale values
        if self.brush_state.shift_mod and flag != SporeToolCmd.k_click:
            scale = self.initial_scale[index]

        # otherweise we generate new values
        else:
            min_scale = self.brush_state.settings['min_scale']
            max_scale = self.brush_state.settings['max_scale']
            uniform = self.brush_state.settings['uni_scale']
            if uniform:
                scale_x = scale_y = scale_z = random.uniform(min_scale[0], max_scale[0])
            else:
                scale_x = random.uniform(min_scale[0], max_scale[0])
                scale_y = random.uniform(min_scale[1], max_scale[1])
                scale_z = random.uniform(min_scale[2], max_scale[2])

            scale = om.MVector(scale_x, scale_y, scale_z)
            self.initial_scale.set(scale, index)

        return scale 
Example #6
Source File: vector.py    From mgear_core with MIT License 6 votes vote down vote up
def __init__(self, t=datatypes.Matrix()):

        self.transform = t

        d = [t.data[j][i]
             for j in range(len(t.data))
             for i in range(len(t.data[0]))]

        m = OpenMaya.MMatrix()
        OpenMaya.MScriptUtil.createMatrixFromList(d, m)
        m = OpenMaya.MTransformationMatrix(m)

        x = OpenMaya.MVector(1, 0, 0).rotateBy(m.rotation())
        y = OpenMaya.MVector(0, 1, 0).rotateBy(m.rotation())
        z = OpenMaya.MVector(0, 0, 1).rotateBy(m.rotation())

        self.x = datatypes.Vector(x.x, x.y, x.z)
        self.y = datatypes.Vector(y.x, y.y, y.z)
        self.z = datatypes.Vector(z.x, z.y, z.z) 
Example #7
Source File: mesh.py    From maya-skinning-tools with GNU General Public License v3.0 6 votes vote down vote up
def getNormals(dag):
    """
    Get the average normal in world space of each vertex on the provided mesh.
    The reason why OpenMaya.MItMeshVertex function has to be used is that the
    MFnMesh class returns incorrect normal results.

    :param OpenMaya.MDagPath dag:
    :return: Normals
    :rtype: list
    """
    # variables
    normals = []

    iter = OpenMaya.MItMeshVertex(dag)
    while not iter.isDone():
        # get normal data
        normal = OpenMaya.MVector()
        iter.getNormal(normal, OpenMaya.MSpace.kWorld)
        normals.append(normal)

        iter.next()

    return normals 
Example #8
Source File: spore_context.py    From spore with MIT License 6 votes vote down vote up
def undo_vector_action(self, attr, undo_command):
        """ undo transformation attributes.
        scale, rotatio be undone with this method
        :param attr: the instance data attribute that should changed
        :type attr: string
        :param undo_command: a list of index, x, y, z vale, repeating in this pattern
        :type undo_command: list
        :return: """

        if not hasattr(self.instance_data, attr):
            self.logger.error('Instance data has not attribute: {}'.format(attr))
            return

        ids = []
        values = om.MVectorArray()
        for i in range(len(undo_command) / 4):
            ids.append(int(undo_command[i * 4]))
            val_x = float(undo_command[i * 4 + 1])
            val_y = float(undo_command[i * 4 + 2])
            val_z = float(undo_command[i * 4 + 3])
            values.append(om.MVector(val_x, val_y, val_z))

        self.instance_data.set_points(ids, **{attr: values})
        self.instance_data.set_state() 
Example #9
Source File: joint.py    From maya-skinning-tools with GNU General Public License v3.0 6 votes vote down vote up
def closestLineToPoint(lines, point):
    """
    Loop over all lines and find the closest point on the line from the
    provided point. After this is done the list of lines is sorted based on
    closest distance to the line.

    :param dict lines:
    :param OpenMaya.MVector point:
    :return: Closest lines and points ordered on distance
    :rtype: tuple
    """
    # get closest point on the line for each line
    names, closestPoints = zip(
        *[
            (name, api.closestPointOnLine(line[0], line[1], point))
            for name, line in lines.iteritems()
        ]
    )

    # sort the closest points from shortest to longest depending on the
    # distance to the vertex in world space position.
    return api.sortByDistance(names, point, closestPoints) 
Example #10
Source File: spore_context.py    From spore with MIT License 6 votes vote down vote up
def scale_action(self, flag):
        position, normal, tangent = self.get_brush_coords()
        radius = self.brush_state.radius

        neighbour = self.instance_data.get_closest_points(position, radius, self.brush_state.settings['ids'])
        if neighbour:
            self.set_cache_length(len(neighbour))
        else:
            return

        for i, index in enumerate(neighbour):
            value = self.instance_data.scale[index]
            factor = self.brush_state.settings['scale_factor']
            falloff_weight = self.get_falloff_weight(self.instance_data.position[index])
            factor = (factor - 1) * falloff_weight + 1
            self.scale.set(value * factor, i)

            # add to undo stack
            if not self.last_state.has_key(index):
                self.last_state[index] = om.MVector(value.x, value.y, value.z)

        self.instance_data.set_points(neighbour, scale=self.scale)
        self.instance_data.set_state() 
Example #11
Source File: oyTrajectoryDrawer.py    From anima with MIT License 6 votes vote down vote up
def boundingBox(self):
        
        # get the tPositions
        tPositions = self.getTPositions()
        
        # get the multiplier
        size = self.getSize()
        
        # create the bounding box
        bbox = OpenMaya.MBoundingBox()
        
        # add the positions one by one
        numOfTPos = tPositions.length()
        
        #print("numOfTPos in bbox : %s " % numOfTPos)
        
        for i in range(numOfTPos):
            
            # add the positive one
            bbox.expand( OpenMaya.MPoint( tPositions[i] + OpenMaya.MVector(size, size, size) ) )
            
            # add the negative one
            bbox.expand( OpenMaya.MPoint( tPositions[i] - OpenMaya.MVector(size, size, size) ) )
        
        return bbox 
Example #12
Source File: spore_context.py    From spore with MIT License 6 votes vote down vote up
def align_action(self, flag):
        position, normal, tangent = self.get_brush_coords()
        radius = self.brush_state.radius
        neighbour = self.instance_data.get_closest_points(position, radius, self.brush_state.settings['ids'])
        if neighbour:
            self.set_cache_length(len(neighbour))
        else:
            return

        for i, index in enumerate(neighbour):
            rotation = self.instance_data.rotation[index]

            # add to undo stack
            if not self.last_state.has_key(index):
                self.last_state[index] = om.MVector(rotation.x, rotation.y, rotation.z)

            normal = self.instance_data.normal[index]
            direction = self.get_alignment(normal)
            rotation = self.rotate_into(direction, rotation)
            self.rotation.set(rotation, i)

        self.instance_data.set_points(neighbour, rotation=self.rotation)
        self.instance_data.set_state() 
Example #13
Source File: spore_sampler.py    From spore with MIT License 6 votes vote down vote up
def get_rotation(self, direction, weight, min_rot, max_rot):
        """ get rotation from a matrix pointing towards the given direction
        slerped by the given weight into the world up vector and added a random
        rotation between min and max rotation """

        r_x = math.radians(random.uniform(min_rot[0], max_rot[0]))
        r_y = math.radians(random.uniform(min_rot[1], max_rot[1]))
        r_z = math.radians(random.uniform(min_rot[2], max_rot[2]))
        util = om.MScriptUtil()
        util.createFromDouble(r_x, r_y, r_z)
        rotation_ptr = util.asDoublePtr()

        matrix = om.MTransformationMatrix()
        matrix.setRotation(rotation_ptr, om.MTransformationMatrix.kXYZ)
        world_up = om.MVector(0, 1, 0)
        rotation = om.MQuaternion(world_up, direction, weight)
        matrix = matrix.asMatrix() * rotation.asMatrix()
        rotation = om.MTransformationMatrix(matrix).rotation().asEulerRotation()

        return om.MVector(math.degrees(rotation.x),
                          math.degrees(rotation.y),
                          math.degrees(rotation.z)) 
Example #14
Source File: spore_sampler.py    From spore with MIT License 6 votes vote down vote up
def sample_triangle(self,triangle_id, point_id):
        """ sample a random point on a the given triangle """

        r = random.random()
        s = random.random()

        if r + s >= 1:
            r = 1 - r
            s = 1 - s

        r = om.MScriptUtil(r).asFloat()
        s = om.MScriptUtil(s).asFloat()

        r = self.geo_cache.AB[triangle_id] * r
        s = self.geo_cache.AC[triangle_id] * s

        p = om.MPoint(r + s + om.MVector(self.geo_cache.p0[triangle_id]))
        u = 0
        v = 0

        self.point_data.set(point_id, p, self.geo_cache.normals[triangle_id],
                            self.geo_cache.poly_id[triangle_id], u, v) 
Example #15
Source File: render.py    From anima with MIT License 6 votes vote down vote up
def generate_reflection_curve(self):
        """Generates a curve which helps creating specular at the desired point
        """
        from maya.OpenMaya import MVector
        from anima.env.mayaEnv import auxiliary

        vtx = pm.ls(sl=1)[0]
        normal = vtx.getNormal(space='world')
        panel = auxiliary.Playblaster.get_active_panel()
        camera = pm.PyNode(pm.modelPanel(panel, q=1, cam=1))
        camera_axis = MVector(0, 0, -1) * camera.worldMatrix.get()

        refl = camera_axis - 2 * normal.dot(camera_axis) * normal

        # create a new curve
        p1 = vtx.getPosition(space='world')
        p2 = p1 + refl

        curve = pm.curve(d=1, p=[p1, p2])

        # move pivot to the first point
        pm.xform(curve, rp=p1, sp=p1) 
Example #16
Source File: spore_sampler.py    From spore with MIT License 6 votes vote down vote up
def slope_filter(self, min_slope, max_slope, fuzz):

        world = om.MVector(0, 1, 0)

        invalid_ids = []
        for i, (_, normal, _, _, _) in enumerate(self.point_data):
            normal = om.MVector(normal[0], normal[1], normal[2])
            angle = math.degrees(normal.angle(world)) + 45 * random.uniform(-fuzz, fuzz)

            if angle < min_slope or angle > max_slope:
                invalid_ids.append(i)

        invalid_ids = sorted(invalid_ids, reverse=True)
        [self.point_data.remove(index) for index in invalid_ids]


        pass 
Example #17
Source File: oyTrajectoryDrawer.py    From anima with MIT License 5 votes vote down vote up
def getTangent(self, normal):
        """returns a tangent vector of normal
        """
        tangent = OpenMaya.MVector()
        
        if abs(normal.x) > 0.5 or abs(normal.y) > 0.5 :
            tangent.x = normal.y;
            tangent.y = -1.0 * normal.x;
            tangent.z = 0.0;
        else:
            tangent.x = -1.0 * normal.z;
            tangent.y = 0.0;
            tangent.z = normal.x;
        
        return tangent 
Example #18
Source File: brush_utils.py    From spore with MIT License 5 votes vote down vote up
def get_offset(min_offset, max_offset, position, normal):
    """ offset a given point along the normal
    :param min_offset float():
    :param max_offset float():
    :param position MPoint:
    :param normal MVector:
    :return MVector: containing the offset position """

    rand_o = random.uniform(min_offset, max_offset)
    return om.MVector(position + normal * rand_o) 
Example #19
Source File: vector.py    From maya-keyframe-reduction with MIT License 5 votes vote down vote up
def __init__(self, *args):
        if len(args) == 1:
            OpenMaya.MVector.__init__(self, args[0])
        elif len(args) == 2:
            OpenMaya.MVector.__init__(self, args[0], args[1], 0) 
Example #20
Source File: rigutils.py    From DynRigBuilder with MIT License 5 votes vote down vote up
def createSurfaceFromJoints(joints, name="surface", ibtCVNum=0, degree=3):
    """
    Create a nurbs surface along the given joints.
    nurbs CV position is defined by joint position.
    :param joints: `list` list of joint nodes
    :param name: `string` name of the built surface
    :param ibtCVNum: `int` number of cv points added inbetween the joint position
    :param degree: `int` nurbs surface degree
    :return: `PyNode` result surface
    """
    # build surface from joints, one span for each joint
    auxCrv = createCurveFromJoint(joints, name+"_crv", ibtCVNum, degree)
    startPos = joints[0].getTranslation(space="world")
    endPos = joints[-1].getTranslation(space="world")

    offDir = (om.MVector(*(startPos-endPos))^om.MVector(0,1,0)).normal()
    if offDir.length() == 0: offDir = om.MVector(0,0,-1)

    print startPos, endPos, offDir[0], offDir[1], offDir[2]
    buildCrv1 = pm.duplicate(auxCrv)
    pm.move(offDir.x*0.5, offDir.y*0.5, offDir.z*0.5, buildCrv1, r=1)
    buildCrv2 = pm.duplicate(auxCrv)
    pm.move(offDir.x*-0.5, offDir.y*-0.5, offDir.z*-0.5, buildCrv2, r=1)
    auxSurf = pm.loft(buildCrv1, buildCrv2, n=name, ch=0, u=1, d=degree)[0]
    pm.rebuildSurface(auxSurf, ch=0, su=1, du=1, dv=degree, sv=0)
    pm.delete(auxCrv, buildCrv1, buildCrv2)
    # auxSurf.setParent(0)
    return auxSurf 
Example #21
Source File: canvas.py    From spore with MIT License 5 votes vote down vote up
def create_brush_shape(self):
        """ generate the shape of the brush based on the brush state """

        if self.brush_state.draw:
            # fetch point and normal
            pnt = om.MPoint(self.brush_state.position[0],
                            self.brush_state.position[1],
                            self.brush_state.position[2])
            nrm = om.MVector(self.brush_state.normal[0],
                            self.brush_state.normal[1],
                            self.brush_state.normal[2])
            tan = om.MVector(self.brush_state.tangent[0],
                            self.brush_state.tangent[1],
                            self.brush_state.tangent[2])

            # get point at normal and tangent
            #  n_pnt = pnt + (nrm * self._state.radius * 0.75)
            #  t_str = pnt + (tan * self._state.radius * 0.75)
            #  t_end = pnt + (tan * self._state.radius)
            #  shape.append(window_utils.world_to_view(pnt))

            shape = []
            # get circle points
            theta = math.radians(360 / 20)
            for i in xrange(40 + 1):
                rot = om.MQuaternion(theta * i, nrm)
                rtan = tan.rotateBy(rot)
                pos = pnt + (rtan * self.brush_state.radius)

                pos_x, pos_y = window_utils.world_to_view(pos)
                shape.append((pos_x, pos_y))

            return [shape] 
Example #22
Source File: utils.py    From maya-retarget-blendshape with GNU General Public License v3.0 5 votes vote down vote up
def getAveragePosition(dag, component, space):
    """
    Get average position of connected vertices.
    
    :param OpenMaya.MDagPath dag: 
    :param OpenMaya.MFnSingleIndexedComponent component: 
    :param OpenMaya.MSpace space:
    :return: Average length of the connected edges
    :rtype: OpenMaya.MPoint
    """
    averagePos = OpenMaya.MPoint()

    # get connected vertices
    connected = OpenMaya.MIntArray()
    
    iterate = OpenMaya.MItMeshVertex(dag, component)
    iterate.getConnectedVertices(connected)
    
    # get original position
    originalPos = iterate.position(space)
      
    # ignore if no vertices are connected
    if not connected.length():
        return averagePos
    
    # get average 
    component = asComponent(connected)
    iterate = OpenMaya.MItMeshVertex(dag, component)
    while not iterate.isDone():
        averagePos += OpenMaya.MVector(iterate.position(space))
        iterate.next()
        
    averagePos = averagePos/connected.length()
    return originalPos, averagePos 
Example #23
Source File: vector.py    From mgear_core with MIT License 5 votes vote down vote up
def rotateAlongAxis(v, axis, a):
    """Rotate a vector around a given axis defined by other vector.

    Arguments:
        v (vector): The vector to rotate.
        axis (vector): The axis to rotate around.
        a (float): The rotation angle in radians.

    """
    sa = math.sin(a / 2.0)
    ca = math.cos(a / 2.0)

    q1 = OpenMaya.MQuaternion(v.x, v.y, v.z, 0)
    q2 = OpenMaya.MQuaternion(axis.x * sa, axis.y * sa, axis.z * sa, ca)
    q2n = OpenMaya.MQuaternion(-axis.x * sa, -axis.y * sa, -axis.z * sa, ca)
    q = q2 * q1
    q *= q2n

    out = OpenMaya.MVector(q.x, q.y, q.z)

    return out


##########################################################
# CLASS
########################################################## 
Example #24
Source File: icon.py    From mgear_core with MIT License 5 votes vote down vote up
def getPointArrayWithOffset(point_pos, pos_offset=None, rot_offset=None):
    """Get Point array with offset

    Convert a list of vector to a List of float and add the position and
    rotation offset.

    Arguments:
        point_pos (list of vector): Point positions.
        pos_offset (vector):  The position offset of the curve from its
            center.
        rot_offset (vector): The rotation offset of the curve from its
            center. In radians.

    Returns:
        list of vector: the new point positions

    """
    points = []
    for v in point_pos:
        if rot_offset:
            mv = om.MVector(v.x, v.y, v.z)
            mv = mv.rotateBy(om.MEulerRotation(rot_offset.x,
                                               rot_offset.y,
                                               rot_offset.z,
                                               om.MEulerRotation.kXYZ))
            v = datatypes.Vector(mv.x, mv.y, mv.z)
        if pos_offset:
            v = v + pos_offset

        points.append(v)

    return points 
Example #25
Source File: vector.py    From maya-skinning-tools with GNU General Public License v3.0 5 votes vote down vote up
def getAverageVector(vectors):
    """
    Get the average vector of the all of the provided vectors. All vectors
    will be added up and divided by the number of the provided vectors.

    :param list vectors:
    :return: Average vector
    :rtype: OpenMaya.MVector
    """
    vector = OpenMaya.MVector()
    for v in vectors:
        vector += v

    vector /= len(vectors)
    return vector 
Example #26
Source File: mesh.py    From maya-skinning-tools with GNU General Public License v3.0 5 votes vote down vote up
def getPoints(dag):
    """
    Get the position in world space of each vertex on the provided mesh.

    :param OpenMaya.MDagPath dag:
    :return: Points
    :rtype: list
    """
    points = OpenMaya.MPointArray()
    mesh = OpenMaya.MFnMesh(dag)
    mesh.getPoints(points, OpenMaya.MSpace.kWorld)

    return [OpenMaya.MVector(points[i]) for i in range(points.length())] 
Example #27
Source File: benchmark.py    From tutorials with MIT License 5 votes vote down vote up
def testPyApi():

    start   = time.time()

    # creating the helix via the cmds module, for consistency
    # in the helix object and number of vertices
    helix   = cmds.polyHelix(**HELIX_OPTS)
    pHelix  = helix[0]

    sel     = OpenMaya.MSelectionList()
    node    = OpenMaya.MObject()

    sel.add(pHelix)
    sel.getDependNode( 0, node ) 

    vector = OpenMaya.MVector()

    iter = OpenMaya.MItMeshVertex(node)

    while not iter.isDone():

        vector.x = RAND.uniform(LOW, HIGH)
        iter.translateBy(vector)

        iter.next()
    
    OpenMaya.MGlobal.deleteNode(node)

    end = time.time()
    return end-start 
Example #28
Source File: node_utils.py    From spore with MIT License 5 votes vote down vote up
def get_local_rotation(mobject):
    """ returns an transform node's world space rotation values
    in degrees """

    dag_path = om.MDagPath()
    om.MDagPath.getAPathTo(mobject, dag_path)
    matrix = dag_path.inclusiveMatrix()
    matrix = om.MTransformationMatrix(matrix)
    rotation = matrix.asEulerRotation()

    return om.MVector(math.degrees(rotation.x),
                      math.degrees(rotation.y),
                      math.degrees(rotation.z)) 
Example #29
Source File: spore_sampler.py    From spore with MIT License 5 votes vote down vote up
def get_alignment(self, alignment, normal):
        """ get a vector representing th current alignment mdoe """

        if alignment == 'normal':
            return normal
        elif alignment == 'world':
            return om.MVector(0, 1, 0)
        elif alignment == 'object':
            return node_utils.get_local_rotation(self.target) 
Example #30
Source File: spore_context.py    From spore with MIT License 5 votes vote down vote up
def smooth_align_action(self, flag):
        """ """
        position, normal, tangent = self.get_brush_coords()
        radius = self.brush_state.radius
        neighbour = self.instance_data.get_closest_points(position, radius, self.brush_state.settings['ids'])
        if neighbour:
            average = self.instance_data.get_rotation_average(neighbour)
            average = om.MVector(average[0], average[1], average[2])
            self.set_cache_length(len(neighbour))
        else:
            return

        for i, index in enumerate(neighbour):
            rotation = self.instance_data.rotation[index]

            # add to undo stack
            if not self.last_state.has_key(index):
                self.last_state[index] = om.MVector(rotation.x, rotation.y, rotation.z)

            normal = self.instance_data.normal[index]
            #  direction = self.get_alignment(normal)
            rotation = self.rotate_into(average, rotation)
            self.rotation.set(rotation, i)

        self.instance_data.set_points(neighbour, rotation=self.rotation)
        self.instance_data.set_state()