Introduction
When an animation searches for things to snap to from the space, the space will provide the animation with SnapAlternatives. Based on different criteria, the animation will choose which SnapAlternative to snap to. In other words, snap alternatives are the possible candidates that an animation can snap to.
Appending Alternatives
Animation
appendAlternatives()
in animation.cm./** * Append alternatives. */ extend public void appendAlternatives(SnapAlternative[] list, SnapperFilter filter=null) { /** Subclass */ }
/** * Append alternatives. */ public void appendAlternatives(SnapAlternative[] list, SnapperFilter filter=null) { if (?AnimationSelection selection = this."selection") { if (selection.main and selection.main.space) selection.main.appendAlternatives(list, this, lastMouseInfo, filter); } }
Snapper
A snapper's alternatives are appended in their own appendAlternatives()
located in snapper.cm.
SnapperAnimation
./** * Append alternatives. */ extend public void appendAlternatives(SnapAlternative[] alternatives, Animation a, AnimationMouseInfo mi, SnapperFilter filter=null) { if (!alternatives) return; appendAttachAlternatives(..); } /** * Append attach alternatives. */ extend public void appendAttachAlternatives(SnapAlternative[] alternatives, Animation a, AnimationMouseInfo mi, SnapperFilter filter=null) { if (!alternatives) return; devassert(a); ?AnimationSelection selection = a.?"selection"; if (selection and !selection.snaps.empty) { ?Connector{} blacklist = a."attachAlternativeBlacklist"; AttachAlternativeBlacklist bfilt(blacklist); if (!blacklist or blacklist.empty) bfilt = null; FilteredConnectorSet fcs(CombinedConnectorFilter(connectableAttachFilter, bfilt, ByRuleConnectableToFilter(selection.activeSnaps))); space.?getCollection(mi.currentLine, searchRadius(), collection=fcs, snapperFilter=filter); for (c in fcs.set) { alternatives << AttachSnapAlternative(c); } } }
appendAttachAlternatives()
being called above is responsible for your animation searching for connectors to snap to.For example, if you want your snapper to snap to features then you will have to append FeatureSnapAlternatives
. If you want your snapper to snap to something else (for example, CET walls), you will have to implement your own snap alternative and append it.
Sorting Alternatives
The priority of the snap alternatives are sorted in sortSnapAlternatives()
. The alternatives are sorted based on priority which affects which alternative is more preferred during snapping.
/** * Sort snap alternatives. */ extend public void sortSnapAlternatives(SnapAlternative[] alternatives, Animation animation, AnimationMouseInfo mi) { SnapAlternativeSortEnv env(animation, mi); env.sort(alternatives); }
SnapAlternative
class has a priority method that returns an integer value which is used by the SnapAlternativeEnv
to sort the alternatives./** * Priority. */ extend public int priority() { return 0; }
ToolAnimationG2 Example
ToolAnimationG2
.The animation uses snap alternatives to find snapper and vessel candidates. These alternatives are SnapperCandidateSnapAlternative
and VesselCandidateSnapAlternative
. appendAlternatives()
below searches for all the snappers and vessels close to the mouse, and appends alternatives for each found. Depending on if the snapperCandidateSearch()
or vesselCandidateSearch()
return false, the animation can omit either one of these alternatives.
/** * Append alternatives. */ public void appendAlternatives(SnapAlternative[] list, SnapperFilter filter=null) { super(..); if (!space) return; // update candidate picker... if (candidatePicker as FuzzyAnimationCandidatePicker) { if (snapperCandidateSearch) { Snapper[] snappers(); candidatePicker.pick(snappers, candidateFilter); appendCandidateAlternatives(list, snappers); } if (vesselCandidateSearch) { Vessel[] vesselCandidates(); candidatePicker.pick(vesselCandidates, vesselCandidateFilter); appendVesselCandidateAlternatives(list, vesselCandidates); } } } /** * Append candidate alternatives. * Called on candidate search. * N.B: Don't use this for new Heap Candidate Picker protocol, although, it will still work. */ extend public void appendCandidateAlternatives(SnapAlternative[] list, Snapper[] potentials) { if (candidatePicker in FuzzyAnimationHeapCandidatePicker) return; // Default is to not append alternatives.. for (c in potentials, index=i) list <<? candidateAlternative(c, i); } /** * Append candidate alternative. */ extend public SnapAlternative candidateAlternative(Snapper snapper, int i=0) { return SnapperCandidateSnapAlternative(snapper, candidatePriority(snapper, i)); } /** * Append vessel candidate alternatives. * N.B: Don't use this for new Heap Candidate Picker protocol, although, it will still work. */ extend public void appendVesselCandidateAlternatives(SnapAlternative[] list, Vessel[] vesselCandidates) { if (candidatePicker in FuzzyAnimationHeapCandidatePicker) return; // Default is to not append alternatives.. for (c in vesselCandidates) list <<? vesselCandidateAlternative(c); } /** * Append vessel candidate alternative. */ extend public SnapAlternative vesselCandidateAlternative(Vessel vessel) { return VesselCandidateSnapAlternative(vessel); }
SnapAlternative
has a method called try which is called by the animation's trySnapAlternative()
. In this method, you will return a SnapInfo
which will let the animation know that snapping is possible for this alternative.
The code below shows how try()
is being implemented by SnapperCandidateSnapAlternative
and VesselCandidateSnapAlternative
. In this case, the try method is also setting the position of the animation.
// SnapperCandidateSnapAlternative /** * Try. */ public SnapInfo try(Animation animation, AnimationMouseInfo mi) { if (animation as ToolAnimationG2) { // If the animation accepts and snapper accepts if (snapper and animation.acceptAsCandidate(snapper) and snapper.acceptSnapAlternative(this, animation)) { Snapper old = animation.candidate; animation.candidate = snapper; if (old != snapper) { animation.candidateChanged(old); old.?abandoned(animation); animation.candidateChosen(this); } animation.pos = getAnimationPos(mi); return CoreToolSnapInfo(true); } } return null; } // VesselCandidateSnapAlternative /** * Try. */ public SnapInfo try(Animation animation, AnimationMouseInfo mi) { if (animation as ToolAnimationG2) { if (vessel and animation.acceptAsVesselCandidate(vessel) and vessel.acceptSnapAlternative(this, animation)) { Vessel old = animation.vesselCandidate; animation.vesselCandidate = vessel; if (old != vessel) { animation.vesselCandidateChanged(old); old.?abandoned(animation); animation.vesselCandidateChosen(this, old); } animation.pos = getAnimationPos(mi); return CoreToolSnapInfo(true); } } return null; }
Comments
0 comments
Please sign in to leave a comment.