Skip to content

Feature/annotation measurements - #1070

Open
chourroutm wants to merge 5 commits into
google:masterfrom
chourroutm:feature/annotation-measurements
Open

Feature/annotation measurements#1070
chourroutm wants to merge 5 commits into
google:masterfrom
chourroutm:feature/annotation-measurements

Conversation

@chourroutm

Copy link
Copy Markdown

I have added measurements for the different types of annotations:

Line:

  • Length
  • Projected lengths on x/y/z
image

Bounding box:

  • Edge lengths
  • Volume
image

Polyline:

  • Total length
  • Angles
image

Add a new RULER annotation type (forked from polyline) plus a ruler
placement tool. A ruler shares polyline geometry but is a distinct type,
so it is distinguishable from a polyline in persisted and in-memory state.

The ruler's total physical length (sum of consecutive segment lengths) is
shown as a read-only "Length" row in the selection panel, formatted with an
auto-scaled unit (e.g. "1.23 um") via formatLength using the annotation
layer's coordinate-space scale. This mirrors how the polyline "Num vertices"
property is presented, and is computed on demand rather than stored.

The toolbar icon is U+007B ("{"). The RULER type reuses the polyline render
handler and serialization via a shared factory; every polyline-specific code
path now also handles rulers via isPolylineLikeAnnotationType. The segment
length math lives in a pure, unit-tested helper (src/util/ruler_length.ts).

Precomputed RULER serialization is intentionally out of scope.

Tests: node unit tests for the length helper (including anisotropic per-axis
scaling); browser tests for JSON round-trip, binary-serialization parity with
polyline, distinct-type, and physical length formatting.
The ruler type reuses the polyline render handler, so it shares the
polyline setter namespace (setPoly*). The annotation shader assembles by
having the current type's defineShader emit the real setter bodies and
every other type's defineShaderNoOpSetters emit empty bodies. With ruler
present, the shared setPoly* setters were emitted more than once
(polyline + ruler no-ops, or a no-op colliding with the real body),
producing duplicate GLSL function definitions that failed to compile, so
no polyline or ruler lines rendered.

Emit the polyline-like no-op setters at most once (via POLYLINE) and never
when compiling a polyline-like shader, since those types provide the real
implementations via defineShader.
Add a new ANGLE annotation type (forked from polyline, like RULER) plus an
angle placement tool. An angle shares polyline geometry but is a distinct
type, distinguishable from a polyline and a ruler.

For each interior vertex of the path (N points -> N-2 vertices) the
selection panel shows the unsigned interior angle between the two adjoining
segments, in degrees (0-180, one decimal), as read-only "Angle google#1",
"Angle google#2", ... rows -- the same panel presentation as the ruler's Length.
Angles are computed in the annotation layer's physical coordinate space
(reusing getAnnotationScalesNm) so anisotropic scales give correct angles,
reflect only committed points (the in-progress cursor point is excluded
while placing), and skip degenerate (zero-length-segment) vertices.

The toolbar icon is U+2221 ("angle"). ANGLE is folded into
isPolylineLikeAnnotationType, so it reuses the shared polyline render
handler, serialization, and the polyline-like shader path added for the
ruler. The angle math lives in a pure, unit-tested helper
(src/util/angle_measurement.ts).

Tests: node unit tests for the angle helper (right/straight/acute angles,
N-2 count, zero-length segment -> NaN, anisotropic scaling, 0-180 range);
browser tests for JSON round-trip, distinct-type, and binary-serialization
parity with polyline.
…ler/angle

Retire the RULER and ANGLE annotation types and their tools/toolbar buttons
(added on the parent branch) and instead surface measurements directly on
the built-in annotations, shown as read-only rows in the selection panel:

- Line: total physical length plus the projected length along each axis
  (dynamic during placement, since a line is two points).
- Polyline: total physical length plus the interior angle at each interior
  vertex (static; the in-progress cursor point is excluded while placing).
- Axis-aligned bounding box: per-axis physical edge length plus the physical
  volume (shown only for exactly three length dimensions).

Per-axis labels (line projected lengths, bbox edges) are derived from the
coordinate-space axis names in the state (default x, y, z), and non-length
axes are skipped. Physical values reuse the retained helpers ruler_length,
angle_measurement, and the new pure axis_extents helper; the physical-scale
helper is renamed getAnnotationScalesNm -> getAnnotationPhysicalScales.

The polyline-like generalization (isPolylineLikeAnnotationType, the shared
handler factory, and the shader setter-collision special-casing) added for
ruler/angle is removed now that polyline is again the only polyline-like
type; those paths revert to direct POLYLINE checks.

Tests: node unit tests for axis_extents; browser tests for the measurement
pipeline (line/polyline/bbox) and line/polyline/bbox JSON round-trip.
Rename the measurement helper functions to describe the physical quantity
rather than its unit, matching getAnnotationScalesNm ->
getAnnotationPhysicalScales:

- computeRulerLengthNm      -> computeRulerPhysicalLength
- computeAxisExtentsNm      -> computeAxisPhysicalExtents
- computeVertexAnglesDegrees-> computeVertexPhysicalAngles
- computeAngleDegrees       -> computeAnnotationPhysicalAngles

Pure rename across definitions, call sites, and tests; no behavior change.
@google-cla

google-cla Bot commented Jul 10, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@chourroutm
chourroutm force-pushed the feature/annotation-measurements branch from 81adb38 to 8e238e3 Compare July 13, 2026 21:05
@chrisj

chrisj commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@chourroutm this is a valuable feature and I will give you more implementation feedback later

I worked on a similar feature and it stalled out but I recommend taking a look at the implementation: #694. It added "default annotation properties" and I think that is a good idea for your implementation as well.

It would be great to get some feedback from scientists/users but I'm wondering what is the right data to show and perhaps there should be an expanded and collapsed version of the metadata.
Screenshot 2026-07-16 at 12 26 46 PM

example

@chourroutm

Copy link
Copy Markdown
Author

Thanks, @chrisj! Should I change something in my implementation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants