Use js-bezier's BBox struct and functions.

pull/1/head
Atul Varma 2021-02-14 07:44:52 -05:00
rodzic 2b0d69bb87
commit 6d911e1654
4 zmienionych plików z 45 dodań i 86 usunięć

Wyświetl plik

@ -1,43 +1,41 @@
import { Bezier, Point } from "../vendor/bezier-js";
import { Bezier, Point, BBox, MinMax } from "../vendor/bezier-js";
import { SVGProps } from "react";
import type { SvgSymbolElement } from "./vocabulary";
import { flatten, float } from "./util";
import { pathToShapes } from "./path";
export type Bbox = {
minX: number;
minY: number;
maxX: number;
maxY: number;
};
export function getBoundingBoxSize(bbox: Bbox): [number, number] {
const width = bbox.maxX - bbox.minX;
const height = bbox.maxY - bbox.minY;
export function getBoundingBoxSize(bbox: BBox): [number, number] {
const width = bbox.x.max - bbox.x.min;
const height = bbox.y.max - bbox.y.min;
return [width, height];
}
export function getBoundingBoxCenter(bbox: Bbox): Point {
export function getBoundingBoxCenter(bbox: BBox): Point {
const [width, height] = getBoundingBoxSize(bbox);
return {
x: bbox.minX + width / 2,
y: bbox.minY + height / 2,
x: bbox.x.min + width / 2,
y: bbox.y.min + height / 2,
};
}
export function dilateBoundingBox(bbox: Bbox, amount: number): Bbox {
function dilateMinMax(minmax: MinMax, amount: number): MinMax {
return {
minX: bbox.minX - amount,
maxX: bbox.maxX + amount,
minY: bbox.minY - amount,
maxY: bbox.maxY + amount,
min: minmax.min - amount,
max: minmax.max + amount,
};
}
export function coalesceBoundingBoxes(bboxes: Bbox[]): Bbox {
export function dilateBoundingBox(bbox: BBox, amount: number): BBox {
return {
x: dilateMinMax(bbox.x, amount),
y: dilateMinMax(bbox.y, amount),
};
}
export function coalesceBoundingBoxes(bboxes: BBox[]): BBox {
let minX = Infinity;
let minY = Infinity;
let maxX = -Infinity;
@ -48,64 +46,28 @@ export function coalesceBoundingBoxes(bboxes: Bbox[]): Bbox {
}
for (let bbox of bboxes) {
if (bbox.minX < minX) {
minX = bbox.minX;
if (bbox.x.min < minX) {
minX = bbox.x.min;
}
if (bbox.maxX > maxX) {
maxX = bbox.maxX;
if (bbox.x.max > maxX) {
maxX = bbox.x.max;
}
if (bbox.minY < minY) {
minY = bbox.minY;
if (bbox.y.min < minY) {
minY = bbox.y.min;
}
if (bbox.maxY > maxY) {
maxY = bbox.maxY;
if (bbox.y.max > maxY) {
maxY = bbox.y.max;
}
}
return { minX, minY, maxX, maxY };
return { x: { min: minX, max: maxX }, y: { min: minY, max: maxY } };
}
function getBoundingBoxForPoints(points: Point[]): Bbox {
let minX = Infinity;
let minY = Infinity;
let maxX = -Infinity;
let maxY = -Infinity;
if (points.length === 0) {
throw new Error(`Must have at least one point!`);
}
for (let point of points) {
if (point.x < minX) {
minX = point.x;
}
if (point.x > maxX) {
maxX = point.x;
}
if (point.y < minY) {
minY = point.y;
}
if (point.y > maxY) {
maxY = point.y;
}
}
return { minX, minY, maxX, maxY };
export function getBoundingBoxForBeziers(beziers: Bezier[]): BBox {
return coalesceBoundingBoxes(beziers.map((b) => b.bbox()));
}
function getBezierBoundingBox(bezier: Bezier): Bbox {
const start = bezier.get(0.0);
const end = bezier.get(1.0);
const extrema = bezier.extrema().values.map((t) => bezier.get(t));
return getBoundingBoxForPoints([start, end, ...extrema]);
}
export function getBoundingBoxForBeziers(beziers: Bezier[]): Bbox {
return coalesceBoundingBoxes(beziers.map(getBezierBoundingBox));
}
function getPathBoundingBox(props: SVGProps<SVGPathElement>): Bbox {
function getPathBoundingBox(props: SVGProps<SVGPathElement>): BBox {
if (!props.d) {
throw new Error(`SVG path has no 'd' attribute value!`);
}
@ -118,7 +80,7 @@ function getPathBoundingBox(props: SVGProps<SVGPathElement>): Bbox {
export function getSvgBoundingBox(
element: SvgSymbolElement | SvgSymbolElement[]
): Bbox {
): BBox {
if (Array.isArray(element)) {
return coalesceBoundingBoxes(element.map(getSvgBoundingBox));
}

Wyświetl plik

@ -1,7 +1,7 @@
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { Point } from "../vendor/bezier-js";
import { Bbox, dilateBoundingBox, getBoundingBoxSize } from "./bounding-box";
import { Point, BBox } from "../vendor/bezier-js";
import { dilateBoundingBox, getBoundingBoxSize } from "./bounding-box";
import { FILL_REPLACEMENT_COLOR, STROKE_REPLACEMENT_COLOR } from "./colors";
import * as colors from "./colors";
import { Specs } from "./specs";
@ -84,15 +84,15 @@ const AttachmentPoints: React.FC<{ color: string; points: Point[] }> = (
</>
);
const BoundingBoxes: React.FC<{ fill: string; bboxes: Bbox[] }> = (props) => (
const BoundingBoxes: React.FC<{ fill: string; bboxes: BBox[] }> = (props) => (
<>
{props.bboxes.map((b, i) => {
const [width, height] = getBoundingBoxSize(b);
return (
<rect
key={i}
x={b.minX}
y={b.minY}
x={b.x.min}
y={b.y.min}
width={width}
height={height}
fill={props.fill}
@ -155,7 +155,7 @@ const SvgSymbol: React.FC<SvgSymbolProps> = (props) => {
return (
<svg
viewBox={`${bbox.minX} ${bbox.minY} ${width} ${height}`}
viewBox={`${bbox.x.min} ${bbox.y.min} ${width} ${height}`}
width={px(width * scale)}
height={px(height * scale)}
>

Wyświetl plik

@ -1,9 +1,5 @@
import { Point } from "../vendor/bezier-js";
import {
Bbox,
getBoundingBoxCenter,
getBoundingBoxForBeziers,
} from "./bounding-box";
import { Point, BBox } from "../vendor/bezier-js";
import { getBoundingBoxCenter, getBoundingBoxForBeziers } from "./bounding-box";
import * as colors from "./colors";
import { pathToShapes } from "./path";
import type { SvgSymbolElement } from "./vocabulary";
@ -16,7 +12,7 @@ export type Specs = {
arm?: Point[];
horn?: Point[];
crown?: Point[];
nesting?: Bbox[];
nesting?: BBox[];
};
function getPoints(path: string): Point[] {
@ -31,9 +27,9 @@ function getPoints(path: string): Point[] {
return points;
}
function getBoundingBoxes(path: string): Bbox[] {
function getBoundingBoxes(path: string): BBox[] {
const shapes = pathToShapes(path);
const bboxes: Bbox[] = [];
const bboxes: BBox[] = [];
for (let shape of shapes) {
bboxes.push(getBoundingBoxForBeziers(shape));

Wyświetl plik

@ -2,12 +2,13 @@ import fs from "fs";
import path from "path";
import cheerio from "cheerio";
import { SVGProps } from "react";
import { getSvgBoundingBox, Bbox } from "./bounding-box";
import { BBox } from "../vendor/bezier-js";
import { getSvgBoundingBox } from "./bounding-box";
import { Specs, extractSpecs } from "./specs";
export type SvgSymbolData = {
name: string;
bbox: Bbox;
bbox: BBox;
layers: SvgSymbolElement[];
specs?: Specs;
};