minor utils tweaks
This commit is contained in:
parent
ac4849a360
commit
8d6fe119a5
4 changed files with 38 additions and 29 deletions
|
@ -15,6 +15,8 @@ import { Vec } from '@tldraw/vec'
|
||||||
import './polyfills'
|
import './polyfills'
|
||||||
import type { Patch, TLBoundsWithCenter } from '+index'
|
import type { Patch, TLBoundsWithCenter } from '+index'
|
||||||
|
|
||||||
|
const TAU = Math.PI * 2
|
||||||
|
|
||||||
export class Utils {
|
export class Utils {
|
||||||
/* -------------------------------------------------- */
|
/* -------------------------------------------------- */
|
||||||
/* Math & Geometry */
|
/* Math & Geometry */
|
||||||
|
@ -467,9 +469,9 @@ export class Utils {
|
||||||
*/
|
*/
|
||||||
static isAngleBetween(a: number, b: number, c: number): boolean {
|
static isAngleBetween(a: number, b: number, c: number): boolean {
|
||||||
if (c === a || c === b) return true
|
if (c === a || c === b) return true
|
||||||
const PI2 = Math.PI * 2
|
|
||||||
const AB = (b - a + PI2) % PI2
|
const AB = (b - a + TAU) % TAU
|
||||||
const AC = (c - a + PI2) % PI2
|
const AC = (c - a + TAU) % TAU
|
||||||
return AB <= Math.PI !== AC > AB
|
return AB <= Math.PI !== AC > AB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,10 +499,24 @@ export class Utils {
|
||||||
* @param B
|
* @param B
|
||||||
*/
|
*/
|
||||||
static getArcLength(C: number[], r: number, A: number[], B: number[]): number {
|
static getArcLength(C: number[], r: number, A: number[], B: number[]): number {
|
||||||
const sweep = Utils.getSweep(C, A, B)
|
const sweep = Utils.getSweepFlag(C, A, B)
|
||||||
return r * (2 * Math.PI) * (sweep / (2 * Math.PI))
|
return r * (2 * Math.PI) * (sweep / (2 * Math.PI))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getSweepFlag(A: number[], B: number[], C: number[]) {
|
||||||
|
const angleAC = Vec.angle(A, C)
|
||||||
|
const angleAB = Vec.angle(A, B)
|
||||||
|
const angleCAB = ((angleAB - angleAC + 3 * Math.PI) % (2 * Math.PI)) - Math.PI
|
||||||
|
return angleCAB > 0 ? 0 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
static getLargeArcFlag(A: number[], C: number[], P: number[]) {
|
||||||
|
const anglePA = Vec.angle(P, A)
|
||||||
|
const anglePC = Vec.angle(P, C)
|
||||||
|
const angleAPC = ((anglePC - anglePA + 3 * Math.PI) % (2 * Math.PI)) - Math.PI
|
||||||
|
return Math.abs(angleAPC) > Math.PI / 2 ? 0 : 1
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a dash offset for an arc, based on its length.
|
* Get a dash offset for an arc, based on its length.
|
||||||
* @param C
|
* @param C
|
||||||
|
@ -510,7 +526,7 @@ export class Utils {
|
||||||
* @param step
|
* @param step
|
||||||
*/
|
*/
|
||||||
static getArcDashOffset(C: number[], r: number, A: number[], B: number[], step: number): number {
|
static getArcDashOffset(C: number[], r: number, A: number[], B: number[], step: number): number {
|
||||||
const del0 = Utils.getSweep(C, A, B)
|
const del0 = Utils.getSweepFlag(C, A, B)
|
||||||
const len0 = Utils.getArcLength(C, r, A, B)
|
const len0 = Utils.getArcLength(C, r, A, B)
|
||||||
const off0 = del0 < 0 ? len0 : 2 * Math.PI * C[2] - len0
|
const off0 = del0 < 0 ? len0 : 2 * Math.PI * C[2] - len0
|
||||||
return -off0 / 2 + step
|
return -off0 / 2 + step
|
||||||
|
|
|
@ -728,6 +728,7 @@ function getCurvedArrowHeadPoints(
|
||||||
sweep: boolean
|
sweep: boolean
|
||||||
) {
|
) {
|
||||||
const ints = intersectCircleCircle(A, r1 * 0.618, C, r2).points
|
const ints = intersectCircleCircle(A, r1 * 0.618, C, r2).points
|
||||||
|
|
||||||
if (!ints) {
|
if (!ints) {
|
||||||
console.warn('Could not find an intersection for the arrow head.')
|
console.warn('Could not find an intersection for the arrow head.')
|
||||||
return { left: A, right: A }
|
return { left: A, right: A }
|
||||||
|
@ -754,6 +755,7 @@ function getStraightArrowHeadPoints(A: number[], B: number[], r: number) {
|
||||||
const left = int ? Vec.rotWith(int, A, Math.PI / 6) : A
|
const left = int ? Vec.rotWith(int, A, Math.PI / 6) : A
|
||||||
|
|
||||||
const right = int ? Vec.rotWith(int, A, -Math.PI / 6) : A
|
const right = int ? Vec.rotWith(int, A, -Math.PI / 6) : A
|
||||||
|
|
||||||
return { left, right }
|
return { left, right }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,11 @@ export function align(data: Data, ids: string[], type: AlignType): TLDrawCommand
|
||||||
|
|
||||||
const initialShapes = ids.map((id) => TLDR.getShape(data, id, currentPageId))
|
const initialShapes = ids.map((id) => TLDR.getShape(data, id, currentPageId))
|
||||||
|
|
||||||
const boundsForShapes = initialShapes.map((shape) => {
|
const boundsForShapes = initialShapes.map((shape) => ({
|
||||||
return {
|
|
||||||
id: shape.id,
|
id: shape.id,
|
||||||
point: [...shape.point],
|
point: [...shape.point],
|
||||||
bounds: TLDR.getShapeUtils(shape).getBounds(shape),
|
bounds: TLDR.getShapeUtils(shape).getBounds(shape),
|
||||||
}
|
}))
|
||||||
})
|
|
||||||
|
|
||||||
const commonBounds = Utils.getCommonBounds(boundsForShapes.map(({ bounds }) => bounds))
|
const commonBounds = Utils.getCommonBounds(boundsForShapes.map(({ bounds }) => bounds))
|
||||||
|
|
||||||
|
@ -46,10 +44,7 @@ export function align(data: Data, ids: string[], type: AlignType): TLDrawCommand
|
||||||
const { before, after } = TLDR.mutateShapes(
|
const { before, after } = TLDR.mutateShapes(
|
||||||
data,
|
data,
|
||||||
ids,
|
ids,
|
||||||
(shape) => {
|
(shape) => (deltaMap[shape.id] ? { point: deltaMap[shape.id].next } : shape),
|
||||||
if (!deltaMap[shape.id]) return shape
|
|
||||||
return { point: deltaMap[shape.id].next }
|
|
||||||
},
|
|
||||||
currentPageId
|
currentPageId
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -197,7 +197,7 @@ export class Vec {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
static tangent = (A: number[], B: number[]): number[] => {
|
static tangent = (A: number[], B: number[]): number[] => {
|
||||||
return Vec.normalize(Vec.sub(A, B))
|
return Vec.uni(Vec.sub(A, B))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -446,21 +446,17 @@ export class Vec {
|
||||||
P: number[],
|
P: number[],
|
||||||
clamp = true
|
clamp = true
|
||||||
): number[] => {
|
): number[] => {
|
||||||
const delta = Vec.sub(B, A)
|
const u = Vec.uni(Vec.sub(B, A))
|
||||||
const length = Vec.len(delta)
|
const C = Vec.add(A, Vec.mul(u, Vec.pry(Vec.sub(P, A), u)))
|
||||||
const u = Vec.div(delta, length)
|
|
||||||
|
|
||||||
const pt = Vec.add(A, Vec.mul(u, Vec.pry(Vec.sub(P, A), u)))
|
|
||||||
|
|
||||||
if (clamp) {
|
if (clamp) {
|
||||||
const da = Vec.dist(A, pt)
|
if (C[0] < Math.min(A[0], B[0])) return A[0] < B[0] ? A : B
|
||||||
const db = Vec.dist(B, pt)
|
if (C[0] > Math.max(A[0], B[0])) return A[0] > B[0] ? A : B
|
||||||
|
if (C[1] < Math.min(A[1], B[1])) return A[1] < B[1] ? A : B
|
||||||
if (db < da && da > length) return B
|
if (C[1] > Math.max(A[1], B[1])) return A[1] > B[1] ? A : B
|
||||||
if (da < db && db > length) return A
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pt
|
return C
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -483,7 +479,7 @@ export class Vec {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
static nudge = (A: number[], B: number[], d: number): number[] => {
|
static nudge = (A: number[], B: number[], d: number): number[] => {
|
||||||
return Vec.add(A, Vec.mul(Vec.uni(Vec.vec(A, B)), d))
|
return Vec.add(A, Vec.mul(Vec.uni(Vec.sub(B, A)), d))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue