Skip to content

Commit

Permalink
Rework distance_from to store polyline_id
Browse files Browse the repository at this point in the history
  • Loading branch information
TrevorBurgoyne committed Sep 20, 2024
1 parent 7b2d1bc commit f634c69
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 67 deletions.
12 changes: 8 additions & 4 deletions api_spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,17 +351,21 @@ enum AllowedToolboxItem {
Brush // 9
}

type AnnotationClassDistanceData = {
"single": number,
[key: number]?: number
type DistanceFromPolyline = {
distance: number // distance in pixels
}

type DistanceFromPolylineClasses = {
"closest_row": DistanceFromPolyline, // value used in single-class mode
[key: number]?: DistanceFromPolyline // values for each polyline class id, used in multi-class mode
}

type FilterDistanceConfig = {
"name"?: string, // Default: Filter Distance From Row
"component_name"?: string, // Default: filter-distance-from-row
"filter_min"?: number, // Default: 0 (px)
"filter_max"?: number, // Default: 400 (px)
"default_values"?: AnnotationClassDistanceData, // Default: { "single": 40 (px) }
"default_values"?: DistanceFromPolylineClasses, // Default: {"closest_row": {"distance": 40}}
"step_value"?: number, // Default: 2 (px)
"multi_class_mode"?: boolean, // Default: false
"disable_multi_class_mode"?: boolean, // Default: false
Expand Down
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Nothing yet.
- Renamed `FilterDistanceConfig` arg `show_overlay_on_load` -> `show_overlay` for internal consistency.
- Added `disable_multi_class_mode` flag to `FilterDistanceConfig`, which defaults to `false`. When `true`, the multi-class mode will be disabled and the checkbox will not be shown.
- Added `filter_during_polyline_move` flag to `FilterDistanceConfig`, which defaults to `true`. When `false`, the filter/overlay will not be updated until polyline moves/edits are completed. This can be useful for boosting performance when working with many annotations.
- Changed format of `default_values` arg in `FilterDistanceConfig`. The name for the single class mode default has changed from `"single"` -> `"closest_row"`, and each entry in the object should be a `DistanceFromPolyline` object (`{distance: <number>}`), rather than a single number. See the updated `api_spec.md` for more details.

## [0.11.0] - Sept 19th, 2024
- Fix bug where class counts wouldn't update when changing subtasks.
Expand Down
2 changes: 1 addition & 1 deletion dist/ulabel.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/ulabel.min.js

Large diffs are not rendered by default.

19 changes: 12 additions & 7 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import { FilterDistanceOverlay } from "./src/overlays";
import { ULabelSubtask } from "./src/subtask";
import { Toolbox } from "./src/toolbox";

export type DistanceFromPolyline = {
distance: number,
polyline_id?: string,
}

/**
* Stores the current "distance from line" filter values.
* "single" refers to the value of the single class distance filter while [key: number] is all of the polyline classes.
* Stores the current "distance from line" filter values, or the distance of a point to the closest lines.
* The key is the class id of the polyline. "closest_row" is a special key that stores the distance to the closest line.
*/
export type AnnotationClassDistanceData = {
"single": number,
[key: number]: number
export type DistanceFromPolylineClasses = {
closest_row: DistanceFromPolyline,
[key: number]: DistanceFromPolyline
}

export type AbstractPoint = {
Expand Down Expand Up @@ -42,7 +47,7 @@ export type DeprecatedBy = {
* Primarily exists so that points can be filtered before the page loads.
*/
export type FilterDistanceOverride = {
distances: AnnotationClassDistanceData,
distances: DistanceFromPolylineClasses,
multi_class_mode: boolean,
should_redraw: boolean,
show_overlay: boolean
Expand Down Expand Up @@ -85,7 +90,7 @@ export type FilterDistanceConfig = {
component_name?: string,
filter_min?: number,
filter_max?: number,
default_values?: AnnotationClassDistanceData,
default_values?: DistanceFromPolylineClasses,
step_value?: number,
multi_class_mode?: boolean,
disable_multi_class_mode?: boolean,
Expand Down
4 changes: 2 additions & 2 deletions src/annotation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
AnnotationClassDistanceData,
DeprecatedBy,
DistanceFromPolylineClasses,
ULabelClassificationPayload,
ULabelContainingBox,
ULabelSpatialType
Expand Down Expand Up @@ -35,7 +35,7 @@ export class ULabelAnnotation {
public classification_payloads?:ULabelClassificationPayload[],
public containing_box?: ULabelContainingBox,
public created_by?: string,
public distance_from?: AnnotationClassDistanceData,
public distance_from?: DistanceFromPolylineClasses,
public frame?: number,
public line_size?: number,
public id?: string,
Expand Down
38 changes: 22 additions & 16 deletions src/annotation_operators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
ULabel,
ULabelSpatialType,
DeprecatedBy,
AnnotationClassDistanceData,
DistanceFromPolylineClasses,
FilterDistanceOverride,
ValidDeprecatedBy,
ClassDefinition
Expand Down Expand Up @@ -252,7 +252,7 @@ export function assign_distance_from_line(
point_annotations.forEach(current_point => {

// Create a DistanceFrom object to be assigned to this point
let distance_from: AnnotationClassDistanceData = {"single": undefined}
let distance_from: DistanceFromPolylineClasses = {closest_row: undefined}
// Use the existing distance_from if it exists
if (current_point.distance_from !== undefined) {
distance_from = current_point.distance_from
Expand All @@ -267,13 +267,19 @@ export function assign_distance_from_line(

// If the distance from the current class is undefined, then set it
// Otherwise replace the value if the current distance is less than the one set
if (distance_from[line_class_id] === undefined || distance < distance_from[line_class_id]) {
distance_from[line_class_id] = distance
if (distance_from[line_class_id] === undefined || distance < distance_from[line_class_id].distance) {
distance_from[line_class_id] = {
distance: distance,
polyline_id: current_line.id,
}
}

// Likewise check to see if the current distance is less than a line of any class
if (distance_from["single"] === undefined || distance < distance_from["single"]) {
distance_from["single"] = distance
if (distance_from.closest_row === undefined || distance < distance_from.closest_row.distance) {
distance_from.closest_row = {
distance: distance,
polyline_id: current_line.id,
}
}
})

Expand Down Expand Up @@ -338,9 +344,7 @@ export function filter_points_distance_from_line(ulabel: ULabel, recalculate_dis
let multi_class_mode: boolean = false;
let show_overlay: boolean
let should_redraw: boolean
let distances: AnnotationClassDistanceData = {
"single": null // It gets angry if you don't initilize the single property
}
let distances: DistanceFromPolylineClasses = {closest_row: undefined}

// If the override is null grab the necessary info from the dom
if (override === null) {
Expand Down Expand Up @@ -372,11 +376,13 @@ export function filter_points_distance_from_line(ulabel: ULabel, recalculate_dis

// Loop through each slider and populate distances
for (let idx = 0; idx < sliders.length; idx++) {
// Use a regex to get the string after the final - character in the slider id (Which is the class id or the string "single")
// Use a regex to get the string after the final - character in the slider id (Which is the class id or the string "closest_row")
const slider_class_name = /[^-]*$/.exec(sliders[idx].id)[0]

console.log(slider_class_name)
// Use the class id as a key to store the slider's value
distances[slider_class_name] = sliders[idx].valueAsNumber
distances[slider_class_name] = {
distance: sliders[idx].valueAsNumber
}
}

// Always redraw when there's no override
Expand Down Expand Up @@ -408,10 +414,10 @@ export function filter_points_distance_from_line(ulabel: ULabel, recalculate_dis
check_distances: {
for (const id in distances) {
// Ignore the single class slider
if (id === "single") continue
if (id === "closest_row") continue

// If the annotation is smaller than the filter value for any id it passes
if (annotation.deprecated && annotation.distance_from[id] <= distances[id]) {
if (annotation.deprecated && annotation.distance_from[id].distance <= distances[id].distance) {
mark_deprecated(annotation, false, "distance_from_row")
annotations_ids_to_redraw_by_subtask[annotation.subtask_key].push(annotation.id)
break check_distances
Expand All @@ -427,7 +433,7 @@ export function filter_points_distance_from_line(ulabel: ULabel, recalculate_dis
} else {
// Single-class mode
point_annotations.forEach(annotation => {
mark_deprecated(annotation, annotation.distance_from["single"] > distances["single"], "distance_from_row")
mark_deprecated(annotation, annotation.distance_from.closest_row.distance > distances.closest_row.distance, "distance_from_row")
annotations_ids_to_redraw_by_subtask[annotation.subtask_key].push(annotation.id)
})
}
Expand All @@ -449,7 +455,7 @@ export function filter_points_distance_from_line(ulabel: ULabel, recalculate_dis
// Update overlay properties first
ulabel.filter_distance_overlay.update_annotations(line_annotations)
ulabel.filter_distance_overlay.update_distances(distances)
ulabel.filter_distance_overlay.update_mode(multi_class_mode ? "multi" : "single")
ulabel.filter_distance_overlay.update_mode(multi_class_mode)
ulabel.filter_distance_overlay.update_display_overlay(show_overlay)

// Then redraw the overlay
Expand Down
2 changes: 1 addition & 1 deletion src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const DEFAULT_FILTER_DISTANCE_CONFIG: FilterDistanceConfig = {
"component_name": "filter-distance-from-row",
"filter_min": 0,
"filter_max": 400,
"default_values": {"single": 40},
"default_values": {closest_row: {distance: 40}},
"step_value": 2,
"multi_class_mode": false,
"disable_multi_class_mode": false,
Expand Down
32 changes: 7 additions & 25 deletions src/overlays.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AbstractPoint, AnnotationClassDistanceData, Offset } from ".."
import { AbstractPoint, DistanceFromPolylineClasses, Offset } from ".."
import { ULabelAnnotation } from "./annotation"
import { get_annotation_class_id } from "./annotation_operators"
import { ULabelSpatialPayload2D } from "./geometric_utils"
Expand Down Expand Up @@ -126,9 +126,7 @@ class ULabelOverlay {

export class FilterDistanceOverlay extends ULabelOverlay {
private polyline_annotations: ULabelAnnotation[] // Set of polyline annotations the overlay will be drawn based on
private distances: AnnotationClassDistanceData = { // The current distance from a line annotation
"single": null
}
private distances: DistanceFromPolylineClasses = {closest_row: undefined} // The current distance from a line annotation
private multi_class_mode: boolean
private display_overlay: boolean // Whether or not the overlay should currently be displayed

Expand Down Expand Up @@ -216,28 +214,12 @@ export class FilterDistanceOverlay extends ULabelOverlay {
this.polyline_annotations = polyline_annotations
}

public update_distances(distances: {[key: string]: number}) {
for (let key in distances) {
// Update this.distances's values with the values inside distances
this.distances[key] = distances[key]
}
}

public update_mode(current_mode: "single" | "multi") {
if (current_mode === "multi") {
this.multi_class_mode = true
}
else if (current_mode === "single") {
this.multi_class_mode = false
}
else {
console.error("FilterDistanceOverlay.update_mode recieved unknown mode type")
}
public update_distances(distances: DistanceFromPolylineClasses) {
this.distances = distances
}

public get_mode() {
console.log(this.multi_class_mode)
return this.multi_class_mode ? "multi" : "single"
public update_mode(multi_class_mode: boolean) {
this.multi_class_mode = multi_class_mode
}

public update_display_overlay(display_overlay: boolean): void {
Expand Down Expand Up @@ -280,7 +262,7 @@ export class FilterDistanceOverlay extends ULabelOverlay {
const annotation_class_id: string = get_annotation_class_id(annotation)

// Use the class id if in multi-class mode, otherwise use the single class distance
const distance: number = this.multi_class_mode ? this.distances[annotation_class_id] : this.distances["single"]
const distance: number = this.multi_class_mode ? this.distances[annotation_class_id].distance : this.distances.closest_row.distance

// length - 1 because the final endpoint doesn't have another endpoint to form a pair with
for (let idx = 0; idx < spatial_payload.length - 1; idx++) {
Expand Down
22 changes: 12 additions & 10 deletions src/toolbox.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
AnnotationClassDistanceData,
DistanceFromPolylineClasses,
FilterDistanceConfig,
RecolorActiveConfig,
ULabel,
Expand Down Expand Up @@ -1977,7 +1977,7 @@ export class KeypointSliderItem extends ToolboxItem {
export class FilterPointDistanceFromRow extends ToolboxItem {
name: string // Component name shown to users
component_name: string // Internal component name
default_values: AnnotationClassDistanceData // Values sliders are set to on page load
default_values: DistanceFromPolylineClasses // Values sliders are set to on page load
filter_min: number // Minimum value slider may be set to
filter_max: number // Maximum value slider may be set to
step_value: number // Value slider increments by
Expand Down Expand Up @@ -2129,7 +2129,7 @@ export class FilterPointDistanceFromRow extends ToolboxItem {
// Toggle whether the single-class slider, or the multi-class sliders are visible
this.switchFilterMode()

this.overlay.update_mode(this.multi_class_mode ? "multi" : "single")
this.overlay.update_mode(this.multi_class_mode)

// Re-filter the points in the new mode, recalculating all distances if changing to multi-class
let recalculate_distances = this.multi_class_mode
Expand Down Expand Up @@ -2183,18 +2183,20 @@ export class FilterPointDistanceFromRow extends ToolboxItem {
const line_annotations: ULabelAnnotation[] = get_point_and_line_annotations(this.ulabel)[1]

// Initialize an object to hold the distances points are allowed to be from each class as well as any line
let filter_values: AnnotationClassDistanceData = {"single": undefined}
let filter_values: DistanceFromPolylineClasses = {closest_row: undefined}

// Grab all filter-distance-sliders on the page
const sliders: NodeListOf<HTMLInputElement> = document.querySelectorAll(".filter-row-distance-slider")

// Loop through each slider and populate filter_values
for (let idx = 0; idx < sliders.length; idx++) {
// Use a regex to get the string after the final - character in the slider id (Which is the class id or the string "single")
// Use a regex to get the string after the final - character in the slider id (Which is the class id or the string "closest_row")
const slider_class_name = /[^-]*$/.exec(sliders[idx].id)[0]

// Use the class id as a key to store the slider's value
filter_values[slider_class_name] = sliders[idx].valueAsNumber
filter_values[slider_class_name] = {
distance: sliders[idx].valueAsNumber
}
}

// Create and assign an overlay class instance to ulabel to be able to access it
Expand Down Expand Up @@ -2232,10 +2234,10 @@ export class FilterPointDistanceFromRow extends ToolboxItem {

let default_value: string
if (this.default_values[current_id] !== undefined) {
default_value = this.default_values[current_id].toString()
default_value = this.default_values[current_id].distance.toString()
}
else {
default_value = this.default_values["single"].toString()
default_value = this.default_values.closest_row.distance.toString()
}

const multi_class_slider_instance = new SliderHandler({
Expand Down Expand Up @@ -2270,8 +2272,8 @@ export class FilterPointDistanceFromRow extends ToolboxItem {
and its event handlers */
const single_class_slider_handler = new SliderHandler({
"class": "filter-row-distance-slider",
"default_value": this.default_values["single"].toString(),
"id": "filter-row-distance-single",
"default_value": this.default_values.closest_row.distance.toString(),
"id": "filter-row-distance-closest_row", // `closest_row` will be extracted using regex
"label_units": "px",
"slider_event": () => filter_points_distance_from_line(this.ulabel, false),
"min": this.filter_min.toString(),
Expand Down

0 comments on commit f634c69

Please sign in to comment.