Improves drawing
This commit is contained in:
parent
7ef83dc508
commit
c41def99d3
4 changed files with 80 additions and 5 deletions
|
@ -12,7 +12,6 @@ export default function Brush() {
|
|||
y={brush.minY}
|
||||
width={brush.width}
|
||||
height={brush.height}
|
||||
className="brush"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -20,4 +19,5 @@ export default function Brush() {
|
|||
const BrushRect = styled("rect", {
|
||||
fill: "$brushFill",
|
||||
stroke: "$brushStroke",
|
||||
zStrokeWidth: 1,
|
||||
})
|
||||
|
|
|
@ -5,6 +5,9 @@ import { registerShapeUtils } from "./index"
|
|||
import { intersectPolylineBounds } from "utils/intersections"
|
||||
import { boundsContainPolygon } from "utils/bounds"
|
||||
import { getBoundsFromPoints, translateBounds } from "utils/utils"
|
||||
import { DotCircle } from "components/canvas/misc"
|
||||
|
||||
const pathCache = new WeakMap<DrawShape, string>([])
|
||||
|
||||
const draw = registerShapeUtils<DrawShape>({
|
||||
boundsCache: new WeakMap([]),
|
||||
|
@ -31,8 +34,34 @@ const draw = registerShapeUtils<DrawShape>({
|
|||
}
|
||||
},
|
||||
|
||||
render({ id, points }) {
|
||||
return <polyline id={id} points={points.toString()} />
|
||||
render(shape) {
|
||||
const { id, point, points } = shape
|
||||
|
||||
if (points.length < 2) {
|
||||
return <DotCircle cx={point[0]} cy={point[1]} r={3} />
|
||||
}
|
||||
|
||||
if (!pathCache.has(shape)) {
|
||||
pathCache.set(
|
||||
shape,
|
||||
points
|
||||
.reduce(
|
||||
(acc, [x0, y0], i, arr) => {
|
||||
if (i === points.length - 1) {
|
||||
acc.push("L", x0, y0)
|
||||
} else {
|
||||
const [x1, y1] = arr[i + 1]
|
||||
acc.push(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2)
|
||||
}
|
||||
return acc
|
||||
},
|
||||
["M", ...points[0], "Q"]
|
||||
)
|
||||
.join(" ")
|
||||
)
|
||||
}
|
||||
|
||||
return <path id={id} d={pathCache.get(shape)} />
|
||||
},
|
||||
|
||||
applyStyles(shape, style) {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { current } from "immer"
|
|||
import { Data, DrawShape } from "types"
|
||||
import BaseSession from "./base-session"
|
||||
import { getShapeUtils } from "lib/shape-utils"
|
||||
import { getPage } from "utils/utils"
|
||||
import { getPage, simplify } from "utils/utils"
|
||||
import * as vec from "utils/vec"
|
||||
import commands from "state/commands"
|
||||
|
||||
|
@ -42,7 +42,15 @@ export default class BrushSession extends BaseSession {
|
|||
}
|
||||
|
||||
complete = (data: Data) => {
|
||||
commands.points(data, this.shapeId, this.snapshot.points, this.points)
|
||||
commands.points(
|
||||
data,
|
||||
this.shapeId,
|
||||
this.snapshot.points,
|
||||
simplify(this.points, 1).map(([x, y]) => [
|
||||
Math.trunc(x * 100) / 100,
|
||||
Math.trunc(y * 100) / 100,
|
||||
])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1492,3 +1492,41 @@ export function getCurrent<T extends object>(source: T): T {
|
|||
Object.entries(source).map(([key, value]) => [key, value])
|
||||
) as T
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplify a line (using Ramer-Douglas-Peucker algorithm).
|
||||
* @param points An array of points as [x, y, ...][]
|
||||
* @param tolerance The minimum line distance (also called epsilon).
|
||||
* @returns Simplified array as [x, y, ...][]
|
||||
*/
|
||||
export function simplify(points: number[][], tolerance = 1) {
|
||||
const len = points.length,
|
||||
a = points[0],
|
||||
b = points[len - 1],
|
||||
[x1, y1] = a,
|
||||
[x2, y2] = b
|
||||
|
||||
if (len > 2) {
|
||||
let distance = 0,
|
||||
index = 0,
|
||||
max = Math.hypot(y2 - y1, x2 - x1)
|
||||
|
||||
for (let i = 1; i < len - 1; i++) {
|
||||
const [x0, y0] = points[i],
|
||||
d = Math.abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1) / max
|
||||
|
||||
if (distance > d) continue
|
||||
|
||||
distance = d
|
||||
index = i
|
||||
}
|
||||
|
||||
if (distance > tolerance) {
|
||||
let l0 = simplify(points.slice(0, index + 1), tolerance)
|
||||
let l1 = simplify(points.slice(index + 1), tolerance)
|
||||
return l0.concat(l1.slice(1))
|
||||
}
|
||||
}
|
||||
|
||||
return [a, b]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue