SVAlignImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on March 11, 1987 4:59:39 pm PST
Contents: Maintains the three snap-dragging gravity bags: triggerBag, sceneBag, and alignBag for Solidviews.
DIRECTORY
AtomButtons, AtomButtonsTypes, CodeTimer, Feedback, FunctionCache, Imager, ImagerBackdoor, Lines2d, SVMatrix3d, Process, Rope, SV2d, SV3d, SVAlign, SVAssembly, SVBoundSphere, SVCaret, SVGraphics, SVInterfaceTypes, SVLines3d, SVModelTypes, SVScene, SVSceneTypes, SVSelect, SVSpheres, SVState, SVUtility, SVVector3d;
SVAlignImpl:
CEDAR
PROGRAM
IMPORTS AtomButtons, CodeTimer, Feedback, Imager, ImagerBackdoor, SVMatrix3d, Process, SVAssembly, SVBoundSphere, SVCaret, SVGraphics, SVLines3d, SVScene, SVSelect, SVSpheres, SVState, SVUtility, SVVector3d
EXPORTS SVAlign
=
BEGIN
AlignBag: TYPE = REF AlignBagObj;
AlignBagObj: TYPE = SVInterfaceTypes.AlignBagObj;
AlignmentLine: TYPE = REF AlignmentLineObj;
AlignmentLineObj: TYPE = SVInterfaceTypes.AlignmentLineObj;
AlignmentSphere: TYPE = REF AlignmentSphereObj;
AlignmentSphereObj: TYPE = SVInterfaceTypes.AlignmentSphereObj;
AssemblyGenerator: TYPE = SVScene.AssemblyGenerator;
Camera: TYPE = SVModelTypes.Camera;
FeatureData: TYPE = SVInterfaceTypes.FeatureData;
FeatureDataObj: TYPE = SVSceneTypes.FeatureDataObj;
Filters: TYPE = SVInterfaceTypes.Filters;
FilterSliceProc: TYPE = SVAlign.FilterSliceProc;
Line: TYPE = Lines2d.Line;
Line3d: TYPE = SV3d.Line3d;
Point3d: TYPE = SV3d.Point3d;
PointGenerator: TYPE = SVSceneTypes.PointGenerator;
PointPairGenerator: TYPE = SVSceneTypes.PointPairGenerator;
ScalarButtonClient: TYPE = AtomButtonsTypes.ScalarButtonClient;
Scene: TYPE = SVSceneTypes.Scene;
Skitter: TYPE = SVSceneTypes.Skitter;
Slice: TYPE = SVSceneTypes.Slice;
SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor;
SliceDescriptorGenerator: TYPE = SVSceneTypes.SliceDescriptorGenerator;
SliceParts: TYPE = SVSceneTypes.SliceParts;
Sphere: TYPE = SV3d.Sphere;
TriggerBag: TYPE = REF TriggerBagObj;
TriggerBagObj: TYPE = SVInterfaceTypes.TriggerBagObj;
SVData: TYPE = SVInterfaceTypes.SVData;
Vector2d: TYPE = SV2d.Vector2d;
Vector3d: TYPE = SV3d.Vector3d;
Problem: SIGNAL [msg: Rope.ROPE] = Feedback.Problem;
alignmentColor: Imager.Color ← ImagerBackdoor.MakeStipple[145065B];
checkerColor: Imager.Color ← ImagerBackdoor.MakeStipple[122645B];
The TriggerBag, the SceneBag and the AlignBag
The set of alignment objects is computed in three steps (see Figure 1). First, we determine which joints, control points, and segments in the scene are triggers. We put these in triggerBag. Next we determine which scene objects are gravity active. We put these in sceneBag. Finally, we determine the set of alignment objects from the triggerBag using the current filters and from the sceneBag if midpoints are activated. This set is represented by the selected slopes, angles, radii, and distances in the user interface.
The bags are recomputed at these times:
triggerBag: Updated whenever an Add or Drag operation is performed, or whenever anything becomes hot or cold.
sceneBag: Updated whenever an Add or Drag operation is performed.
alignBag. Updated whenever an Add or Drag operation is performed, whenever anything becomes hot or cold, or whenever the set of current filters changes.
The bags are represented as follows:
triggerBag and sceneBag: several LIST OF FeatureData. The FeatureData will point to a SliceDescriptor, --an SliceDescriptor,-- or the anchor.
alignBag: several LIST OF FeatureData. The FeatureData will point to an AlignmentLine, an AlignmentCircle, an AlignmentPoint, or a Skitter (e.g. the anchor).
[Artwork node; type 'ArtworkInterpress on' to command tool]
Creating and filling a TriggerBag
emptyTriggerBag: PUBLIC TriggerBag;
CreateTriggerBag:
PUBLIC
PROC [scene: Scene]
RETURNS [triggerBag: TriggerBag] = {
triggerBag ← NEW[TriggerBagObj ← [tree: scene.tree, ignoreMoving: FALSE, scene: scene, slices: NIL, anchor: NIL]];
};
FlushTriggerBag:
PUBLIC PROC [triggerBag: TriggerBag] = {
triggerBag.slices ← NIL;
triggerBag.anchor ← NIL;
};
CopyTriggerBag:
PUBLIC
PROC [triggerBag: TriggerBag]
RETURNS [copy: TriggerBag] = {
copy ← CreateTriggerBag[triggerBag.scene];
copy.ignoreMoving ← triggerBag.ignoreMoving;
copy.slices ← SVUtility.CopyFeatureList[triggerBag.slices];
copy.anchor ← triggerBag.anchor;
};
FeatureFromSlice:
PUBLIC
PROC [slice: Slice, parts: SliceParts ←
NIL]
RETURNS [feature: FeatureData] = {
sliceParts: SliceParts ← IF parts=NIL THEN SVAssembly.NewParts[slice, NIL, [0,0,0], slice].parts ELSE parts;
sliceD: SliceDescriptor ← SVAssembly.DescriptorFromParts[slice, sliceParts];
feature ← NEW[FeatureDataObj];
feature.type ← slice;
feature.shape ← sliceD;
};
FeatureFromAnchor:
PUBLIC
PROC [anchor: Skitter]
RETURNS [feature: FeatureData] = {
feature ← NEW[FeatureDataObj];
feature.type ← anchor; -- that is, anchor => the member of the enumerated type
feature.shape ← anchor; -- that is, anchor => the parameter
};
FillStaticTriggerBag:
PUBLIC
PROC [anchor: Skitter, scene: Scene, heuristics:
BOOL, triggerBag: TriggerBag] = {
AddAnchorTrigger[anchor, triggerBag];
AddAllHotSlices[scene, triggerBag];
};
FillDynamicTriggerBag:
PUBLIC
PROC [anchor: Skitter, scene: Scene, heuristics:
BOOL, triggerBag: TriggerBag] = {
AddAnchorTrigger[anchor, triggerBag];
AddAllHotSlices[scene, triggerBag];
AddHeuristics[scene, heuristics, $Drag, triggerBag];
RemoveMoving[scene, triggerBag];
};
Filling the SceneBag
FillStaticSceneBag:
PUBLIC
PROC [scene: Scene, sceneBag: TriggerBag] = {
sceneBag.tree ← scene.tree;
sceneBag.ignoreMoving ← FALSE;
IF sceneBag.tree # NIL THEN sceneBag.tree.outOfDate ← TRUE;
sceneBag.scene ← scene;
AddAllSlices[scene, sceneBag];
ComputeAllBoundingBoxes[sceneBag]; -- if we wish to be like Solidviews
};
FillDynamicSceneBag:
PUBLIC
PROC [scene: Scene, sceneBag: TriggerBag] = {
sceneBag.ignoreMoving ← TRUE;
IF sceneBag.tree # NIL THEN sceneBag.tree.outOfDate ← TRUE;
AddAllSlices[scene, sceneBag];
RemoveMoving[scene, sceneBag];
ComputeAllBoundingBoxes[sceneBag]; -- if we wish to be like Solidviews
};
AlignBag
emptyAlignBag:
PUBLIC AlignBag;
Use this as an (immutable) empty TriggerBag.
CreateAlignBag:
PUBLIC
PROC []
RETURNS [alignBag: AlignBag] = {
alignBag ←
NEW[AlignBagObj ← [
slopeLines: NIL,
slopePlanes: NIL,
spheres: NIL,
anchor: NIL
]];
};
FlushAlignBag:
PUBLIC
PROC [alignBag: AlignBag] = {
alignBag.slopeLines ← NIL;
alignBag.slopePlanes ← NIL;
alignBag.spheres ← NIL;
alignBag.anchor ← NIL;
};
JointAddSlopeLine:
PUBLIC
PROC [azimuth, slope:
REAL, point: Point3d, alignBag: AlignBag]
RETURNS [feature: FeatureData] = {
For now, each slope line only remembers one of the joints which it passes thru.
line: Line3d;
direction: Vector3d;
oldFeature: FeatureData ← FindLine[point, azimuth, slope, alignBag.slopeLines];
IF oldFeature #
NIL
THEN {
alignmentLine: AlignmentLine ← NARROW[oldFeature.shape];
alignmentLine.triggerPoints ← CONS[point, alignmentLine.triggerPoints];
feature ← NIL;
}
ELSE {
alignmentLine: AlignmentLine;
direction ← SVVector3d.VectorFromAngles[azimuth, slope];
line ← SVLines3d.LineFromPointAndVector[point, direction];
alignmentLine ← NEW[AlignmentLineObj ← [line: line, azimuth: azimuth, slope: slope, triggerPoints: CONS[point, NIL]]];
feature ← NEW[FeatureDataObj];
feature.type ← slopeLine;
feature.shape ← alignmentLine;
AddAlignment[feature, alignBag];
};
};
JointAddSphere:
PUBLIC
PROC [radius:
REAL, point: Point3d, alignBag: AlignBag]
RETURNS [feature: FeatureData] = {
For now, each sphere only remembers one of the joints that triggers it.
oldFeature: FeatureData ← FindSphere[point, radius, alignBag.spheres];
IF oldFeature #
NIL
THEN {
alignmentSphere: AlignmentSphere ← NARROW[oldFeature.shape];
alignmentSphere.triggerPoints ← CONS[point, alignmentSphere.triggerPoints];
feature ← NIL;
}
ELSE {
alignmentSphere: AlignmentSphere;
sphere: Sphere ← SVSpheres.SphereFromPointAndRadius[point, radius];
alignmentSphere ← NEW[AlignmentSphereObj ← [sphere: sphere, triggerPoints: CONS[point, NIL]]];
feature ← NEW[FeatureDataObj];
feature.type ← sphere;
feature.shape ← alignmentSphere;
AddAlignment[feature, alignBag];
};
};
FindLine:
PRIVATE
PROC [point: Point3d, azimuth, slope:
REAL, list:
LIST
OF FeatureData]
RETURNS [coincident: FeatureData] = {
epsilon: REAL = 1.0e-5;
line3d: Line3d;
alignmentLine: AlignmentLine;
FOR l:
LIST
OF FeatureData ← list, l.rest
UNTIL l =
NIL
DO
alignmentLine ← NARROW[l.first.shape];
line3d ← alignmentLine.line;
IF alignmentLine.azimuth = azimuth
AND alignmentLine.slope = slope
AND
SVLines3d.DistancePointToLine[point, line3d] < epsilon THEN RETURN[l.first];
ENDLOOP;
RETURN[NIL];
};
FindSphere:
PRIVATE
PROC [point: Point3d, radius:
REAL, list:
LIST
OF FeatureData]
RETURNS [coincident: FeatureData] = {
epsilon: REAL = 1.0e-5;
sphere: Sphere;
alignmentSphere: AlignmentSphere;
FOR l:
LIST
OF FeatureData ← list, l.rest
UNTIL l =
NIL
DO
alignmentSphere ← NARROW[l.first.shape];
sphere ← alignmentSphere.sphere;
IF sphere.radius = radius
AND
SVVector3d.Distance[point, sphere.center] < epsilon THEN RETURN[l.first];
ENDLOOP;
RETURN[NIL];
};
FillStaticAlignBag:
PUBLIC
PROC [triggerBag: TriggerBag, sceneBag: TriggerBag, filters: Filters, hideAlignments:
BOOL, midpoints:
BOOL, alignBag: AlignBag] = {
BuiltInFilters[triggerBag, filters, hideAlignments, alignBag];
};
FillDynamicAlignBag:
PUBLIC
PROC [triggerBag: TriggerBag, sceneBag: TriggerBag, filters: Filters, hideAlignments:
BOOL, midpoints:
BOOL, action:
ATOM, alignBag: AlignBag] = {
BuiltInFilters[triggerBag, filters, hideAlignments, alignBag];
};
Filling all three Bags at Once
SetStaticBags:
PUBLIC
PROC [svData: SVData] = {
triggerBag: TriggerBag ← svData.hitTest.triggerBag;
alignBag: AlignBag ← svData.hitTest.alignBag;
sceneBag: TriggerBag ← svData.hitTest.sceneBag;
scene: Scene ← svData.scene;
anchor: Skitter ← scene.anchor;
heuristics: BOOL ← SVState.GetHeuristics[svData];
filters: Filters ← svData.hitTest;
hideAlignments: BOOL ← NOT SVState.GetShowAlignments[svData];
midpoints: BOOL ← SVState.GetMidpoints[svData];
IF hideAlignments
THEN {
FlushAlignBag[alignBag];
FlushTriggerBag[sceneBag];
FillStaticSceneBag[scene, sceneBag];
}
ELSE {
CodeTimer.StartInt[$SetBagsForAction, $Solidviews];
Fill TriggerBag
FlushTriggerBag[triggerBag];
FillStaticTriggerBag[anchor, scene, heuristics, triggerBag];
Fill Scene Bag
FlushTriggerBag[sceneBag];
FillStaticSceneBag[scene, sceneBag];
Fill Align Bag
FlushAlignBag[alignBag];
FillStaticAlignBag[triggerBag, sceneBag, filters, hideAlignments, midpoints, alignBag];
CodeTimer.StopInt[$SetBagsForAction, $Solidviews];
};
};
SetDynamicBags:
PUBLIC
PROC [svData: SVData, action:
ATOM] = {
triggerBag: TriggerBag ← svData.hitTest.triggerBag;
alignBag: AlignBag ← svData.hitTest.alignBag;
sceneBag: TriggerBag ← svData.hitTest.sceneBag;
scene: Scene ← svData.scene;
anchor: Skitter ← scene.anchor;
heuristics: BOOL ← SVState.GetHeuristics[svData];
filters: Filters ← svData.hitTest;
hideAlignments: BOOL ← NOT SVState.GetShowAlignments[svData];
midpoints: BOOL ← SVState.GetMidpoints[svData];
IF hideAlignments
THEN {
FlushAlignBag[alignBag];
FlushTriggerBag[sceneBag];
FlushTriggerBag[triggerBag];
FillDynamicSceneBag[scene, sceneBag];
}
ELSE {
CodeTimer.StartInt[$SetBagsForAction, $Solidviews];
Fill TriggerBag
FlushTriggerBag[triggerBag];
FillDynamicTriggerBag[anchor, scene, heuristics, triggerBag];
Fill Scene Bag
FlushTriggerBag[sceneBag];
FillDynamicSceneBag[scene, sceneBag];
Fill Align Bag
FlushAlignBag[alignBag];
FillDynamicAlignBag[triggerBag, sceneBag, filters, hideAlignments, midpoints, action, alignBag];
CodeTimer.StopInt[$SetBagsForAction, $Solidviews];
};
};
StaticToDynamicBags:
PUBLIC
PROC [svData: SVData]
RETURNS [repaintForeground:
BOOL] = {
triggerBag: TriggerBag ← svData.hitTest.triggerBag;
sceneBag: TriggerBag ← svData.hitTest.sceneBag;
alignBag: AlignBag ← svData.hitTest.alignBag;
heuristics: BOOL ← SVState.GetHeuristics[svData];
filters: Filters ← svData.hitTest;
hideAlignments: BOOL ← NOT SVState.GetShowAlignments[svData];
midpoints: BOOL ← SVState.GetMidpoints[svData];
repaintForeground ← SomeSelectedIsHot[svData.scene] OR SVState.GetHeuristics[svData];
IF
NOT SVState.GetShowAlignments[svData]
THEN {
No alignments. Just build sceneBag.
repaintForeground ← FALSE;
FlushAlignBag[alignBag];
svData.hitTest.oldSceneBag ← sceneBag;
sceneBag ← StaticToDynamicSceneBag[svData.scene, sceneBag];
svData.hitTest.sceneBag ← sceneBag;
}
ELSE {
CodeTimer.StartInt[$UpdateBagsForAction, $Solidviews];
Incrementally Update TriggerBag
svData.hitTest.oldTriggerBag ← triggerBag;
triggerBag ← CopyTriggerBag[triggerBag];
AddHeuristics[svData.scene, heuristics, $Drag, triggerBag];
RemoveMoving[svData.scene, triggerBag];
svData.hitTest.triggerBag ← triggerBag;
Incrementally Update SceneBag
svData.hitTest.oldSceneBag ← sceneBag;
sceneBag ← StaticToDynamicSceneBag[svData.scene, sceneBag];
svData.hitTest.sceneBag ← sceneBag;
Remake AlignBag from Scratch
svData.hitTest.oldAlignBag ← alignBag;
alignBag ← CreateAlignBag[];
BuiltInFilters[triggerBag, filters, hideAlignments, alignBag];
AddAllMidpoints[sceneBag, midpoints, alignBag];
svData.hitTest.alignBag ← alignBag;
CodeTimer.StopInt[$UpdateBagsForAction, $Solidviews];
};
};
StaticToDynamicSceneBag:
PROC [scene: Scene, sceneBag: TriggerBag]
RETURNS [newBag: TriggerBag] = {
newBag ← CopyTriggerBag[sceneBag];
RemoveMoving[scene, newBag];
newBag.ignoreMoving ← TRUE;
IF newBag.tree # NIL THEN newBag.tree.outOfDate ← TRUE;
ComputeAllBoundingBoxes[newBag];
};
DynamicToStaticBags:
PUBLIC
PROC [svData: SVData]
RETURNS [repaintForeground:
BOOL] = {
triggerBag: TriggerBag;
sceneBag: TriggerBag;
alignBag: AlignBag ← svData.hitTest.alignBag;
filters: Filters ← svData.hitTest;
hideAlignments: BOOL ← NOT SVState.GetShowAlignments[svData];
midpoints: BOOL ← SVState.GetMidpoints[svData];
Use the old TriggerBag and SceneBag.
triggerBag ← svData.hitTest.triggerBag ← svData.hitTest.oldTriggerBag;
sceneBag ← svData.hitTest.sceneBag ← svData.hitTest.oldSceneBag;
ComputeAllBoundingBoxes[sceneBag]; -- not understood yet in Solidviews
Remake AlignBag from Scratch
alignBag ← CreateAlignBag[];
BuiltInFilters[triggerBag, filters, hideAlignments, alignBag];
AddAllMidpoints[sceneBag, midpoints, alignBag];
svData.hitTest.alignBag ← alignBag;
repaintForeground ← TRUE;
};
UpdateBagsForNewSlices:
PUBLIC
PROC [newSlices:
LIST
OF Slice, svData: SVData] = {
SetStaticBags[svData];
};
In support of building sceneBag.
AddAllSlices:
PROC [scene: Scene, triggerBag: TriggerBag] = {
sliceGen: AssemblyGenerator ← SVScene.PrimAssembliesInScene[scene];
feature: FeatureData;
FOR slice: Slice ← SVScene.NextAssembly[sliceGen], SVScene.NextAssembly[sliceGen]
UNTIL slice =
NIL
DO
feature ← FeatureFromSlice[slice];
AddFeature[feature, triggerBag];
ENDLOOP;
};
AddFeature:
PROC [featureData: FeatureData, triggerBag: TriggerBag] = {
Process.CheckForAbort[];
SELECT featureData.type
FROM
slice => {
triggerBag.slices ← CONS[featureData, triggerBag.slices];
};
anchor => {
triggerBag.anchor ← featureData;
};
ENDCASE => ERROR;
};
AddAlignment:
PRIVATE
PROC [featureData: FeatureData, alignBag: AlignBag] = {
Process.CheckForAbort[];
SELECT featureData.type
FROM
slopeLine => alignBag.slopeLines ← CONS[featureData, alignBag.slopeLines];
sphere => alignBag.spheres ← CONS[featureData, alignBag.spheres];
anchor => alignBag.anchor ← featureData;
ENDCASE => SIGNAL Problem[msg: "Unimplemented feature type"];
};
The Filter Routines shown in the figure as boxes and ovals
AddAnchorTrigger:
PROC [anchor: Skitter, triggerBag: TriggerBag] = {
[] ← CreateAnchorTrigger[anchor, triggerBag];
};
AddAllHotSlices:
PROC [scene: Scene, triggerBag: TriggerBag] = {
feature: FeatureData;
sliceDescGen: SliceDescriptorGenerator ← SVSelect.SelectedSlices[scene, hot];
FOR sliceD: SliceDescriptor ← SVSelect.NextSliceDescriptor[sliceDescGen], SVSelect.NextSliceDescriptor[sliceDescGen]
UNTIL sliceD =
NIL
DO
feature ← FeatureFromSlice[sliceD.slice, sliceD.parts];
AddFeature[feature, triggerBag];
ENDLOOP;
};
AddHeuristics:
PROC [scene: Scene, heuristics:
BOOL, atom:
ATOM, triggerBag: TriggerBag] = {
feature: FeatureData;
IF NOT heuristics THEN RETURN;
SELECT atom
FROM
$Drag => {
sliceDGen: SVSceneTypes.SliceDescriptorGenerator ← SVSelect.SelectedSlices[scene, normal];
FOR sliceD: SliceDescriptor ← SVSelect.NextSliceDescriptor[sliceDGen], SVSelect.NextSliceDescriptor[sliceDGen]
UNTIL sliceD =
NIL
DO
feature ← FeatureFromSlice[sliceD.slice, NIL];
AddFeature[feature, triggerBag];
ENDLOOP;
};
$CaretPos => NULL;
ENDCASE => ERROR Problem[msg: "unexpected type"];
};
RemoveMoving:
PROC [scene: Scene, triggerBag: TriggerBag] = {
If we are about to drag all of the selected objects, then we must remove selected objects from the triggerBag. We must also remove segments which are adjacent to a moving joint (called "dangling" segments), and segments whose control points are selected.
DeleteTriggersFilter[triggerBag, scene, RemoveMovingSlice];
};
RemoveMovingSlice:
PROC [sliceD: SliceDescriptor, scene: Scene]
RETURNS [stationary: SliceDescriptor] = {
selSliceD: SliceDescriptor ← SVSelect.FindSelectedSlice[sliceD.slice, scene, normal];
background, overlay, rubber, drag, move: SliceDescriptor;
IF selSliceD = NIL THEN RETURN[sliceD]; -- clearly nothing is moving
[background, overlay, rubber, drag] ← SVAssembly.MovingParts[selSliceD.slice, selSliceD.parts];
move ← SVAssembly.UnionParts[rubber, drag];
stationary ← SVAssembly.DifferenceParts[sliceD, move];
};
BuiltInFilters:
PUBLIC
PROC [triggerBag: TriggerBag, filters: Filters, hideAlignments:
BOOL, alignBag: AlignBag] = {
Add Alignment Objects to the alignBag, using the triggers in the triggerBag.
anchor: Skitter;
anchorFeature: FeatureData;
sliceD: SliceDescriptor;
pointGen: PointGenerator;
pointPairGen: PointPairGenerator;
index: NAT ← 0;
CodeTimer.StartInt[$BuiltInFilters, $Solidviews];
IF hideAlignments
THEN {
FlushAlignBag[alignBag];
RETURN;
};
The anchor as a trigger.
anchorFeature ← triggerBag.anchor;
IF anchorFeature #
NIL
AND SVCaret.Exists[(anchor ←
NARROW[anchorFeature.shape, Skitter])]
THEN {
point: Point3d ← SVMatrix3d.OriginOfMatrix[SVCaret.GetPosition[anchor]];
AddAnchorObject[anchorFeature, alignBag];
[] ← PointFireRule[point, filters, alignBag];
};
Triggers from slices.
FOR l:
LIST
OF FeatureData ← triggerBag.slices, l.rest
UNTIL l =
NIL
DO
sliceD ← NARROW[l.first.shape];
pointGen ← SVAssembly.PointsInDescriptor[sliceD, TRUE];
FOR next: SVSceneTypes.PointAndDone ← SVAssembly.NextPoint[pointGen], SVAssembly.NextPoint[pointGen]
UNTIL next.done
DO
[] ← PointFireRule[next.point, filters, alignBag];
ENDLOOP;
pointPairGen ← SVAssembly.PointPairsInDescriptor[sliceD];
index ← 0;
FOR next: SVSceneTypes.PointPairAndDone ← SVAssembly.NextPointPair[pointPairGen], SVAssembly.NextPointPair[pointPairGen]
UNTIL next.done
DO
[] ← SegmentFireRule[9999, next.lo, next.hi, filters, alignBag];
index ← index + 1;
ENDLOOP;
ENDLOOP;
CodeTimer.StopInt[$BuiltInFilters, $Solidviews];
};
Incremental Addition versions of the Filter Routines shown in the figure as boxes and ovals.
CreateAnchorTrigger:
PUBLIC
PROC [anchor: Skitter, triggerBag: TriggerBag]
RETURNS [feature: FeatureData] = {
feature ← FeatureFromAnchor[anchor];
AddFeature[feature, triggerBag];
};
AddHotSlice:
PUBLIC
PROC [sliceD: SliceDescriptor, triggerBag: TriggerBag]
RETURNS [feature: FeatureData] = {
oldD, unionD: SliceDescriptor;
oldD ← FindOldSlice[sliceD.slice, triggerBag.slices];
IF oldD =
NIL
THEN {
feature ← FeatureFromSlice[sliceD.slice, sliceD.parts];
triggerBag.slices ← AppendFeature[feature, triggerBag.slices];
}
ELSE {
unionD ← SVAssembly.UnionParts[oldD, sliceD];
triggerBag.slices ← DeleteSlice[oldD.slice, triggerBag.slices];
feature ← FeatureFromSlice[sliceD.slice, unionD.parts];
triggerBag.slices ← AppendFeature[feature, triggerBag.slices];
};
};
IncrementalFilters:
PUBLIC
PROC [trigger: FeatureData, filters: Filters, hideAlignments:
BOOL, alignBag: AlignBag]
RETURNS [alignObjects:
LIST
OF FeatureData] = {
A single new trigger has been added to the triggerBag. Add to the alignBag, all alignment objects generated by that trigger. Returns a list of the new alignment objects that were generated.
alignObjects ← NIL;
IF hideAlignments
THEN {
FlushAlignBag[alignBag];
RETURN;
};
WITH trigger.shape
SELECT
FROM
sliceD: SliceDescriptor => {
alignObjects ← IncrementalFilterSlice[sliceD, filters, hideAlignments, alignBag];
};
anchor: Skitter => {
The anchor as a trigger.
IF SVCaret.Exists[anchor]
THEN {
point: Point3d ← SVCaret.GetPoint[anchor];
[] ← PointFireRule[point, filters, alignBag];
};
};
ENDCASE => ERROR;
};
IncrementalFilterSlice:
PUBLIC
PROC [sliceD: SliceDescriptor, filters: Filters, hideAlignments:
BOOL, alignBag: AlignBag]
RETURNS [alignObjects:
LIST
OF FeatureData] = {
pointGen: PointGenerator;
pointPairGen: PointPairGenerator;
pointGen ← SVAssembly.PointsInDescriptor[sliceD, TRUE];
FOR next: SVSceneTypes.PointAndDone ← SVAssembly.NextPoint[pointGen], SVAssembly.NextPoint[pointGen]
UNTIL next.done
DO
alignObjects ← SVUtility.FeatureDataNconc[PointFireRule[next.point, filters, alignBag], alignObjects];
ENDLOOP;
pointPairGen ← SVAssembly.PointPairsInDescriptor[sliceD];
FOR next: SVSceneTypes.PointPairAndDone ← SVAssembly.NextPointPair[pointPairGen], SVAssembly.NextPointPair[pointPairGen]
UNTIL next.done
DO
alignObjects ← SVUtility.FeatureDataNconc[SegmentFireRule[9999, next.lo, next.hi, filters, alignBag], alignObjects];
ENDLOOP;
};
Special Operations
CreateAnchorAlignment:
PUBLIC
PROC [anchor: Skitter, alignBag: AlignBag]
RETURNS [feature: FeatureData] = {
Adds the new feature to the AlignBag and returns it.
feature ← FeatureFromAnchor[anchor];
AddAnchorObject[feature, alignBag];
};
In support of building triggerBag and sceneBag.
DeleteTriggersFilter:
PROC [triggerBag: TriggerBag, scene: Scene, filterSliceProc: FilterSliceProc] = {
When this procedure is called, all sequences in triggerBag are passed to filterSeqProc. filterSeqProc should return those parts which should be included in the new bag.
sliceD, newSliceD: SliceDescriptor;
sliceFeatures: LIST OF FeatureData ← triggerBag.slices;
newFeature: FeatureData;
triggerBag.slices ← NIL;
FOR sliceList:
LIST
OF FeatureData ← sliceFeatures, sliceList.rest
UNTIL sliceList =
NIL
DO
sliceD ← NARROW[sliceList.first.shape];
newSliceD ← filterSliceProc[sliceD, scene];
IF
NOT SVAssembly.IsEmptyParts[sliceD]
THEN {
newFeature ← FeatureFromSlice[newSliceD.slice, newSliceD.parts];
triggerBag.slices ← CONS[newFeature, triggerBag.slices];
};
ENDLOOP;
};
In support of building alignBag.
AddAnchorObject:
PROC [anchorFeature: FeatureData, alignBag: AlignBag] = {
alignBag.anchor ← anchorFeature;
};
PointFireRule:
PROC [point: Point3d, filters: Filters, alignBag: AlignBag]
RETURNS [alignObjects:
LIST
OF FeatureData] = {
CreateSlopeLines:
PROC [state:
BOOL, name: Rope.
ROPE, value:
REF
ANY, clientData:
REF
ANY]
RETURNS [done:
BOOL ←
FALSE] = {
IF state
THEN {
vector: Vector2d ← NARROW[value, REF Vector2d]^;
feature ← JointAddSlopeLine[
azimuth: vector[1],
slope: vector[2],
point: point,
alignBag: alignBag
];
IF feature # NIL THEN alignObjects ← CONS[feature, alignObjects];
};
};
CreateSpheres:
PROC [state:
BOOL, name: Rope.
ROPE, value:
REF
ANY, clientData:
REF
ANY]
RETURNS [done:
BOOL ←
FALSE] = {
IF state
THEN {
radius: REAL ← NARROW[value, REF REAL]^;
feature ← JointAddSphere[
radius: radius*filters.scaleUnit,
point: point,
alignBag: alignBag
];
IF feature # NIL THEN alignObjects ← CONS[feature, alignObjects];
};
};
feature: FeatureData;
alignObjects ← NIL;
AtomButtons.ReadSortedButtons[filters.slopeLineHandle, CreateSlopeLines];
AtomButtons.ReadSortedButtons[filters.radiusHandle, CreateSpheres];
};
SegmentFireRule:
PROC [segNum:
NAT, lo, hi: Point3d, filters: Filters, alignBag: AlignBag]
RETURNS [alignObjects:
LIST
OF FeatureData] = {
firstButton: ScalarButtonClient;
line1, line2: FeatureData;
alignObjects ← NIL;
Parallel Lines at Given Distance
firstButton ← filters.distanceHeader.scalarButtons;
FOR thisButton: ScalarButtonClient ← firstButton, thisButton.next UNTIL thisButton = NIL DO
IF thisButton.on THEN {
[line1, line2] ← SVGravity.SegmentAddDistanceLines[ distance: thisButton.value*filters.scaleUnit, segNum: segNum, lo: lo, hi: hi, objectBag: alignBag];
IF line1 # NIL THEN alignObjects ← CONS[line1, alignObjects];
IF line2 # NIL THEN alignObjects ← CONS[line2, alignObjects];
};
ENDLOOP;
AngleLines
firstButton ← filters.angleHeader.scalarButtons;
FOR thisButton: ScalarButtonClient ← firstButton, thisButton.next UNTIL thisButton = NIL DO
IF thisButton.on THEN {
[line1, line2] ← SVGravity.SegmentAddTwoAngleLines[degrees: thisButton.value, segNum: segNum, lo: lo, hi: hi, objectBag: alignBag];
IF line1 # NIL THEN alignObjects ← CONS[line1, alignObjects];
IF line2 # NIL THEN alignObjects ← CONS[line2, alignObjects];
};
ENDLOOP;
};
In support of building all three bags.
SomeSelectedIsHot:
PROC [scene: Scene]
RETURNS [
BOOL] = {
sliceDescGen: SliceDescriptorGenerator ← SVSelect.SelectedSlices[scene, normal];
FOR sliceD: SliceDescriptor ← SVSelect.NextSliceDescriptor[sliceDescGen], SVSelect.NextSliceDescriptor[sliceDescGen]
UNTIL sliceD=
NIL
DO
IF SVSelect.IsSelectedInPart[sliceD.slice, scene, hot] THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};
FeatureList Utilities
FindOldSlice:
PROC [slice: Slice, list:
LIST
OF FeatureData]
RETURNS [oldSliceD: SliceDescriptor] = {
FOR l:
LIST
OF FeatureData ← list, l.rest
UNTIL l =
NIL
DO
IF NARROW[l.first.shape, SliceDescriptor].slice = slice THEN RETURN [NARROW[l.first.shape]];
ENDLOOP;
RETURN [NIL];
};
FindSliceAndNeighbors:
PROC [entity: Slice, entityList:
LIST
OF FeatureData]
RETURNS [beforeEnt, ent, afterEnt:
LIST
OF FeatureData] = {
lastE: LIST OF FeatureData ← NIL;
eList: LIST OF FeatureData ← entityList;
IF eList = NIL THEN ERROR Problem[msg: "entity not found"];
UNTIL eList =
NIL
DO
IF NARROW[eList.first.shape, SliceDescriptor].slice = entity THEN {
beforeEnt ← lastE; ent ← eList; afterEnt ← eList.rest; RETURN};
lastE ← eList;
eList ← eList.rest;
ENDLOOP;
SIGNAL Problem[msg: "entity not found"];
};
DeleteSlice:
PROC [slice: Slice, featureList:
LIST
OF FeatureData]
RETURNS [smallerList:
LIST
OF FeatureData] = {
before, at, after: LIST OF FeatureData;
notFound: BOOL ← FALSE;
[before, at, after] ← FindSliceAndNeighbors[slice, featureList];
IF notFound THEN RETURN[featureList];
IF before = NIL THEN smallerList ← after
ELSE {
before.rest ← after;
smallerList ← featureList;
};
}; -- end of DeleteSlice
AppendFeature:
PUBLIC
PROC [feature: FeatureData, featureList:
LIST
OF FeatureData]
RETURNS [biggerList:
LIST
OF FeatureData] = {
Process.CheckForAbort[];
biggerList ← CONS[feature, featureList];
};
Drawing
DrawAlignBagRegardless:
PUBLIC PROC [dc: Imager.Context, alignBag: AlignBag, svData: SVData] = {
Draws all objects in the object bag regardless of how they have been marked.
IF alignBag = NIL THEN RETURN;
DrawFeatureList[dc, alignBag.slopeLines, svData];
DrawFeatureList[dc, alignBag.slopePlanes, svData];
DrawFeatureList[dc, alignBag.spheres, svData];
};
DrawFeatureList:
PUBLIC
PROC [dc: Imager.Context, alignObjects:
LIST
OF FeatureData, svData: SVData] = {
DrawLineAux:
PROC [line: Line3d] = {
SVGraphics.DrawInfiniteLine[dc, line.base, SVVector3d.Add[line.base, line.direction], camera, scene.coordSysRoot, rect];
};
DrawSphereAux:
PROC [sphere: Sphere] = {
SVBoundSphere.DrawBoundSphere[dc, sphere, camera];
};
rect: Imager.Rectangle ← SVState.GetViewport[svData];
scene: Scene ← svData.scene;
camera: Camera ← svData.camera;
Imager.SetStrokeWidth[dc, 1.0];
Imager.SetColor[dc, alignmentColor];
FOR list:
LIST
OF FeatureData ← alignObjects, list.rest
UNTIL list =
NIL
DO
WITH list.first.shape
SELECT
FROM
slopeLine: AlignmentLine => DrawLineAux[slopeLine.line];
alignmentSphere: AlignmentSphere => DrawSphereAux[alignmentSphere.sphere];
ENDCASE => ERROR;
ENDLOOP;
};
Initializing
InitStats:
PROC [] = {
boundBoxes, bags, interval: CodeTimer.Interval;
boundBoxes ← CodeTimer.CreateInterval[$ComputeBoundBoxes];
bags ← CodeTimer.CreateInterval[$UpdateBagsForAction, LIST[boundBoxes]];
CodeTimer.AddInt[bags, $Solidviews];
bags ← CodeTimer.CreateInterval[$SetBagsForAction, NIL];
CodeTimer.AddInt[bags, $Solidviews];
interval ← CodeTimer.CreateInterval[$BuiltInFilters, NIL];
CodeTimer.AddInt[interval, $Solidviews];
interval ← CodeTimer.CreateInterval[$AddAllMidpoints, NIL];
CodeTimer.AddInt[interval, $Solidviews];
};
Init:
PROC [] = {
emptyTriggerBag ← NIL;
emptyAlignBag ← CreateAlignBag[];
};
InitStats[];
Init[];
END.