SVGravityImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on February 17, 1987 11:19:15 pm PST
Contents: Routines to snap the skitter to faces, segments, and points in the scene.
DIRECTORY
AtomButtonsTypes, CodeTimer, CoordSys, DisplayListToTree, Feedback, IO, Matrix3d, Preprocess3d, Real, RealFns, Rope, SV2d, SV3d, SVAssembly, SVCaret, SVCastRays, SVGravity, SVInterfaceTypes, SVLines3d, SVModelTypes, SVRay, SVScene, SVSceneTypes, SVState, SVVector3d;
SVGravityImpl: CEDAR PROGRAM
IMPORTS CodeTimer, CoordSys, DisplayListToTree, Feedback, Matrix3d, Preprocess3d, RealFns, SVAssembly, SVCaret, SVCastRays, SVLines3d, SVRay, SVState, SVVector3d
EXPORTS SVGravity =
BEGIN
AlignBag: TYPE = SVInterfaceTypes.AlignBag;
AlignmentLine: TYPE = SVInterfaceTypes.AlignmentLine;
Camera: TYPE = SVSceneTypes.Camera;
Classification: TYPE = SVSceneTypes.Classification;
CSGTree: TYPE = SVSceneTypes.CSGTree;
FeatureCycler: TYPE = REF FeatureCyclerObj;
FeatureCyclerObj: TYPE = SVInterfaceTypes.FeatureCyclerObj;
FeatureData: TYPE = SVInterfaceTypes.FeatureData;
FeedbackData: TYPE = AtomButtonsTypes.FeedbackData;
GoodPoint: TYPE = REF GoodPointObj;
GoodPointObj: TYPE = SVInterfaceTypes.GoodPointObj;
GravityType: TYPE = SVInterfaceTypes.GravityType;
Line3d: TYPE = SV3d.Line3d;
MasterObject: TYPE = SVSceneTypes.MasterObject;
Matrix4by4: TYPE = SV3d.Matrix4by4;
NearDistances: TYPE = REF NearDistancesObj;
NearDistancesObj: TYPE = SVGravity.NearDistancesObj;
NearFeatures: TYPE = REF NearFeaturesObj;
NearFeaturesObj: TYPE = SVGravity.NearFeaturesObj;
NearVertexEdgeAndFaces: TYPE = REF NearVertexEdgeAndFacesObj;
NearVertexEdgeAndFacesObj: TYPE = SVInterfaceTypes.NearVertexEdgeAndFacesObj;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = SV3d.Point3d;
PointAndDone: TYPE = SVSceneTypes.PointAndDone;
PointGenerator: TYPE = SVSceneTypes.PointGenerator;
Primitive: TYPE = SVSceneTypes.Primitive;
Ray: TYPE = SVSceneTypes.Ray;
Scene: TYPE = SVSceneTypes.Scene;
SearchDepth: TYPE = SVSceneTypes.SearchDepth;
Shape: TYPE = SVSceneTypes.Shape;
Skitter: TYPE = SVSceneTypes.Skitter;
Slice: TYPE = SVSceneTypes.Slice;
SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor;
TriggerBag: TYPE = SVInterfaceTypes.TriggerBag;
Vector3d: TYPE = SV3d.Vector3d;
SVData: TYPE = SVInterfaceTypes.SVData;
Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = Feedback.Problem;
maxFeatures: NAT ← 20;
BestPoints: TYPE = REF BestPointsObj;
BestPointsObj: TYPE = RECORD [
size: NAT,
max, min: REAL,
bestTossed: REAL, -- the distance of the closest object that has been thrown away
dTol: REAL, -- min + s
innerR: REAL, -- find all curves within this radius even if they are not neighbors of the nearest
s: REAL, -- the size of neighborhoods. BestPoints should contain all objects that have been seen such that min <= dist(o, q) <= min+s, unless BestPoints overflows.
overflow: BOOL,
points: SEQUENCE len: NAT OF GoodPoint];
MultiGravityPool: TYPE = REF MultiGravityPoolObj;
MultiGravityPoolObj: TYPE = RECORD [
distances: NearDistances,
features: NearFeatures,
bestpoints: BestPoints,
bestcurves: BestPoints
];
EmptyBag: PROC [alignBag: AlignBag] RETURNS [BOOL] = {
RETURN[
alignBag.slopeLines = NIL AND
alignBag.slopePlanes = NIL AND
alignBag.anchor = NIL];
};
EmptyTriggers: PROC [triggerBag: TriggerBag] RETURNS [BOOL] = {
RETURN[
triggerBag.slices = NIL AND
triggerBag.anchor = NIL
];
};
RayMap: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL ← FALSE] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
gravityType: GravityType ← SVState.GetGravityType[svData];
camera: Camera ← svData.camera;
CodeTimer.StartInt[$RayMap, $Solidviews];
IF SVState.GetGravity[svData] THEN {
SELECT gravityType FROM
facesPreferred =>
[surfacePtWorld, normalWorld, feature, hitData] ← FacesPreferred[cameraPt, t, alignBag, sceneBag, svData];
linesPreferred =>
[surfacePtWorld, normalWorld, feature, hitData] ← LinesPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections];
pointsPreferred =>
[surfacePtWorld, normalWorld, feature, hitData] ← PointsPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections];
ENDCASE => ERROR;
}
ELSE {
parallel: BOOL;
[surfacePtWorld, normalWorld, parallel] ← RayMeetsCentralCameraPlane[cameraPt, camera];
feature ← NIL;
hitData ← NIL;
};
CodeTimer.StopInt[$RayMap, $Solidviews];
};
RayMapCycler: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOLFALSE] RETURNS [featureCycler: FeatureCycler] = {
gravityType: GravityType ← SVState.GetGravityType[svData];
camera: Camera ← svData.camera;
IF SVState.GetGravity[svData] THEN {
SELECT gravityType FROM
facesPreferred =>
featureCycler ← FacesPreferredCycler[cameraPt, t, alignBag, sceneBag, svData];
linesPreferred =>
featureCycler ← LinesPreferredCycler[cameraPt, t, alignBag, sceneBag, svData, intersections];
pointsPreferred =>
featureCycler ← PointsPreferredCycler[cameraPt, t, alignBag, sceneBag, svData, intersections];
ENDCASE => ERROR;
}
ELSE {
featureCycler ← EmptyCycler[cameraPt, camera];
};
};
EmptyCycler: PROC [cameraPt: Point2d, camera: Camera] RETURNS [featureCycler: FeatureCycler] = {
featureCycler ← NEW[FeatureCyclerObj ← [
nearVEF: NIL,
count: 0,
index: -1,
cameraPt: cameraPt,
camera: camera
]];
};
FacesPreferred: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
Find the nearest face hit by the cursor ray. If the ray hits no faces, find the nearest face that passes within t screen units of the ray. Ideally, this would be implemented by a "nearest face to line" routine that would find the nearest edge of a face in the same way that Gargoyle finds the nearest endpoint of an edge. Failing this, we can just combine ray-tracing with an edge finder.
nearVEF: NearVertexEdgeAndFaces;
camera: Camera ← svData.camera;
count: NAT;
[nearVEF, count] ← MultiFacesPreferred[cameraPt, t, alignBag, sceneBag, svData];
IF count = 0 THEN {
parallel: BOOL;
[surfacePtWorld, normalWorld, parallel] ← RayMeetsCentralCameraPlane[cameraPt, camera];
hitData ← NIL;
RETURN;
};
SortByDepth[nearVEF];
RETURN PrepareWinner[nearVEF, 0];
};
LinesPreferred: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
Find the nearest line and any that are almost as near, if any lines exist with radius t. Choose one of these lines. If the winner is an edge, use the surface normal of the face that owns that edge, whose normal most nearly points toward the eyepoint.
If no lines exist within t, then choose the nearest face hit by the cursor ray, if any.
If still no object is found, use the background plane.
nearVEF: NearVertexEdgeAndFaces;
count: NAT;
camera: Camera ← svData.camera;
[nearVEF, count] ← MultiLinesPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections];
IF count = 0 THEN {
parallel: BOOL;
[surfacePtWorld, normalWorld, parallel] ← RayMeetsCentralCameraPlane[cameraPt, camera];
feature ← NIL;
hitData ← NIL;
RETURN;
};
IF count = 1 THEN RETURN PrepareWinner[nearVEF, 0]
ELSE {
Otherwise, let's do arbitration.
nearestDist: REAL ← -1;
bestSceneObject: INT ← -1;
neighborCount: NAT ← 1;
s: REAL = 0.072; -- 1/1000 inches
nearestDist ← nearVEF[0].dist;
Find how many nearest neighbors there are.
FOR i: NAT IN [1..count) DO
IF nearVEF[i].dist - nearestDist < s THEN neighborCount ← neighborCount + 1;
ENDLOOP;
IF neighborCount = 1 THEN RETURN PrepareWinner[nearVEF, 0];
bestSceneObject ← -1;
RETURN PrepareWinner[nearVEF, 0];
};
};
PointsPreferred: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
count: NAT;
nearVEF: NearVertexEdgeAndFaces;
[nearVEF, count] ← MultiPointsPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections];
IF count = 0 THEN {
parallel: BOOL;
camera: Camera ← svData.camera;
[surfacePtWorld, normalWorld, parallel] ← RayMeetsCentralCameraPlane[cameraPt, camera];
feature ← NIL;
hitData ← NIL;
RETURN;
};
IF count = 1 THEN RETURN PrepareWinner[nearVEF, 0]
ELSE {
Otherwise, let's do arbitration.
neighborCount: NAT ← 1;
s: REAL = 0.072; -- 1/1000 inches
nearestDist: REAL ← -1;
nearestDist ← nearVEF[0].dist;
FOR i: NAT IN [1..count) DO
IF nearVEF[i].dist - nearestDist < s THEN neighborCount ← neighborCount + 1;
ENDLOOP;
IF neighborCount = 1 THEN RETURN PrepareWinner[nearVEF, 0];
FOR i: NAT IN [0..neighborCount) DO
IF nearVEF[i].featureData.type = slice THEN {
RETURN PrepareWinner[nearVEF, i];
};
REPEAT
FINISHED => RETURN PrepareWinner[nearVEF, 0];
ENDLOOP;
};
};
PrepareWinner: PROC [nearVEF: NearVertexEdgeAndFaces, index: NAT] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
goodPoint: GoodPoint ← nearVEF[index];
surfacePtWorld ← goodPoint.point;
normalWorld ← goodPoint.normal;
feature ← goodPoint.featureData;
hitData ← goodPoint.hitData;
};
FacesPreferredCycler: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData] RETURNS [featureCycler: FeatureCycler] = {
Find the nearest face hit by the cursor ray. If the ray hits no faces, find the nearest face that passes within t screen units of the ray. Ideally, this would be implemented by a "nearest face to line" routine that would find the nearest edge of a face in the same way that Gargoyle finds the nearest endpoint of an edge. Failing this, we can just combine ray-tracing with an edge finder.
nearVEF: NearVertexEdgeAndFaces;
camera: Camera ← svData.camera;
count: NAT;
BEGIN
[nearVEF, count] ← MultiFacesPreferred[cameraPt, t, alignBag, sceneBag, svData];
IF count = 0 THEN RETURN[EmptyCycler[cameraPt, camera]];
GOTO MakeSimpleCycler;
SortByDepth[nearVEF];
EXITS
MakeSimpleCycler => {
featureCycler ← NEW[FeatureCyclerObj ← [
nearVEF: nearVEF,
count: count,
index: 0,
cameraPt: cameraPt,
camera: camera
]];
};
END;
};
LinesPreferredCycler: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL, maxDimension: [0..2] ← 2] RETURNS [featureCycler: FeatureCycler] = {
Find the nearest line and any that are almost as near, if any lines exist with radius t. Choose one of these lines. If the winner is an edge, use the surface normal of the face that owns that edge, whose normal most nearly points toward the eyepoint.
If no lines exist within t, then choose the nearest face hit by the cursor ray, if any.
If still no object is found, use the background plane.
nearVEF: NearVertexEdgeAndFaces;
count: NAT;
camera: Camera ← svData.camera;
BEGIN
[nearVEF, count] ← MultiLinesPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections, maxDimension];
IF count = 0 THEN RETURN[EmptyCycler[cameraPt, camera]];
IF count = 1 THEN GOTO MakeSimpleCycler
ELSE {
Otherwise, let's do arbitration.
nearestDist: REAL ← -1;
bestSceneObject: INT ← -1;
neighborCount: NAT ← 1;
s: REAL = 0.072; -- 1/1000 inches
nearestDist ← nearVEF[0].dist;
Find how many nearest neighbors there are.
FOR i: NAT IN [1..count) DO
IF nearVEF[i].dist - nearestDist < s THEN neighborCount ← neighborCount + 1;
ENDLOOP;
IF neighborCount = 1 THEN GOTO MakeSimpleCycler;
bestSceneObject ← -1;
featureCycler ← NEW[FeatureCyclerObj ← [
nearVEF: nearVEF,
count: count,
index: 0,
cameraPt: cameraPt,
camera: camera
]];
};
EXITS
MakeSimpleCycler => {
featureCycler ← NEW[FeatureCyclerObj ← [
nearVEF: nearVEF,
count: count,
index: 0,
cameraPt: cameraPt,
camera: camera
]];
};
END;
};
PointsPreferredCycler: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL, maxDimension: [0..2] ← 2] RETURNS [featureCycler: FeatureCycler] = {
count: NAT;
nearVEF: NearVertexEdgeAndFaces;
camera: Camera ← svData.camera;
BEGIN
[nearVEF, count] ← MultiPointsPreferred[cameraPt, t, alignBag, sceneBag, svData, intersections, maxDimension];
IF count = 0 THEN RETURN[EmptyCycler[cameraPt, camera]];
IF count = 1 THEN GOTO MakeSimpleCycler
ELSE {
Otherwise, let's do arbitration. Find the nearest slice if one is close enough. Otherwise, start with the nearest alignment object.
neighborCount: NAT ← 1;
s: REAL = 0.072; -- 1/1000 inches
nearestDist: REAL ← -1;
featureCycler ← NEW[FeatureCyclerObj ← [
nearVEF: nearVEF,
count: count,
index: -1,-- will be filled in below
cameraPt: cameraPt,
camera: camera
]];
nearestDist ← nearVEF[0].dist;
FOR i: NAT IN [1..count) DO
IF nearVEF[i].dist - nearestDist < s THEN neighborCount ← neighborCount + 1;
ENDLOOP;
IF neighborCount = 1 THEN GOTO MakeSimpleCycler;
FOR i: NAT IN [0..neighborCount) DO
IF nearVEF[i].featureData.type = slice THEN {
featureCycler.index ← i;
RETURN;
};
REPEAT
FINISHED => featureCycler.index ← 0;
ENDLOOP;
};
EXITS
MakeSimpleCycler => {
featureCycler ← NEW[FeatureCyclerObj ← [
nearVEF: nearVEF,
count: count,
index: 0,
cameraPt: cameraPt,
camera: camera
]];
};
END;
};
FirstFeature: PUBLIC PROC [featureCycler: FeatureCycler] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
RETURN GetFeature[featureCycler, 0];
};
NextFeature: PUBLIC PROC [featureCycler: FeatureCycler] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
RETURN GetFeature[featureCycler, 1];
};
PreviousFeature: PUBLIC PROC [featureCycler: FeatureCycler] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
RETURN GetFeature[featureCycler, -1];
};
GetFeature: PUBLIC PROC [featureCycler: FeatureCycler, move: [-1..1]] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
IF featureCycler.count = 0 THEN { -- return a backdrop position
parallel: BOOL;
cameraPt: Point2d ← featureCycler.cameraPt;
camera: Camera ← featureCycler.camera;
[surfacePtWorld, normalWorld, parallel] ← RayMeetsCentralCameraPlane[cameraPt, camera];
feature ← NIL;
hitData ← NIL;
}
ELSE {
featureCycler.index ← (featureCycler.index + move + featureCycler.count) MOD featureCycler.count;
[surfacePtWorld, normalWorld, feature, hitData] ← PrepareWinner[featureCycler.nearVEF, featureCycler.index];
};
};
MultiFacesPreferred: PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData] RETURNS [nearVEF: NearVertexEdgeAndFaces, count: NAT] = {
camera: Camera ← svData.camera;
bestFaces: BestPoints;
[bestFaces, count] ← FacesInNeighborhoodPlus[alignBag, sceneBag, cameraPt, svData, t];
IF count > 0 THEN {
nearVEF ← NEW[NearVertexEdgeAndFacesObj[1]];
nearVEF[0] ← bestFaces[0];
};
};
MultiLinesPreferred: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL, maxDimension: [0..2] ← 2] RETURNS [nearVEF: NearVertexEdgeAndFaces, count: NAT] = {
Find the nearest line to ray and those lines that are not much farther. If intersections is TRUE, compute the intersections of surfaces that are within the cone whose radius at the screen is innerR. (For now assume intersections is false).
bestVerts, bestEdges, bestFaces: BestPoints;
vertCount, edgeCount, faceCount, veCount: NAT;
IF EmptyBag[alignBag] AND EmptyTriggers[sceneBag] THEN
RETURN[NIL, 0];
IF maxDimension >= 2 THEN {
[bestFaces, faceCount] ← FacesInNeighborhoodPlus[alignBag, sceneBag, cameraPt, svData, t];
SortFaces[bestFaces, faceCount];
}
ELSE faceCount ← 0;
[bestEdges, edgeCount] ← EdgesInNeighborhoodPlus[alignBag, sceneBag, cameraPt, svData, t, 0];
SortCurves[bestEdges, edgeCount];
[bestVerts, vertCount] ← VertsInNeighborhoodPlus[bestEdges, edgeCount, alignBag, sceneBag, cameraPt, t, svData, FALSE];
SortPoints[bestVerts, vertCount];
veCount ← MIN[vertCount + edgeCount, maxFeatures];
count ← MIN[veCount + faceCount, maxFeatures];
nearVEF ← NEW[NearVertexEdgeAndFacesObj[count]];
MergePointsAndCurves[bestVerts, vertCount, bestEdges, edgeCount, nearVEF, veCount];
MergeVEWithFaces[bestFaces, faceCount, nearVEF, veCount, maxFeatures];
};
MultiPointsPreferred: PUBLIC PROC [cameraPt: Point2d, t: REAL, alignBag: AlignBag, sceneBag: TriggerBag, svData: SVData, intersections: BOOL, maxDimension: [0..2] ← 2] RETURNS [nearVEF: NearVertexEdgeAndFaces, count: NAT] = {
bestVerts, bestEdges, bestFaces: BestPoints;
vertCount, edgeCount, faceCount, veCount: NAT;
innerR: REAL ← t/2.0;
IF EmptyBag[alignBag] AND EmptyTriggers[sceneBag] THEN RETURN[NIL, 0];
IF maxDimension >= 2 THEN {
[bestFaces, faceCount] ← FacesInNeighborhoodPlus[alignBag, sceneBag, cameraPt, svData, t];
SortFaces[bestFaces, faceCount];
}
ELSE faceCount ← 0;
[bestEdges, edgeCount] ← EdgesInNeighborhoodPlus[alignBag, sceneBag, cameraPt, svData, t, innerR];
SortCurves[bestEdges, edgeCount];
[bestVerts, vertCount] ← VertsInNeighborhoodPlus[bestEdges, edgeCount, alignBag, sceneBag, cameraPt, t, svData, intersections];
SortPoints[bestVerts, vertCount];
IF vertCount > 0 AND bestVerts[0].dist < innerR THEN {
count ← vertCount;
nearVEF ← NEW[NearVertexEdgeAndFacesObj[count]];
NearPointsFromPoints[bestVerts, vertCount, nearVEF];
}
ELSE {
veCount ← MIN[vertCount + edgeCount, maxFeatures];
count ← MIN[veCount + faceCount, maxFeatures];
nearVEF ← NEW[NearVertexEdgeAndFacesObj[count]];
MergePointsAndCurves[bestVerts, vertCount, bestEdges, edgeCount, nearVEF, veCount];
MergeVEWithFaces[bestFaces, faceCount, nearVEF, veCount, maxFeatures];
};
};
FacesInNeighborhoodPlus: PROC [alignBag: AlignBag, sceneBag: TriggerBag, cameraPt: Point2d, svData: SVData, t: REAL] RETURNS [bestFaces: BestPoints, count: NAT] = {
goodPoint: GoodPoint ← NEW[GoodPointObj];
camera: Camera ← svData.camera;
searchDepth: SearchDepth ← SVState.GetSearchDepth[svData];
rayWorld: Ray ← GetWorldRayFromCameraPoint[cameraPt, camera]; -- from pool
[goodPoint.point, goodPoint.normal, goodPoint.featureData, goodPoint.hitData] ← RayAtSurfaces[rayWorld, cameraPt, t, sceneBag, camera, searchDepth];
goodPoint.dimension ← 2;
IF goodPoint.featureData = NIL THEN {
count ← 0;
}
ELSE {
count ← 1;
bestFaces ← NEW[BestPointsObj[1]];
goodPoint.dist ← 0.0;
bestFaces[0] ← goodPoint;
};
SVRay.ReturnRayToPool[rayWorld];
};
EdgesInNeighborhoodPlus: PROC [alignBag: AlignBag, sceneBag: TriggerBag, q: Point2d, svData: SVData, t: REAL, innerR: REAL] RETURNS [h: BestPoints, curveCount: NAT] = {
ProcessSlice: PROC [sliceD: SliceDescriptor, thisCurve: GoodPoint, featureData: FeatureData] = {
success: BOOL;
[thisCurve.dist, thisCurve.point, thisCurve.normal, thisCurve.hitData, success] ← SVAssembly.ClosestSegmentToLine[sliceD, q, line3d, t, camera];
IF success AND thisCurve.dist < t THEN {
thisCurve.featureData ← featureData;
thisCurve.dimension ← 1;
dTol ← MergeCurve[thisCurve, h];
};
};
ProcessLine: PROC [line: Line3d, thisCurve: GoodPoint, featureData: FeatureData] = {
thisCurve.dist ← SVLines3d.DistanceLineToLine[line, line3d];
IF thisCurve.dist < t THEN {
pAlignment, pRay: Point3d;
parallel: BOOL;
thisCurve.featureData ← featureData;
[pAlignment, pRay, parallel] ← SVLines3d.NearLinePoints[line, line3d];
thisCurve.point ← pAlignment;
thisCurve.normal ← SVVector3d.Sub[pRay, pAlignment];
thisCurve.hitData ← NIL;
dTol ← MergeCurve[thisCurve, h];
}
};
line: Line3d;
circle: Circle;
sliceD: SliceDescriptor;
featureData: FeatureData;
added: BOOLFALSE;
thisCurve: GoodPoint ← NEW[GoodPointObj];
dTol: REAL ← t;
camera: Camera ← svData.camera;
line3d: Line3d;
rayWorld: Ray ← GetWorldRayFromCameraPoint[q, camera]; -- from pool
h ← BestCurvesFromPool[svData, t, innerR];
line3d ← LineFromRay[rayWorld];
Align Bag
FOR slopeLines: LIST OF FeatureData ← alignBag.slopeLines, slopeLines.rest UNTIL slopeLines = NIL DO
featureData ← slopeLines.first;
line ← NARROW[featureData.shape, AlignmentLine].line;
ProcessLine[line, thisCurve, featureData];
ENDLOOP;
Scene Bag.
FOR slices: LIST OF FeatureData ← sceneBag.slices, slices.rest UNTIL slices = NIL DO
featureData ← slices.first;
sliceD ← NARROW[featureData.shape, SliceDescriptor];
ProcessSlice[sliceD, thisCurve, featureData];
ENDLOOP;
curveCount ← h.size;
IF h.overflow THEN {
CodeTimer.StartInt[$CurveOverflow, $Solidviews];
CodeTimer.StopInt[$CurveOverflow, $Solidviews];
};
SVRay.ReturnRayToPool[rayWorld];
}; -- end CurvesInNeighborhoodPlus
VertsInNeighborhoodPlus: PROC [bestCurves: BestPoints, curveCount: NAT, alignBag: AlignBag, sceneBag: TriggerBag, q: Point2d, t: REAL, svData: SVData, intersections: BOOL] RETURNS [h: BestPoints, pointCount: NAT] = {
thisPoint: GoodPoint;
ProcessPoint: PROC [thisPoint: GoodPoint, featureData: FeatureData] = { -- used for the anchor
dSquared: REAL;
dTolSquared: REAL ← dTol*dTol;
dSquared ← SVLines3d.Distance2PointToLine[thisPoint.point, line3d];
thisPoint.hitData ← NIL;
IF dSquared < dTolSquared THEN {
anchor: Skitter ← NARROW[featureData.shape];
thisPoint.dist ← RealFns.SqRt[dSquared];
thisPoint.normal ← Matrix3d.ZAxisOfMatrix[SVCaret.GetPosition[anchor]];
thisPoint.featureData ← featureData;
dTol ← MergePoint[thisPoint, h];
};
};
ProcessSlice: PROC [sliceD: SliceDescriptor, thisPoint: GoodPoint, featureData: FeatureData] = {
[thisPoint.dist, thisPoint.point, thisPoint.normal, thisPoint.hitData, success] ← SVAssembly.ClosestPointToLine[sliceD, q, line3d, dTol, camera];
IF success AND thisPoint.dist < dTol THEN {
thisPoint.featureData ← featureData;
thisPoint.dimension ← 0;
dTol ← MergePoint[thisPoint, h];
};
};
sliceD: SliceDescriptor;
featureData: FeatureData;
success: BOOLFALSE;
dTol: REAL ← t;
midpoints: BOOL ← SVState.GetMidpoints[svData];
camera: Camera ← svData.camera;
line3d: Line3d;
rayWorld: Ray ← GetWorldRayFromCameraPoint[q, camera]; -- from pool
thisPoint ← NEW[GoodPointObj];
h ← BestPointsFromPool[svData, t];
line3d ← LineFromRay[rayWorld];
IF intersections THEN
dTol ← FindIntersections[bestCurves, curveCount, thisPoint, q, dTol, h];
IF intersections AND midpoints THEN
dTol ← FindMidpoints[bestCurves, curveCount, thisPoint, q, dTol, h];
FOR slices: LIST OF FeatureData ← sceneBag.slices, slices.rest UNTIL slices = NIL DO
featureData ← slices.first;
sliceD ← NARROW[featureData.shape, SliceDescriptor];
ProcessSlice[sliceD, thisPoint, featureData];
ENDLOOP;
featureData ← alignBag.anchor;
IF featureData # NIL THEN {
anchor: Skitter ← NARROW[featureData.shape];
IF NOT SVCaret.Exists[anchor] THEN ERROR;
thisPoint.point ← Matrix3d.OriginOfMatrix[SVCaret.GetPosition[anchor]];
ProcessPoint[thisPoint, featureData];
};
pointCount ← h.size;
IF h.overflow THEN {
CodeTimer.StartInt[$PointOverflow, $Solidviews];
CodeTimer.StopInt[$PointOverflow, $Solidviews];
};
SVRay.ReturnRayToPool[rayWorld];
};
MergePoint: PROC [thisPoint: GoodPoint, h: BestPoints] RETURNS [dTol: REAL] = {
d: REAL ← thisPoint.dist;
n: NAT = maxFeatures;
BEGIN
SELECT TRUE FROM
h.size < n => GOTO Add;
h.size = n AND d <= h.dTol => GOTO ReplaceOrOverflow;
h.size = n AND d > h.dTol => GOTO Toss; -- the caller is not taking our hints and is passing us trash
ENDCASE => SIGNAL Problem[msg: "Impossible case."];
EXITS
Add => {
h[h.size]^ ← thisPoint^;
h.size ← h.size + 1;
h.min ← MIN[h.min, d];
dTol ← h.dTol ← h.min+h.s;
};
ReplaceOrOverflow => {
iWorst: NAT;
worstDist: REAL ← 0.0;
Replace the worst element with the new one if the new is better.
iWorst ← 0; worstDist ← 0.0;
FOR i: NAT IN [0..maxFeatures-1] DO
IF h[i].dist > worstDist THEN {iWorst ← i; worstDist ← h[i].dist};
ENDLOOP;
IF d < worstDist THEN { -- do the replace
h[iWorst].dist ← d;
h[iWorst]^ ← thisPoint^;
h.bestTossed ← MIN[h.bestTossed, worstDist];
h.min ← MIN[h.min, d];
dTol ← h.dTol ← h.min+h.s;
h.overflow ← h.bestTossed <= dTol;
}
ELSE { -- toss the new item
dTol ← h.dTol;
h.bestTossed ← MIN[h.bestTossed, d];
h.overflow ← TRUE;
};
};
Toss => {
dTol ← h.dTol;
h.bestTossed ← MIN[h.bestTossed, d];
h.overflow ← h.bestTossed <= dTol;
};
END;
};
MergeCurve: PROC [thisPoint: GoodPoint, h: BestPoints] RETURNS [dTol: REAL] = {
d: REAL ← thisPoint.dist;
n: NAT = maxFeatures;
BEGIN
SELECT TRUE FROM
h.size < n => GOTO Add;
h.size = n AND d <= h.dTol => GOTO ReplaceOrOverflow;
h.size = n AND d > h.dTol => GOTO Toss; -- the caller is not taking our hints and is passing us trash
ENDCASE => SIGNAL Problem[msg: "Impossible case."];
EXITS
Add => {
h[h.size]^ ← thisPoint^;
h.size ← h.size + 1;
h.min ← MIN[h.min, d];
dTol ← h.dTol ← MAX[h.min+h.s, h.innerR];
};
ReplaceOrOverflow => {
iWorst: NAT;
worstDist: REAL ← 0.0;
Replace the worst element with the new one if the new is better.
iWorst ← 0; worstDist ← 0.0;
FOR i: NAT IN [0..maxFeatures-1] DO
IF h[i].dist > worstDist THEN {iWorst ← i; worstDist ← h[i].dist};
ENDLOOP;
IF d < worstDist THEN { -- do the replace
h[iWorst].dist ← d;
h[iWorst]^ ← thisPoint^;
h.bestTossed ← MIN[h.bestTossed, worstDist];
h.min ← MIN[h.min, d];
dTol ← h.dTol ← MAX[h.min+h.s, h.innerR];
h.overflow ← h.bestTossed <= dTol;
}
ELSE { -- toss the new item
dTol ← h.dTol;
h.bestTossed ← MIN[h.bestTossed, d];
h.overflow ← TRUE;
};
};
Toss => {
dTol ← h.dTol;
h.bestTossed ← MIN[h.bestTossed, d];
h.overflow ← h.bestTossed <= dTol;
};
END;
};
NearPointsFromPoints: PROC [bestPoints: BestPoints, pointCount: NAT, nearVEF: NearVertexEdgeAndFaces] = {
FOR i: NAT IN [0..pointCount-1] DO
nearVEF[i] ← bestPoints[i];
ENDLOOP;
};
MergePointsAndCurves: PROC [bestPoints: BestPoints, pointCount: NAT, bestCurves: BestPoints, curveCount: NAT, nearVEF: NearVertexEdgeAndFaces, count: NAT] = {
Merge the bestPoints and the bestCurves. There will be count elements in the result.
pointIndex, curveIndex: NAT;
pointDist, curveDist: REAL;
pointIndex ← curveIndex ← 0;
FOR i: NAT IN [0..count-1] DO
IF pointIndex >= pointCount THEN GOTO NoMorePoints;
IF curveIndex >= curveCount THEN GOTO NoMoreCurves;
pointDist ← bestPoints[i].dist;
curveDist ← bestCurves[i].dist;
IF pointDist <= curveDist THEN {
nearVEF[i] ← bestPoints[pointIndex];
pointIndex ← pointIndex + 1;
}
ELSE {
nearVEF[i] ← bestCurves[curveIndex];
curveIndex ← curveIndex + 1;
};
REPEAT
NoMorePoints => { -- finish up with Curves data
FOR k: NAT ← i, k+1 UNTIL k >= count DO
nearVEF[k] ← bestCurves[curveIndex];
curveIndex ← curveIndex + 1;
ENDLOOP};
NoMoreCurves => { -- finish up with points data
FOR k: NAT ← i, k+1 UNTIL k >= count DO
nearVEF[k] ← bestPoints[pointIndex];
pointIndex ← pointIndex + 1;
ENDLOOP};
ENDLOOP;
};
MergeVEWithFaces: PROC [bestFaces: BestPoints, faceCount: NAT, nearVEF: NearVertexEdgeAndFaces, oldCount, maxCount: NAT] = {
Add the faces onto the end.
faceIndex, totalCount: NAT;
totalCount ← MIN[oldCount + faceCount, maxCount];
faceIndex ← 0;
FOR i: NAT IN [oldCount..totalCount-1] DO
nearVEF[i] ← bestFaces[faceIndex];
faceIndex ← faceIndex + 1;
ENDLOOP;
};
SortPoints: PROC [bestPoints: BestPoints, pointCount: NAT] = {
Sort the points in order of increasing distance. Since n is likely to be small, bubble sort is sensible:
temp: GoodPointObj;
FOR i: NAT IN [0..pointCount-2] DO
FOR j: NAT IN [1..pointCount-i-1] DO
IF bestPoints[j-1].dist > bestPoints[j].dist THEN {
temp ← bestPoints[j]^;
bestPoints[j]^ ← bestPoints[j-1]^;
bestPoints[j-1]^ ← temp;
};
ENDLOOP;
ENDLOOP;
};
SortCurves: PROC [bestCurves: BestPoints, curveCount: NAT] = {
Sort the curves in order of increasing distance. Since n is likely to be small, bubble sort is sensible:
temp: GoodPointObj;
FOR i: NAT IN [0..curveCount-2] DO
FOR j: NAT IN [1..curveCount-i-1] DO
IF bestCurves[j-1].dist > bestCurves[j].dist THEN {
temp ← bestCurves[j]^;
bestCurves[j]^ ← bestCurves[j-1]^;
bestCurves[j-1]^ ← temp;
};
ENDLOOP;
ENDLOOP;
};
SortFaces: PROC [bestFaces: BestPoints, faceCount: NAT] = {
};
PointsOrSurfaces: PUBLIC PROC [cameraPt: Point2d, t: REAL, sceneBag: TriggerBag, camera: Camera, searchDepth: SearchDepth, gravityType: GravityType] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
pointsPtWorld: Point3d;
pointsNormalWorld: Vector3d;
pointsFeature: FeatureData;
parallel: BOOL;
pointsHitData: REF ANY;
rayWorld: Ray ← GetWorldRayFromCameraPoint[cameraPt, camera]; -- from pool
[surfacePtWorld, normalWorld, feature, hitData] ← RayAtSurfaces[rayWorld, cameraPt, t, sceneBag, camera, searchDepth];
[pointsPtWorld, pointsNormalWorld, pointsFeature, pointsHitData] ← RayAtPoints[rayWorld, cameraPt, t, sceneBag, camera, gravityType];
IF pointsFeature # NIL AND WithinTolerance[pointsPtWorld, rayWorld, t] THEN {
surfacePtWorld ← pointsPtWorld;
IF pointsFeature # feature THEN {
normalWorld ← pointsNormalWorld;
feature ← pointsFeature;
};
hitData ← pointsHitData;
}
ELSE IF feature # NIL THEN {
}
ELSE {
[surfacePtWorld, normalWorld, parallel] ← RayMeetsCentralCameraPlane[cameraPt, camera];
hitData ← NIL;
};
SVRay.ReturnRayToPool[rayWorld];
};
LineFromRay: PROC [ray: Ray] RETURNS [line: Line3d] = {
basePt: Point3d;
direction: Vector3d;
[basePt, direction] ← SVRay.GetWorldRay[ray];
line ← SVLines3d.LineFromPointAndVector[basePt, direction];
};
WithinTolerance: PROC [point: Point3d, rayWorld: Ray, t: REAL] RETURNS [BOOL] = {
line: Line3d;
dist: REAL;
line ← LineFromRay[rayWorld];
dist ← SVLines3d.DistancePointToLine[point, line];
RETURN[dist <= t];
};
GetWorldRayFromCameraPoint: PROC [cameraPt: Point2d, camera: Camera] RETURNS [rayWorld: Ray] = {
rayCamera: Ray;
cameraWorld: Matrix4by4 ← CoordSys.WRTWorld[camera.coordSys];
rayCameraSVRay.GetRayFromPool[]; -- allocates ray from pool
SVRay.StuffCameraRay[rayCamera, cameraPt, camera];
rayWorldSVRay.TransformRayToWorld[rayCamera, cameraWorld]; -- allocates ray from pool
SVRay.ReturnRayToPool[rayCamera];
};
RayAtSurfaces: PROC [rayWorld: Ray, cameraPt: Point2d, t: REAL, sceneBag: TriggerBag, camera: Camera, searchDepth: SearchDepth] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d, feature: FeatureData, hitData: REF ANY] = {
class: Classification;
primitive: Primitive;
assembly: Slice;
class ← SingleRay[rayWorld, cameraPt, sceneBag, camera, TRUE, NIL]; -- class from pool
IF sceneBag.scene # NIL THEN
[assembly, primitive] ← AssemblyAndPrimitiveAtSearchDepth[class, searchDepth, sceneBag.scene.assembly];
IF class.count > 0 THEN
[surfacePtWorld, normalWorld] ← SurfacePointAndNormalAtSearchDepth[class, rayWorld, searchDepth, sceneBag.scene.assembly];
feature ← FindFeature[assembly, sceneBag];
hitData ← HitDataAtSearchDepth[class, searchDepth, sceneBag.scene.assembly];
SVCastRays.ReturnClassToPool[class];
};
FindFeature: PROC [assembly: Slice, sceneBag: TriggerBag] RETURNS [feature: FeatureData] = {
sliceD: SliceDescriptor;
IF assembly = NIL THEN RETURN[NIL];
FOR list: LIST OF FeatureData ← sceneBag.slices, list.rest UNTIL list = NIL DO
sliceD ← NARROW[list.first.shape];
IF sliceD.slice = assembly THEN RETURN[list.first];
ENDLOOP;
RETURN[NIL];
};
AssemblyAndPrimitiveAtSearchDepth: PROC [class: Classification, searchDepth: SearchDepth, root: Slice] RETURNS [assembly: Slice, primitive: Primitive] = {
SELECT searchDepth FROM
first => [assembly, primitive] ← SVCastRays.NthAssemblyAndPrimitive[class, 1];
lastOfFirst => [assembly, primitive] ← SVCastRays.NthAssemblyAndPrimitive[class, 1];
last => [assembly, primitive] ← SVCastRays.NthAssemblyAndPrimitive[class, class.count];
lastOfLevel1 => [assembly, primitive] ← SVCastRays.LastTopLevelAssemAndPrim[class, root];
ENDCASE => ERROR;
};
SurfacePointAndNormalAtSearchDepth: PROC [class: Classification, rayWorld: Ray, searchDepth: SearchDepth, root: Slice] RETURNS [surfacePtWorld: Point3d, normalWorld: Vector3d] = {
SELECT searchDepth FROM
first =>
[surfacePtWorld, normalWorld] ← SVCastRays.NthSurfacePointAndNormal[class, rayWorld, 1];
lastOfFirst =>
[surfacePtWorld, normalWorld] ← SVCastRays.LastOfFirstPointAndNormal[class, rayWorld];
last =>
IF class.count = 0 THEN ERROR
ELSE [surfacePtWorld, normalWorld] ← SVCastRays.NthSurfacePointAndNormal[class, rayWorld, class.count];
lastOfLevel1 =>
[surfacePtWorld, normalWorld] ← SVCastRays.LastTopLevelPointAndNormal[class, rayWorld, root];
ENDCASE => ERROR;
};
HitDataAtSearchDepth: PROC [class: Classification, searchDepth: SearchDepth, root: Slice] RETURNS [hitData: REF ANY] = {
SELECT searchDepth FROM
first =>
hitData ← SVCastRays.NthHitData[class, 1];
lastOfFirst =>
hitData ← SVCastRays.LastOfFirstHitData[class];
last =>
IF class.count = 0 THEN ERROR
ELSE hitData ← SVCastRays.NthHitData[class, class.count];
lastOfLevel1 =>
hitData ← SVCastRays.LastTopLevelHitData[class, root];
ENDCASE => ERROR;
};
SingleRay: PUBLIC PROC [rayWorld: Ray, cameraPt: Point2d, sceneBag: TriggerBag, camera: Camera, consolidate: BOOLTRUE, feedback: FeedbackData, makeStream: BOOLFALSE] RETURNS [class: Classification] = {
tree: CSGTree ← sceneBag.tree;
topNode: REF ANY;
IF tree = NIL THEN {
class ← SVCastRays.GetClassFromPool[];
SVCastRays.MakeClassAMiss[class];
RETURN;
};
IF tree.outOfDate THEN {
tree ← DisplayListToTree.AssemblyToTree[sceneBag.scene.assembly, sceneBag.scene, camera, tree, sceneBag.ignoreMoving];
[] ← Preprocess3d.PreprocessForInteraction[tree, camera];
tree.outOfDate ← FALSE;
};
topNode ← tree.son;
class ← SVCastRays.RayCast[cameraPt, rayWorld, topNode, consolidate, feedback, makeStream, 0];
}; -- end of SingleRay
RayAtPoints: PROC [ray: Ray, cameraPt: Point2d, t: REAL, sceneBag: TriggerBag, camera: Camera, gravityType: GravityType] RETURNS [bestPoint: Point3d, bestNormal: Vector3d, bestFeature: FeatureData, bestHitData: REF ANY] = {
line3d: Line3d;
bestDist, thisDist: REAL;
pointWorld: Point3d;
normalWorld: Vector3d;
feature: FeatureData;
sliceD: SliceDescriptor;
hitData: REF ANY;
success: BOOL;
scene: Scene ← sceneBag.scene;
line3d ← LineFromRay[ray];
bestDist ← Real.LargestNumber;
bestFeature ← NIL;
IF gravityType = linesPreferred THEN {
FOR list: LIST OF FeatureData ← sceneBag.slices, list.rest UNTIL list = NIL DO
feature ← list.first;
sliceD ← NARROW[feature.shape];
[thisDist, pointWorld, normalWorld, hitData, success] ← SVAssembly.ClosestSegmentToLine[sliceD, cameraPt, line3d, t, camera];
IF success AND thisDist < bestDist THEN {
bestDist ← thisDist;
bestPoint ← pointWorld;
bestNormal ← normalWorld;
bestHitData ← hitData;
bestFeature ← feature;
};
ENDLOOP;
};
FOR list: LIST OF FeatureData ← sceneBag.slices, list.rest UNTIL list = NIL DO
feature ← list.first;
sliceD ← NARROW[feature.shape];
[thisDist, pointWorld, normalWorld, hitData, success] ← SVAssembly.ClosestPointToLine[sliceD, cameraPt, line3d, t, camera];
IF success AND thisDist < bestDist THEN {
bestDist ← thisDist;
bestPoint ← pointWorld;
bestNormal ← normalWorld;
bestHitData ← hitData;
bestFeature ← feature;
};
ENDLOOP;
bestNormal ← Matrix3d.ZAxisOfMatrix[CoordSys.WRTWorld[camera.coordSys]];
};
RayMeetsCameraPlane: PROC [cameraPt: Point2d, depth: REAL, camera: Camera] RETURNS [planePtCamera: Point3d, parallel: BOOL] = {
rayWorld: Ray;
worldCamera: Matrix4by4;
planePtWorld: Point3d;
rayWorldSVRay.GetRayFromPool[];
SVRay.StuffWorldRayFromCamera[rayWorld, cameraPt, camera];
[planePtWorld, parallel] ← SVCastRays.RayMeetsPlaneOfCoordSystem[camera.coordSys, rayWorld, 3, depth];
worldCamera ← CoordSys.FindAInTermsOfB[CoordSys.Parent[camera.coordSys], camera.coordSys];
planePtCamera ← Matrix3d.Update[planePtWorld, worldCamera];
SVRay.ReturnRayToPool[rayWorld];
};
RayMeetsCentralCameraPlane: PROC [cameraPt: Point2d, camera: Camera] RETURNS [pointWorld: Point3d, normalWorld: Vector3d, parallel: BOOL] = {
worldCAMERA: Matrix4by4 ← CoordSys.FindWorldInTermsOf[camera.coordSys];
originCAMERA: Point3d ← Matrix3d.OriginOfMatrix[worldCAMERA];
depth: REAL ← originCAMERA[3];
rayWorld: Ray;
rayWorldSVRay.GetRayFromPool[];
SVRay.StuffWorldRayFromCamera[rayWorld, cameraPt, camera];
[pointWorld, parallel] ← SVCastRays.RayMeetsPlaneOfCoordSystem[camera.coordSys, rayWorld, 3, depth];
normalWorld ← Matrix3d.ZAxisOfMatrix[CoordSys.WRTWorld[camera.coordSys]];
SVRay.ReturnRayToPool[rayWorld];
};
NewGravityPool: PUBLIC PROC [] RETURNS [gravityPool: REF ANY] = {
pool: MultiGravityPool ← NEW[MultiGravityPoolObj];
pool.distances ← NEW[NearDistancesObj[maxFeatures]];
pool.features ← NEW[NearFeaturesObj[maxFeatures]];
pool.bestpoints ← NEW[BestPointsObj[maxFeatures]];
pool.bestcurves ← NEW[BestPointsObj[maxFeatures]];
FOR i: NAT IN [0..maxFeatures) DO
pool.bestpoints[i] ← NEW[GoodPointObj];
pool.bestcurves[i] ← NEW[GoodPointObj];
ENDLOOP;
RETURN[pool];
};
BestCurvesFromPool: PROC [svData: SVData, t: REAL, innerR: REAL] RETURNS [h: BestPoints] = {
h ← NARROW[svData.gravityPool, MultiGravityPool].bestcurves;
h.size ← 0;
h.max ← 0;
h.min ← Real.LargestNumber;
h.dTol ← t;
h.innerR ← innerR;
h.s ← 0.072; -- 1/1000 inches
h.bestTossed ← Real.LargestNumber;
h.overflow ← FALSE;
FOR i: NAT IN [0..maxFeatures-1] DO
h[i].dist ← Real.LargestNumber;
h[i].featureData ← NIL;
ENDLOOP;
};
BestPointsFromPool: PROC [svData: SVData, t: REAL] RETURNS [h: BestPoints] = {
h ← NARROW[svData.gravityPool, MultiGravityPool].bestpoints;
h.size ← 0;
h.max ← 0;
h.min ← Real.LargestNumber;
h.dTol ← t;
h.s ← 0.072; -- 1/1000 inches
h.bestTossed ← Real.LargestNumber;
h.overflow ← FALSE;
FOR i: NAT IN [0..maxFeatures-1] DO
h[i].dist ← Real.LargestNumber;
h[i].featureData ← NIL;
ENDLOOP;
};
Init: PROC = {
};
InitStats: PROC = {
interval: CodeTimer.Interval;
interval ← CodeTimer.CreateInterval[$RayMap];
CodeTimer.AddInt[interval, $Solidviews];
};
InitStats[];
Init[];
END.