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, Matrix3d, GList, Lines2d, Process, Rope, SV2d, SV3d, SVAlign, SVAssembly, SVCaret, SVGraphics, SVInterfaceTypes, SVLines3d, SVModelTypes, SVScene, SVSceneTypes, SVSelect, SVState, SVVector3d;
SVAlignImpl: CEDAR PROGRAM
IMPORTS AtomButtons, CodeTimer, Feedback, GList, Imager, ImagerBackdoor, Matrix3d, Process, SVAssembly, SVCaret, SVGraphics, SVLines3d, SVScene, SVSelect, SVState, SVVector3d
EXPORTS SVAlign
=
BEGIN
AlignBag: TYPE = REF AlignBagObj;
AlignBagObj: TYPE = SVInterfaceTypes.AlignBagObj;
AlignmentLine: TYPE = REF AlignmentLineObj;
AlignmentLineObj: TYPE = SVInterfaceTypes.AlignmentLineObj;
AssemblyGenerator: TYPE = SVScene.AssemblyGenerator;
Camera: TYPE = SVModelTypes.Camera;
FeatureData: TYPE = SVInterfaceTypes.FeatureData;
FeatureDataObj: TYPE = SVInterfaceTypes.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;
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 ← NARROW[GList.Copy[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,
anchor: NIL
]];
};
FlushAlignBag: PUBLIC PROC [alignBag: AlignBag] = {
alignBag.slopeLines ← NIL;
alignBag.slopePlanes ← 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];
};
};
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];
};
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: BOOLNOT 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: BOOLNOT 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: BOOLNOT 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: BOOLNOT 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];
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 ← Matrix3d.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];
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];
FOR next: SVSceneTypes.PointAndDone ← SVAssembly.NextPoint[pointGen], SVAssembly.NextPoint[pointGen] UNTIL next.done DO
alignObjects ← NARROW[GList.Nconc[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 ← NARROW[GList.Nconc[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.EmptyParts[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: BOOLFALSE] = {
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];
};
};
feature: FeatureData;
alignObjects ← NIL;
AtomButtons.ReadSortedButtons[filters.slopeLineHandle, CreateSlopeLines];
Circle
firstButton ← filters.radiusHeader.scalarButtons;
FOR thisButton: ScalarButtonClient ← firstButton, thisButton.next UNTIL thisButton = NIL DO
IF thisButton.on THEN {
feature ← SVGravity.JointAddCircle[
radius: thisButton.value*filters.scaleUnit,
point: point,
objectBag: alignBag
];
IF feature # NIL THEN alignObjects ← CONS[feature, alignObjects];
};
ENDLOOP;
};
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: BOOLFALSE;
[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: PUBLIC PROC [dc: Imager.Context, alignObjects: LIST OF FeatureData, svData: SVData] = {
DrawLineAux: PROC [line: Line3d] = { -- uses FunctionCache to avoid duplication
LineCompare: PROC [argument: FunctionCache.Domain] RETURNS [good: BOOL] = {
thisLine: Line3d ← NARROW[argument];
RETURN[SVLines3d.EqualLine[thisLine, line]];
};
ok: BOOL;
[----, ok] ← FunctionCache.Lookup[svData.refresh.lineCache, LineCompare];
IF ok THEN RETURN
FunctionCache.Insert[svData.refresh.lineCache, line, NIL, 2];
IF ABS[line.theta] < 1.0 OR ABS[line.theta - 90.0] < 1.0 THEN {
Imager.SetColor[dc, checkerColor];
Lines2d.DrawLine[dc, line, rect, 0.0]; -- 0 width lines go fast
Imager.SetColor[dc, alignmentColor];
}
ELSE Lines2d.DrawLine[dc, line, rect, 0.0]; -- 0 width lines go fast
SVGraphics.DrawInfiniteLine[dc, line.base, SVVector3d.Add[line.base, line.direction], camera, scene.coordSysRoot, rect];
};
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];
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.