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 type { Patch, TLBoundsWithCenter } from '+index'
|
||||
|
||||
const TAU = Math.PI * 2
|
||||
|
||||
export class Utils {
|
||||
/* -------------------------------------------------- */
|
||||
/* Math & Geometry */
|
||||
|
@ -467,9 +469,9 @@ export class Utils {
|
|||
*/
|
||||
static isAngleBetween(a: number, b: number, c: number): boolean {
|
||||
if (c === a || c === b) return true
|
||||
const PI2 = Math.PI * 2
|
||||
const AB = (b - a + PI2) % PI2
|
||||
const AC = (c - a + PI2) % PI2
|
||||
|
||||
const AB = (b - a + TAU) % TAU
|
||||
const AC = (c - a + TAU) % TAU
|
||||
return AB <= Math.PI !== AC > AB
|
||||
}
|
||||
|
||||
|
@ -497,10 +499,24 @@ export class Utils {
|
|||
* @param B
|
||||
*/
|
||||
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))
|
||||
}
|
||||
|
||||
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.
|
||||
* @param C
|
||||
|
@ -510,7 +526,7 @@ export class Utils {
|
|||
* @param step
|
||||
*/
|
||||
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 off0 = del0 < 0 ? len0 : 2 * Math.PI * C[2] - len0
|
||||
return -off0 / 2 + step
|
||||
|
|
|
@ -728,6 +728,7 @@ function getCurvedArrowHeadPoints(
|
|||
sweep: boolean
|
||||
) {
|
||||
const ints = intersectCircleCircle(A, r1 * 0.618, C, r2).points
|
||||
|
||||
if (!ints) {
|
||||
console.warn('Could not find an intersection for the arrow head.')
|
||||
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 right = int ? Vec.rotWith(int, A, -Math.PI / 6) : A
|
||||
|
||||
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 boundsForShapes = initialShapes.map((shape) => {
|
||||
return {
|
||||
id: shape.id,
|
||||
point: [...shape.point],
|
||||
bounds: TLDR.getShapeUtils(shape).getBounds(shape),
|
||||
}
|
||||
})
|
||||
const boundsForShapes = initialShapes.map((shape) => ({
|
||||
id: shape.id,
|
||||
point: [...shape.point],
|
||||
bounds: TLDR.getShapeUtils(shape).getBounds(shape),
|
||||
}))
|
||||
|
||||
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(
|
||||
data,
|
||||
ids,
|
||||
(shape) => {
|
||||
if (!deltaMap[shape.id]) return shape
|
||||
return { point: deltaMap[shape.id].next }
|
||||
},
|
||||
(shape) => (deltaMap[shape.id] ? { point: deltaMap[shape.id].next } : shape),
|
||||
currentPageId
|
||||
)
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ export class Vec {
|
|||
* @returns
|
||||
*/
|
||||
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[],
|
||||
clamp = true
|
||||
): number[] => {
|
||||
const delta = Vec.sub(B, A)
|
||||
const length = Vec.len(delta)
|
||||
const u = Vec.div(delta, length)
|
||||
|
||||
const pt = Vec.add(A, Vec.mul(u, Vec.pry(Vec.sub(P, A), u)))
|
||||
const u = Vec.uni(Vec.sub(B, A))
|
||||
const C = Vec.add(A, Vec.mul(u, Vec.pry(Vec.sub(P, A), u)))
|
||||
|
||||
if (clamp) {
|
||||
const da = Vec.dist(A, pt)
|
||||
const db = Vec.dist(B, pt)
|
||||
|
||||
if (db < da && da > length) return B
|
||||
if (da < db && db > length) return A
|
||||
if (C[0] < Math.min(A[0], B[0])) return A[0] < B[0] ? A : B
|
||||
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 (C[1] > Math.max(A[1], B[1])) return A[1] > B[1] ? A : B
|
||||
}
|
||||
|
||||
return pt
|
||||
return C
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -483,7 +479,7 @@ export class Vec {
|
|||
* @returns
|
||||
*/
|
||||
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