## PointLocatorData

Object Hierarchy | Related C++ Class: PointLocatorData

### Introduced

v5.0

### Description

A PointLocatorData object represents a collection of point locators. A point locator is a geometric surface coordinate, and represents a precise location on a geometry. Point locators are topologically defined, so they are not dependent on the position or the deformation of the geometry (they "stick" to the surface). The actual data defining a point locator is abstracted and depends on the geometry type.
Point locators are a generalization of Points. As points, point locators can be processed independently from the geometry type. Like point indices, point locators are not related to a particular geometry instance. You can query any geometry having the same topology with the same PointLocatorData. For instance, you can use point locators to evaluate positions of an animated geometry at different times.
Because point locators don't apply to a particular geometry instance, the PointLocatorData object has no functionality by itself. Most methods related to PointLocatorData are defined in Geometry, PolygonMesh and NurbsSurfaceMesh. PointLocatorData can be created by methods Geometry.GetClosestLocations, Geometry.GetClosestLocationsWithinRadius, Geometry.GetRaycastIntersections, Geometry.GetSurfacePointLocatorsFromPoints PolygonMesh.ConstructPointLocators and NurbsSurfaceMesh.ConstructPointLocators.
Other examples of PointLocatorData usage can be found in various related methods such as PointLocatorData.Count and PolygonMesh.ConstructPointLocators.
Note: Point locators are currently only supported by NurbsSurfaceMesh and PolygonMesh objects.

### Properties

Count |  |  |

### Examples

#### 1. Python Example

    #
    #       This example uses PointLocatorData to shrink-wrap a sphere to a cube,
    #       and then pushes the sphere along cube's normals.
    #
    app = Application
    app.NewScene( "", 0 )
    root = app.ActiveSceneRoot
    CubeGeom = root.AddGeometry("Cube", "MeshSurface").ActivePrimitive.Geometry
    SphereObj = root.AddGeometry("Sphere", "MeshSurface")
    SphereObj.subdivv = 24
    SphereObj.subdivu = 24
    # Freeze it, otherwise its position array cannot be set:
    app.FreezeObj(SphereObj)
    SphereGeom = SphereObj.ActivePrimitive.Geometry
    SphereOnCubePointLocators = CubeGeom.GetClosestLocations(SphereGeom.Points.PositionArray)
    SphereOnCubePositions = CubeGeom.EvaluatePositions(SphereOnCubePointLocators)
    SphereOnCubeNormals = CubeGeom.EvaluateNormals(SphereOnCubePointLocators)
    SphereNewPositions = []
    i = 0
    while i < len(SphereOnCubePositions) :
            j = 0
            tmplist = []
            while j < len(SphereOnCubePositions[i]) :
                    tmplist.append( SphereOnCubeNormals[i][j]*3 )
                    j = j + 1
            SphereNewPositions.append(tmplist)
            i = i + 1
    SphereGeom.Points.PositionArray = SphereNewPositions;

#### 2. JScript Example

    /*
            This example uses PointLocatorData to deform a polygon mesh based on
            the closest weight map value of a NURBS surface mesh.
    */
    // Scene creation:
    //     Polygon mesh grid and a NURBS surface grid.
    //     On the NURBS grid, a weight map having a radial gradient
    NewScene( null, false );
    var root = Application.ActiveSceneRoot;
    var MeshGridObj = root.AddGeometry("Grid", "MeshSurface");
    MeshGridObj.subdivu = 24;
    MeshGridObj.subdivv = 24;
    // We must freeze it, otherwise setting its position array will be forbidden:
    FreezeObj(MeshGridObj);
    var MeshGridGeom = MeshGridObj.ActivePrimitive.Geometry;
    var NURBSGridObj = root.AddGeometry("Grid", "NurbsSurface");
    NURBSGridObj.subdivu = 2;
    NURBSGridObj.subdivv = 2;
    var NURBSGridGeom = NURBSGridObj.ActivePrimitive.Geometry;
    var NURBSWeightMap = CreateWeightMap(null, NURBSGridObj, "Weight_Map").item(0);
    SetValue(NURBSWeightMap + ".weightmapop.type", 5);
    SetValue(NURBSWeightMap + ".weightmapop.weight", 1);
    SetValue(NURBSWeightMap + ".weightmapop.invert", true);
    NURBSWeightMap = GetValue(NURBSWeightMap);      // Get the weight map again to have an updated copy
    // Applying the deformation
    var MeshGridPos = MeshGridGeom.Points.PositionArray.toArray();
    var MeshGridOnNURBSGridPointLocators = NURBSGridGeom.GetClosestLocations(MeshGridPos);
    var WeightMapValuesForMesh = NURBSGridGeom.EvaluateClusterProperty(     MeshGridOnNURBSGridPointLocators,
                                                                            NURBSWeightMap.Parent,
                                                                            NURBSWeightMap ).toArray();
    // Push mesh vertices along Y, modulated by NURBS grid's closest surface's weight map value
    for(i = 0; i < MeshGridPos.length; i+=3)
            MeshGridPos[i+1] += WeightMapValuesForMesh[i/3]*5;
    MeshGridGeom.Points.PositionArray = MeshGridPos;

#### 3. JScript Example

    // The following example is more complex but shows the PointLocatorData
    // at work in the context of a relatively complex scripted operator.
    //
    // This example creates a "skinning" custom operator, which a kind
    // of shrink wrap-based cage deform operator. This operator
    // wraps a deformed "body" object with a "skin" object having a different
    // topology. In order to create the surface correspondance between
    // the skin and the body, it uses a static copy of the "body", which
    // is not animated and stands as a reference. The operator supports,
    // too, arbitrary poses on each object.
    //
    // Since the skin and the reference body are not animated, the
    // custom operator can create the point locators only once,
    // at the first evaluation, and then only need to evaluate
    // them on the deformed body at each frame. This improves a lot
    // the performance since creating point locators from spatial
    // proximity is much more costly than simply evaluating their
    // positions or normals.
    //
    // Additionally, in order to improve the skinning result, the
    // operator pushes the sking along the normals of the body,
    // and the amplitude of this push can be controlled by a parameter.
    NewScene( null, false );
    var root = Application.ActiveSceneRoot;
    Translate("Camera", 0, 0, 50.0, siRelative, siView, siObj, siXYZ);
    // Create the reference body object, non-animated object (a cube),
    // and move it to a non-trivial pose
    var ReferenceCubeObj = root.AddGeometry("Cube", "MeshSurface");
    Translate(ReferenceCubeObj, -25.0, 0, 0, siRelative, siView, siObj, siXYZ);
    // Create the skin object (a sphere with more resolution),
    // and move it to a non-trivial pose
    var ShrinkWrappedSphereObj = root.AddGeometry("Sphere", "MeshSurface");
    ShrinkWrappedSphereObj.subdivu = 25;
    ShrinkWrappedSphereObj.subdivv = 25;
    Rotate(ShrinkWrappedSphereObj, 0, 0, -60.0, siRelative, siLocal, siObj, siXYZ);
    Scale(ShrinkWrappedSphereObj, 1.5, 1.5, 1.5, siRelative, siLocal, siObj, siXYZ);
    Translate(ShrinkWrappedSphereObj, -25.0, 0, 0, siRelative, siView, siObj, siXYZ);
    // Create the animated target body object.
    // In order to show the scripted op at work, add kinematic and
    // shape animation.
    var TargetCubeObj = root.AddGeometry("Cube", "MeshSurface");
    Translate(TargetCubeObj, 10.0, 10.0, 0, siRelative, siView, siObj, siXYZ);
    SetValue("Context.constructionmode", 1);
    Scale("cube1.pnt[2,3,6,LAST]", 0.3, 0.3, 0.3, siRelative, siLocal, siObj, siXYZ);
    SaveShapeKey("cube1.pnt[2,3,6,LAST]", null, null, 1);
    Scale("cube1.pnt[2,3,6,LAST]", 10.0, 10.0, 10.0, siRelative, siLocal, siObj, siXYZ);
    SaveShapeKey("cube1.polymsh.cls.Shape", null, null, 100);
    SaveKey("cube1.kine.local.posx,cube1.kine.local.posy,cube1.kine.local.posz");
    SaveKey("cube1.kine.local.rotx,cube1.kine.local.roty,cube1.kine.local.rotz");
    Rotate(TargetCubeObj, 50.0, 0, 50.0, siRelative, siLocal, siObj, siXYZ);
    SetValue("PlayControl.Current", 100);
    SaveKey("cube1.kine.local.rotx,cube1.kine.local.roty,cube1.kine.local.rotz", 100);
    Translate(TargetCubeObj, -15.0, -15.0, 0.0, siRelative, siView, siObj, siXYZ);
    SaveKey("cube1.kine.local.posx,cube1.kine.local.posy,cube1.kine.local.posz", 100);
    SetValue("PlayControl.Current", 1);
    // Apply the scripted op to the skin.
    var SkinOp = ApplySkinOp( ShrinkWrappedSphereObj, ReferenceCubeObj, TargetCubeObj );
    SetValue("PlayControl.Loop", true);
    PlayForwardsFromStart();
    InspectObj(SkinOp);
    function ApplySkinOp( inSkinObj, inReferenceBody, inTargetBody )
    {
            var op = XSIFactory.CreateScriptedOp( "MySkinOp", MySkinOp_Update.toString(), "JScript" );
            // Define connections
            var skin_group = op.AddPortGroup( "SkinGroup" );
            op.AddIOPort( inSkinObj.ActivePrimitive, "Geom", skin_group.Index );
            op.AddInputPort( inSkinObj.Kinematics.Global, "Pose", skin_group.Index );
            var ref_group = op.AddPortGroup( "ReferenceBodyGroup" );
            op.AddInputPort( inReferenceBody.ActivePrimitive, "Geom", ref_group.Index );
            op.AddInputPort( inReferenceBody.Kinematics.Global, "Pose", ref_group.Index );
            var tgt_group = op.AddPortGroup( "TargetBodyGroup" );
            op.AddInputPort( inTargetBody.ActivePrimitive, "Geom", tgt_group.Index );
            op.AddInputPort( inTargetBody.Kinematics.Global, "Pose", tgt_group.Index );
            // Define a parameter for the push amplitude
            var pdef = XSIFactory.CreateParamDef2( "PushAmplitude", siDouble, 2, -1, 5 );
            op.AddParameter(pdef);
            // Connect operator
            op.Connect(inSkinObj + ";" + inReferenceBody + ";" + inTargetBody);
            return op;
    }
    // This function contains the implementation of the scripted operator.
    function MySkinOp_Update( ctx, out, InSkinGeom, InSkinPose, InReferenceBodyGeom, InReferenceBodyPose, InTargetBodyGeom, InTargetBodyPose )
    {
            // TransformPositionArray: transforms in place an array of packed XYZ vectors
            function TransformPositionArray( array, transfo )
            {
                    for (i = 0; i < array.length; i+=3)
                    {
                            var TempVector3 = XSIMath.CreateVector3()
                            TempVector3.Set(array[i], array[i+1], array[i+2]);
                            TempVector3.MulByTransformationInPlace(transfo);
                            var XYZArray = TempVector3.Get2().toArray();
                            array[i] = XYZArray[0];
                            array[i+1] = XYZArray[1];
                            array[i+2] = XYZArray[2];
                    }
            }
            var SkinGeom = InSkinGeom.Value.Geometry;
            var ReferenceBodyGeom = InReferenceBodyGeom.Value.Geometry;
            /////////////////////////////////////////////////////////
            //1) Create skin point locators relatively to the surface
            //   proximity to the reference body. We intentionally keep
            //   a snapshot of the point locators to speed up the
            //   next evaluations; we assume that InSkinGeom, InSkinPose,
            //   InReferenceBodyGeom and InReferenceBodyPose are not
            //   animated.
            var SkinPointLocators = ctx.UserData;
            if(SkinPointLocators == null)   // No user data means that this is the first evaluation of the operator
            {
                    // The skin object and the reference may have different poses, so we
                    // will compute the surface proximity computation in global space.
                    // We will use the closest smoothed surface method (2==siClosestSmoothedSurface).
                    ReferenceBodyGeom.SetupPointLocatorQueries(2, InReferenceBodyPose.Value.Transform);
                    // Transform the skin positions in global space
                    var SkinGeomPosArray = SkinGeom.Points.PositionArray.toArray();
                    // TransformPositionArray: transforms in place an array of packed XYZ vectors
                    TransformPositionArray( SkinGeomPosArray, InSkinPose.Value.Transform );
                    SkinPointLocators = ReferenceBodyGeom.GetClosestLocations(SkinGeomPosArray);
                    ctx.UserData = SkinPointLocators;
            }
            /////////////////////////////////////////////////////////
            //2) Evaluate the point locators on the target body, and
            //   displace them along target body's normals, with the
            //   amplitude given by the scirted op parameter.
            var TargetBodyGeom = InTargetBodyGeom.Value.Geometry;
            var SkinOnTargetBodyPositions = TargetBodyGeom.EvaluatePositions(SkinPointLocators).toArray();
            var SkinOnTargetBodyNormals = TargetBodyGeom.EvaluateNormals(SkinPointLocators).toArray();
            var SkinToTargetTransform = XSIMath.MapWorldPoseToObjectSpace(InSkinPose.Value.Transform, InTargetBodyPose.Value.Transform);
            var dPushAmplitude = ctx.Parameters("PushAmplitude").Value
            for (i = 0; i < SkinOnTargetBodyPositions.length; i++)
                    SkinOnTargetBodyPositions[i] += SkinOnTargetBodyNormals[i]*dPushAmplitude;
            // TransformPositionArray: transforms in place an array of packed XYZ vectors
            TransformPositionArray( SkinOnTargetBodyPositions, SkinToTargetTransform );
            SkinGeom.Points.PositionArray = SkinOnTargetBodyPositions;
    }

### See Also

Geometry Geometry.GetClosestLocations Geometry.GetClosestLocationsWithinRadius Geometry.GetRaycastIntersections Geometry.SetupPointLocatorQueries Geometry.GetSurfacePointLocatorsFromPoints Geometry.EvaluatePositions Geometry.EvaluateNormals Geometry.EvaluateClusterProperty PolygonMesh.GetPolygonIndexArray PolygonMesh.GetTriangleVertexIndexArray PolygonMesh.GetTriangleNodeIndexArray PolygonMesh.GetTriangleWeightArray PolygonMesh.ConstructPointLocators NurbsSurfaceMesh.GetSubSurfaceIndexArray NurbsSurfaceMesh.GetNormalizedUVArray NurbsSurfaceMesh.ConstructPointLocators