Skip to content

Commit

Permalink
Additional documentation for AccuDraw, AccuSnap, and ACS. (backport #…
Browse files Browse the repository at this point in the history
…6367) [release/4.3.x] (#6394)

Co-authored-by: bbastings <[email protected]>
Co-authored-by: Ben Polinsky <[email protected]>
  • Loading branch information
3 people authored Jan 30, 2024
1 parent 0325f8b commit 507b7c1
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 0 deletions.
72 changes: 72 additions & 0 deletions docs/learning/frontend/PrimitiveTools.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ Example of typical implementation for onRestartTool:

### Snapping

An interactive tool that requires the user to identity a specific point on geometry can enable snapping.

![snapping example](./accusnap.png "Example of AccuSnap with snapping enabled")

Tools that override [InteractiveTool.onDataButtonDown]($frontend) or [InteractiveTool.onDataButtonUp]($frontend) and use [BeButtonEvent.point]($frontend) directly, in particular those that create new or modify existing elements, should call [AccuSnap.enableSnap]($frontend) with true to enable snapping. Snapping allows the user to identity locations of interest to them on existing elements or pickable decorations by choosing a [SnapMode]($frontend) and snap divisor. Snapping is used to identify points, *not* elements.
Expand All @@ -78,6 +80,30 @@ Tools that override [InteractiveTool.onDataButtonDown]($frontend) or [Interactiv
![tentative example](./tentative.png "Example showing Tentative snap to element")

Information about the current snap is presented using several on screen indicators detailed below.

1. Tentative snap preview
2. The snap mode used to compute the point
3. Hot snap location
4. The snap normal

![snapping indicators](./accusnap-indicators.png "Example of tentative vs. hot AccuSnap")

A tentative snap preview (shown with a dotted black and white plus symbol) is used as an alternative to forcing a hot snap and having the current point jump around wildly (to potentially off screen locations). [SnapMode.NearestKeypoint]($frontend) will show a tentative snap preview when the closest keypoint is too far from the cursor to be considered "hot". The user can accept the tentative snap location either by using a [TentativePoint]($frontend) or by moving the cursor closer to the previewed location. The hot distance is based on the settings for [AccuSnap.Settings.hotDistanceFactor]($frontend) and [ElementLocateManager.apertureInches]($frontend).

> When a tentative point preview is displayed but not accepted, [BeButtonEvent.point]($frontend) will be set to the hit point on the geometry under the cursor (not the location of the tentative point preview) as opposed to being treated as unsnapped and projected to the view's [ACS](#auxiliary-coordinate-system).
Unlike the tentative snap preview, a hot snap (shown by a yellow X symbol) indicates an accepted snap location that will be reflected in [BeButtonEvent.point]($frontend). Using [SnapMode.Center]($frontend) will always force a hot snap regardless of distance from the cursor to facilitate being able to easily locate arc centers.

The snap normal (shown with a filled in-plane disc) indicates the surface normal of a solid/sheet or well defined normal for other planar geometry at the snap location. In the case of an edge snap, the snap normal combined with the edge tangent will fully define a rotation.

You can combine a [TentativePoint]($frontend) snap with [AccuSnap]($frontend) when using [SnapMode.Intersection]($frontend) to identify extended intersections.

1. First use a [TentativePoint]($frontend) to snap to a curve or edge
2. AccuSnap finds the intersection with the geometry identified by the tentative with any curve/edge under the cursor

![snap to extended intersection](./tentative-intersection.png "Example of snap to extended intersection")

> A tool with an understanding of connection points and how things fit together *should not* enable AccuSnap. For example, a tool to place a valve on a pipe knows to only choose pipe end points of a given diameter, it should not require the user to choose an appropriate snap point at the end of a correct pipe or try to influence AccuSnap to only generative *key points* it deems appropriate. This is case where [locate](#locate) should be enabled instead.
Example from a simple sketching tool that uses AccuSnap to create and show a linestring in dynamics:
Expand All @@ -94,6 +120,8 @@ Example from a simple sketching tool that uses AccuSnap to create and show a lin

A tool that only needs to identify elements and does not use [BeButtonEvent.point]($frontend) should not enable snapping. Instead the tool should call [AccuSnap.enableLocate]($frontend) with true to begin locating elements as the cursor moves over them. Enabling locate for AccuSnap provides the user with feedback regarding the element under the cursor in the form of a tooltip. Element's will also glow to highlight when they are of the type the tool is looking for.

> When not snapping be aware that [BeButtonEvent.point]($frontend) is not set to [HitDetail.hitPoint]($frontend) since this represents an approximate world location based on the displayed facetted/stroked graphics. The point will instead be projected to the view's [ACS](#auxiliary-coordinate-system). In cases where enabling snapping is not desirable but an exact hit point on the geometry is required, calling [AccuSnap.doSnapRequest]($frontend) with [SnapMode.Nearest]($frontend) may provide an easy alternative to getting the element geometry.
When either locate with AccuSnap is enabled, or the tool requests a new locate by calling [ElementLocateManager.doLocate]($frontend) on a button event, [InteractiveTool.filterHit]($frontend) will be called to give the tool an opportunity to accept or reject the element or pickable decoration identified by a supplied [HitDetail]($frontend). When overriding filterHit and rejecting a hit, the tool should set [LocateResponse.reason]($frontend) to explain why the hit is being rejected; this message will be displayed on motion stop in a tooltip when an implementation for [NotificationManager._showToolTip]($frontend) is provided.

A tool can also customize the tooltip for accepted elements in order to include tool specific details by overriding [InteractiveTool.getToolTip]($frontend).
Expand All @@ -108,12 +136,24 @@ Example from a simple tool that locates elements and makes them the current sele
[[include:PrimitiveTool_Locate]]
```

## Auxiliary Coordinate System

An auxiliary coordinate system or ACS defines a working plane for a view that can differ from the global coordinate system. By default every view has an ACS that is aligned with the global system. Display of the ACS triad showing the location of ACS origin and direction of the X and Y axes is enabled by setting [ViewFlags.acsTriad]($common). The drawing grid can also help visualize the working plane by using [GridOrientationType.AuxCoord]($common) and enabling [ViewFlags.grid]($common).

![rotated acs](./rotated-acs.png "Example showing ACS triad and aligned grid")

Setting [ToolAdmin.acsContextLock]($frontend) makes it easier to work in a rotated coordinate system as tools like [StandardViewTool]($frontend) will use rotations relative to the view's ACS instead of the global system. Use [AccuDrawHintBuilder.getContextRotation]($frontend) when writing an interactive tool to properly support this setting.

Setting [ToolAdmin.acsPlaneSnapLock]($frontend) makes it easier to work on the ACS plane by projecting snap points into the ACS plane. Unsnapped points are always projected to the ACS plane when AccuDraw is not active.

## AccuDraw

![AccuDraw example](./accudraw.png "Example of AccuDraw using axis lock to constrain snapped point")

[AccuDrawHintBuilder]($frontend) is an aide for entering coordinate data. By using *shortcuts* to position and orient the AccuDraw compass, locking a direction, or entering distance and angle values, the user is able to accurately enter points. AccuDraw isn't strictly controlled by the user however, the tool is also able to provide additional context to AccuDraw in the form of *hints* to make the tool easier to use.

> When [ToolAdmin.acsContextLock]($frontend) is enabled the AccuDraw shortcuts for orienting the compass to top, front, or side will be relative to the view's ACS instead of the global system. Additionally, when AccuDraw first becomes active when using an interactive tool it will orient itself to the view's ACS.
Some examples of AccuDraw tool hints:

- Send AccuDraw hint to use polar mode when defining a sweep angle.
Expand All @@ -127,8 +167,40 @@ Upon installing a new Primitive tool as the active tool, AccuDraw's default stat

> Tools that enable AccuDraw, either through automatic or explicit activation, should still not rely on AccuDraw or its hints for point adjustment. The user may choose to disable AccuDraw completely, set a preference to ignore tool hints in favor of manually controlling the AccuDraw compass, or use shortcuts to override the tool's hints. If for example a tool requires the input point be projected to a particular plane in the view, even after enabling AccuDraw and sending hints to set the compass origin and rotation to define the plane, it must still correct [BeButtonEvent.point]($frontend) to ensure it lies on the plane for the reasons previously mentioned.
[AccuDrawHintBuilder]($frontend) provides several utility methods to help interactive tools with point adjustment.

- [AccuDrawHintBuilder.projectPointToPlaneInView]($frontend)
- [AccuDrawHintBuilder.projectPointToLineInView]($frontend)
- [AccuDrawHintBuilder.getBoresite]($frontend)

Example from a simple sketching tool that uses AccuDrawHintBuilder to facilitate drawing orthogonal segments:

```ts
[[include:PrimitiveTool_PointsTool]]
```

### Getting the Current AccuDraw Rotation

An interactive tool might want to allow the user to use AccuDraw to define the orientation of the geometry it is creating or modifying. For example using AccuDraw to define the rotation when sketching a planar shape or placing a symbol.

Tools should use [AccuDrawHintBuilder.getCurrentRotation]($frontend) to get the current AccuDraw rotation when it is active and to fallback to either the view or ACS rotation when not active. When calling [AccuDrawHintBuilder.getCurrentRotation]($frontend) with true for checking both AccuDraw and the view's ACS, the priority for what rotation is returned is a follows.

1. Current AccuDraw rotation when active
2. Current view ACS rotation when [ToolAdmin.acsContextLock]($frontend) is enabled
3. Current view rotation

> By calling [AccuDrawHintBuilder.getCurrentRotation]($frontend) the interactive tool doesn't need to consider if AccuDraw is active or not.
### AccuDraw and Nearest Snap

You can combine AccuDraw's distance and axis locks with [SnapMode.Nearest]($frontend) to adjust the current point to the intersection with the snapped geometry.

1. Keypoint snap projects the closest keypoint on the snapped geometry to the locked axis
2. Nearest snap finds the intersection of the locked axis and the snapped geometry

![accudraw nearest axis lock](./accudraw-nearest-axis.png "Example showing keypoint vs. nearest snap with axis lock")

1. Keypoint snap sets the current point at the locked distance along the vector from the compass origin to closest keypoint.
2. Nearest snap finds the intersection between the circle defined by the locked distance and the snapped geometry.

![accudraw nearest distance lock](./accudraw-nearest-distance.png "Example showing keypoint vs. nearest snap with distance lock")
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/learning/frontend/accusnap-indicators.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/learning/frontend/rotated-acs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 507b7c1

Please sign in to comment.