You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

110 lines
2.8 KiB

import { v4 as uuidv4 } from 'uuid'
import Flatten from '@flatten-js/core'
import LabelProps from '@/domain/models/tasks/shared/LabelProps'
import LineSegment from './LineSegment'
import PolygonProps from './PolygonProps'
import ValidationError from './errors'
import Point = Flatten.Point
import Vector = Flatten.Vector
const MINIMUM_NUMBER_OF_SIDES = 3
export default class Polygon {
readonly id: string
readonly labelId: number
points: Point[] = []
constructor(labelId: number, points: number[] = [], id: string = uuidv4()) {
if (points.length % 2 !== 0) {
throw new ValidationError('Invalid number of points')
}
this.id = id
this.labelId = labelId
for (let i = 0; i < points.length; i += 2) {
this.addPoint(points[i], points[i + 1])
}
}
clone(): Polygon {
return new Polygon(this.labelId, this.flattenedPoints, this.id)
}
translate(x: number, y: number): void {
const vector = new Vector(x, y)
this.points = this.points.map((point) => point.translate(vector))
}
canBeClosed(): boolean {
return this.points.length >= MINIMUM_NUMBER_OF_SIDES
}
addPoint(x: number, y: number): void {
const point = new Point(x, y)
this.points.push(point)
}
movePoint(index: number, x: number, y: number): void {
const point = new Point(x, y)
this.points[index] = point
}
removePoint(index: number): void {
if (this.points.length > MINIMUM_NUMBER_OF_SIDES) {
this.points.splice(index, 1)
}
}
insertPoint(x: number, y: number, index: number): void {
const point = new Point(x, y)
this.points.splice(index, 0, point)
}
toPoints(): Point[] {
return this.points.map((point) => point.clone())
}
minMaxPoints(): [number, number, number, number] {
const [minX, minY, maxX, maxY] = this.points.reduce(
([minx, miny, maxx, maxy], point) => [
Math.min(minx, point.x),
Math.min(miny, point.y),
Math.max(maxx, point.x),
Math.max(maxy, point.y)
],
[Infinity, Infinity, -Infinity, -Infinity]
)
return [minX, minY, maxX, maxY]
}
toProps(): PolygonProps {
return {
id: this.id,
label: this.labelId,
points: this.points.flatMap((point) => [point.x, point.y])
}
}
getColor(labels: LabelProps[]): string {
return labels.find((label) => label.id === this.labelId)!.color || '##ff0000'
}
get lineSegments(): LineSegment[] {
const lineSegments = []
for (let i = 0; i < this.points.length; i += 1) {
const p1 = this.points[i]
const p2 = this.points[(i + 1) % this.points.length]
lineSegments.push(new LineSegment(p1, p2))
}
return lineSegments
}
get flattenedPoints(): number[] {
return this.points.flatMap((point) => [point.x, point.y])
}
get numberOfSides(): number {
return this.points.length
}
}