## 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").ActivePrimitive2.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.ActivePrimitive2.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