/// <inheritdocs /> public Interpolant Find(Vector3 pos) { Interpolant bary = FindTriangleOrEdgeOrVertex(pos); AdjustForBoundingIndices(bary); return(bary); }
/// <summary> /// Query for a triangle containing the projection of this position, or failing that, /// find the closest point on the closest edge. /// </summary> /// <param name="pos">The query position.</param> /// <returns>The interpolant, or null if there is no data to query.</returns> private Interpolant FindTriangleOrEdgeOrVertex(Vector3 pos) { if (PointInsideBounds(pos)) { Interpolant bary = FindTriangle(pos).bary; if (IsInteriorTriangle(bary)) { return(bary); } } return(FindClosestExteriorEdge(pos)); }
/// <summary> /// Determine if the interpolant is interpolating between real vertices, or is /// exterior (i.e. one or more vertices are bounding dummy vertices). /// </summary> /// <param name="bary"></param> /// <returns></returns> private bool IsInteriorTriangle(Interpolant bary) { if (bary == null) { return(false); } for (int i = 0; i < bary.idx.Length; ++i) { if (IsBoundary(bary.idx[i])) { return(false); } } return(true); }
/// <summary> /// Adjust the indices accounting for the 4 dummy verts introduced in SetBounds()/SeedQuad(). /// </summary> /// <param name="bary">The interpolant whose indices need adjusting.</param> /// <remarks> /// Note that with this current implementation, once the indices are corrected, it's no longer possible to tell whether they are boundary vertices. /// </remarks> private void AdjustForBoundingIndices(Interpolant bary) { if (bary != null) { for (int i = 0; i < 3; ++i) { if (!IsBoundary(bary.idx[i])) { bary.idx[i] = bary.idx[i] - 4; } else { Debug.Assert(bary.weights[i] == 0.0f); } } } }
/// <summary> /// Find the exterior edge with the closest point on the edge to the query position. /// </summary> /// <param name="pos">The query position.</param> /// <returns>A triangle interpolant that will evaluate to the interpolation between the two edge endpoints. Returns null if there are no exterior edges.</returns> /// <remarks> /// The third triangle vertex always has index 0 and weight 0. /// </remarks> private Interpolant FindClosestExteriorEdge(Vector3 pos) { if (exteriorEdges.Count == 0) { if (vertices.Count == 5) { /// There is a single real vertex, so no exterior edges. /// That's okay, the single vertex wins all the weight. Interpolant singleVert = new Interpolant(); singleVert.idx[0] = singleVert.idx[1] = singleVert.idx[2] = 4; singleVert.weights[0] = 1.0f; singleVert.weights[1] = singleVert.weights[2] = 0.0f; return(singleVert); } return(null); } int closestEdge = -1; float closestDistance = float.MaxValue; float closestParm = 0.0f; for (int i = 0; i < exteriorEdges.Count; ++i) { PointOnEdge point = PositionOnEdge(exteriorEdges[i], pos); if (point.distanceSqr < closestDistance) { closestEdge = i; closestDistance = point.distanceSqr; closestParm = point.parm; } } Debug.Assert(closestEdge >= 0, "If there are any edges, there must be a closest one."); Edge edge = exteriorEdges[closestEdge]; Interpolant bary = new Interpolant(); bary.idx[0] = edge.idx0; bary.idx[1] = edge.idx1; bary.idx[2] = 0; bary.weights[0] = 1.0f - closestParm; bary.weights[1] = closestParm; bary.weights[2] = 0; return(bary); }
private List <WeightedPose> ComputePoseWeights(Vector3 lockedHeadPosition) { weightedPoses.Clear(); Triangulator.Interpolant bary = triangulator.Find(lockedHeadPosition); if (bary != null) { for (int i = 0; i < 3; ++i) { weightedPoses.Add(new WeightedPose() { pose = ComputePinnedFromLocked(activePoses[bary.idx[i]]), weight = bary.weights[i] }); } } else { Debug.Assert(activePoses.Count == 0, "Failed to find an interpolant even though there are pins active."); } return(weightedPoses); }