123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984 |
- "use strict";
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
- if (k2 === undefined) k2 = k;
- var desc = Object.getOwnPropertyDescriptor(m, k);
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
- desc = { enumerable: true, get: function() { return m[k]; } };
- }
- Object.defineProperty(o, k2, desc);
- }) : (function(o, m, k, k2) {
- if (k2 === undefined) k2 = k;
- o[k2] = m[k];
- }));
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
- Object.defineProperty(o, "default", { enumerable: true, value: v });
- }) : function(o, v) {
- o["default"] = v;
- });
- var __importStar = (this && this.__importStar) || function (mod) {
- if (mod && mod.__esModule) return mod;
- var result = {};
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
- __setModuleDefault(result, mod);
- return result;
- };
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.Path = void 0;
- const util_1 = require("../util");
- const PathUtil = __importStar(require("./util"));
- const line_1 = require("../line");
- const point_1 = require("../point");
- const curve_1 = require("../curve");
- const polyline_1 = require("../polyline");
- const rectangle_1 = require("../rectangle");
- const geometry_1 = require("../geometry");
- const close_1 = require("./close");
- const lineto_1 = require("./lineto");
- const moveto_1 = require("./moveto");
- const curveto_1 = require("./curveto");
- const normalize_1 = require("./normalize");
- class Path extends geometry_1.Geometry {
- constructor(args) {
- super();
- this.PRECISION = 3;
- this.segments = [];
- if (Array.isArray(args)) {
- if (line_1.Line.isLine(args[0]) || curve_1.Curve.isCurve(args[0])) {
- let previousObj = null;
- const arr = args;
- arr.forEach((o, i) => {
- if (i === 0) {
- this.appendSegment(Path.createSegment('M', o.start));
- }
- if (previousObj != null && !previousObj.end.equals(o.start)) {
- this.appendSegment(Path.createSegment('M', o.start));
- }
- if (line_1.Line.isLine(o)) {
- this.appendSegment(Path.createSegment('L', o.end));
- }
- else if (curve_1.Curve.isCurve(o)) {
- this.appendSegment(Path.createSegment('C', o.controlPoint1, o.controlPoint2, o.end));
- }
- previousObj = o;
- });
- }
- else {
- const arr = args;
- arr.forEach((s) => {
- if (s.isSegment) {
- this.appendSegment(s);
- }
- });
- }
- }
- else if (args != null) {
- if (line_1.Line.isLine(args)) {
- this.appendSegment(Path.createSegment('M', args.start));
- this.appendSegment(Path.createSegment('L', args.end));
- }
- else if (curve_1.Curve.isCurve(args)) {
- this.appendSegment(Path.createSegment('M', args.start));
- this.appendSegment(Path.createSegment('C', args.controlPoint1, args.controlPoint2, args.end));
- }
- else if (polyline_1.Polyline.isPolyline(args)) {
- if (args.points && args.points.length) {
- args.points.forEach((point, index) => {
- const segment = index === 0
- ? Path.createSegment('M', point)
- : Path.createSegment('L', point);
- this.appendSegment(segment);
- });
- }
- }
- else if (args.isSegment) {
- this.appendSegment(args);
- }
- }
- }
- get start() {
- const segments = this.segments;
- const count = segments.length;
- if (count === 0) {
- return null;
- }
- for (let i = 0; i < count; i += 1) {
- const segment = segments[i];
- if (segment.isVisible) {
- return segment.start;
- }
- }
- // if no visible segment, return last segment end point
- return segments[count - 1].end;
- }
- get end() {
- const segments = this.segments;
- const count = segments.length;
- if (count === 0) {
- return null;
- }
- for (let i = count - 1; i >= 0; i -= 1) {
- const segment = segments[i];
- if (segment.isVisible) {
- return segment.end;
- }
- }
- // if no visible segment, return last segment end point
- return segments[count - 1].end;
- }
- moveTo(...args) {
- return this.appendSegment(moveto_1.MoveTo.create.call(null, ...args));
- }
- lineTo(...args) {
- return this.appendSegment(lineto_1.LineTo.create.call(null, ...args));
- }
- curveTo(...args) {
- return this.appendSegment(curveto_1.CurveTo.create.call(null, ...args));
- }
- arcTo(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, endX, endY) {
- const start = this.end || new point_1.Point();
- const points = typeof endX === 'number'
- ? PathUtil.arcToCurves(start.x, start.y, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, endX, endY)
- : PathUtil.arcToCurves(start.x, start.y, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, endX.x, endX.y);
- if (points != null) {
- for (let i = 0, ii = points.length; i < ii; i += 6) {
- this.curveTo(points[i], points[i + 1], points[i + 2], points[i + 3], points[i + 4], points[i + 5]);
- }
- }
- return this;
- }
- quadTo(x1, y1, x, y) {
- const start = this.end || new point_1.Point();
- const data = ['M', start.x, start.y];
- if (typeof x1 === 'number') {
- data.push('Q', x1, y1, x, y);
- }
- else {
- const p = y1;
- data.push(`Q`, x1.x, x1.y, p.x, p.y);
- }
- const path = Path.parse(data.join(' '));
- this.appendSegment(path.segments.slice(1));
- return this;
- }
- close() {
- return this.appendSegment(close_1.Close.create());
- }
- drawPoints(points, options = {}) {
- const raw = PathUtil.drawPoints(points, options);
- const sub = Path.parse(raw);
- if (sub && sub.segments) {
- this.appendSegment(sub.segments);
- }
- }
- bbox() {
- const segments = this.segments;
- const count = segments.length;
- if (count === 0) {
- return null;
- }
- let bbox;
- for (let i = 0; i < count; i += 1) {
- const segment = segments[i];
- if (segment.isVisible) {
- const segmentBBox = segment.bbox();
- if (segmentBBox != null) {
- bbox = bbox ? bbox.union(segmentBBox) : segmentBBox;
- }
- }
- }
- if (bbox != null) {
- return bbox;
- }
- // if the path has only invisible elements, return end point of last segment
- const lastSegment = segments[count - 1];
- return new rectangle_1.Rectangle(lastSegment.end.x, lastSegment.end.y, 0, 0);
- }
- appendSegment(seg) {
- const count = this.segments.length;
- let previousSegment = count !== 0 ? this.segments[count - 1] : null;
- let currentSegment;
- const nextSegment = null;
- if (Array.isArray(seg)) {
- for (let i = 0, ii = seg.length; i < ii; i += 1) {
- const segment = seg[i];
- currentSegment = this.prepareSegment(segment, previousSegment, nextSegment);
- this.segments.push(currentSegment);
- previousSegment = currentSegment;
- }
- }
- else if (seg != null && seg.isSegment) {
- currentSegment = this.prepareSegment(seg, previousSegment, nextSegment);
- this.segments.push(currentSegment);
- }
- return this;
- }
- insertSegment(index, seg) {
- const count = this.segments.length;
- if (index < 0) {
- index = count + index + 1; // eslint-disable-line
- }
- if (index > count || index < 0) {
- throw new Error('Index out of range.');
- }
- let currentSegment;
- let previousSegment = null;
- let nextSegment = null;
- if (count !== 0) {
- if (index >= 1) {
- previousSegment = this.segments[index - 1];
- nextSegment = previousSegment.nextSegment;
- }
- else {
- previousSegment = null;
- nextSegment = this.segments[0];
- }
- }
- if (!Array.isArray(seg)) {
- currentSegment = this.prepareSegment(seg, previousSegment, nextSegment);
- this.segments.splice(index, 0, currentSegment);
- }
- else {
- for (let i = 0, ii = seg.length; i < ii; i += 1) {
- const segment = seg[i];
- currentSegment = this.prepareSegment(segment, previousSegment, nextSegment);
- this.segments.splice(index + i, 0, currentSegment);
- previousSegment = currentSegment;
- }
- }
- return this;
- }
- removeSegment(index) {
- const idx = this.fixIndex(index);
- const removedSegment = this.segments.splice(idx, 1)[0];
- const previousSegment = removedSegment.previousSegment;
- const nextSegment = removedSegment.nextSegment;
- // link the previous and next segments together (if present)
- if (previousSegment) {
- previousSegment.nextSegment = nextSegment;
- }
- if (nextSegment) {
- nextSegment.previousSegment = previousSegment;
- }
- if (removedSegment.isSubpathStart && nextSegment) {
- this.updateSubpathStartSegment(nextSegment);
- }
- return removedSegment;
- }
- replaceSegment(index, seg) {
- const idx = this.fixIndex(index);
- let currentSegment;
- const replacedSegment = this.segments[idx];
- let previousSegment = replacedSegment.previousSegment;
- const nextSegment = replacedSegment.nextSegment;
- let updateSubpathStart = replacedSegment.isSubpathStart;
- if (!Array.isArray(seg)) {
- currentSegment = this.prepareSegment(seg, previousSegment, nextSegment);
- this.segments.splice(idx, 1, currentSegment);
- if (updateSubpathStart && currentSegment.isSubpathStart) {
- // already updated by `prepareSegment`
- updateSubpathStart = false;
- }
- }
- else {
- this.segments.splice(index, 1);
- for (let i = 0, ii = seg.length; i < ii; i += 1) {
- const segment = seg[i];
- currentSegment = this.prepareSegment(segment, previousSegment, nextSegment);
- this.segments.splice(index + i, 0, currentSegment);
- previousSegment = currentSegment;
- if (updateSubpathStart && currentSegment.isSubpathStart) {
- updateSubpathStart = false;
- }
- }
- }
- if (updateSubpathStart && nextSegment) {
- this.updateSubpathStartSegment(nextSegment);
- }
- }
- getSegment(index) {
- const idx = this.fixIndex(index);
- return this.segments[idx];
- }
- fixIndex(index) {
- const length = this.segments.length;
- if (length === 0) {
- throw new Error('Path has no segments.');
- }
- let i = index;
- while (i < 0) {
- i = length + i;
- }
- if (i >= length || i < 0) {
- throw new Error('Index out of range.');
- }
- return i;
- }
- segmentAt(ratio, options = {}) {
- const index = this.segmentIndexAt(ratio, options);
- if (!index) {
- return null;
- }
- return this.getSegment(index);
- }
- segmentAtLength(length, options = {}) {
- const index = this.segmentIndexAtLength(length, options);
- if (!index)
- return null;
- return this.getSegment(index);
- }
- segmentIndexAt(ratio, options = {}) {
- if (this.segments.length === 0) {
- return null;
- }
- const rate = util_1.GeometryUtil.clamp(ratio, 0, 1);
- const opt = this.getOptions(options);
- const len = this.length(opt);
- const length = len * rate;
- return this.segmentIndexAtLength(length, opt);
- }
- segmentIndexAtLength(length, options = {}) {
- const count = this.segments.length;
- if (count === 0) {
- return null;
- }
- let fromStart = true;
- if (length < 0) {
- fromStart = false;
- length = -length; // eslint-disable-line
- }
- const precision = this.getPrecision(options);
- const segmentSubdivisions = this.getSubdivisions(options);
- let memo = 0;
- let lastVisibleIndex = null;
- for (let i = 0; i < count; i += 1) {
- const index = fromStart ? i : count - 1 - i;
- const segment = this.segments[index];
- const subdivisions = segmentSubdivisions[index];
- const len = segment.length({ precision, subdivisions });
- if (segment.isVisible) {
- if (length <= memo + len) {
- return index;
- }
- lastVisibleIndex = index;
- }
- memo += len;
- }
- // If length requested is higher than the length of the path, return
- // last visible segment index. If no visible segment, return null.
- return lastVisibleIndex;
- }
- getSegmentSubdivisions(options = {}) {
- const precision = this.getPrecision(options);
- const segmentSubdivisions = [];
- for (let i = 0, ii = this.segments.length; i < ii; i += 1) {
- const segment = this.segments[i];
- const subdivisions = segment.getSubdivisions({ precision });
- segmentSubdivisions.push(subdivisions);
- }
- return segmentSubdivisions;
- }
- updateSubpathStartSegment(segment) {
- let previous = segment.previousSegment;
- let current = segment;
- while (current && !current.isSubpathStart) {
- // assign previous segment's subpath start segment to this segment
- if (previous != null) {
- current.subpathStartSegment = previous.subpathStartSegment;
- }
- else {
- current.subpathStartSegment = null;
- }
- previous = current;
- current = current.nextSegment;
- }
- }
- prepareSegment(segment, previousSegment, nextSegment) {
- segment.previousSegment = previousSegment;
- segment.nextSegment = nextSegment;
- if (previousSegment != null) {
- previousSegment.nextSegment = segment;
- }
- if (nextSegment != null) {
- nextSegment.previousSegment = segment;
- }
- let updateSubpathStart = segment;
- if (segment.isSubpathStart) {
- // move to
- segment.subpathStartSegment = segment;
- updateSubpathStart = nextSegment;
- }
- // assign previous segment's subpath start (or self if it is a subpath start) to subsequent segments
- if (updateSubpathStart != null) {
- this.updateSubpathStartSegment(updateSubpathStart);
- }
- return segment;
- }
- closestPoint(p, options = {}) {
- const t = this.closestPointT(p, options);
- if (!t) {
- return null;
- }
- return this.pointAtT(t);
- }
- closestPointLength(p, options = {}) {
- const opts = this.getOptions(options);
- const t = this.closestPointT(p, opts);
- if (!t) {
- return 0;
- }
- return this.lengthAtT(t, opts);
- }
- closestPointNormalizedLength(p, options = {}) {
- const opts = this.getOptions(options);
- const cpLength = this.closestPointLength(p, opts);
- if (cpLength === 0) {
- return 0;
- }
- const length = this.length(opts);
- if (length === 0) {
- return 0;
- }
- return cpLength / length;
- }
- closestPointT(p, options = {}) {
- if (this.segments.length === 0) {
- return null;
- }
- const precision = this.getPrecision(options);
- const segmentSubdivisions = this.getSubdivisions(options);
- let closestPointT;
- let minSquaredDistance = Infinity;
- for (let i = 0, ii = this.segments.length; i < ii; i += 1) {
- const segment = this.segments[i];
- const subdivisions = segmentSubdivisions[i];
- if (segment.isVisible) {
- const segmentClosestPointT = segment.closestPointT(p, {
- precision,
- subdivisions,
- });
- const segmentClosestPoint = segment.pointAtT(segmentClosestPointT);
- const squaredDistance = util_1.GeometryUtil.squaredLength(segmentClosestPoint, p);
- if (squaredDistance < minSquaredDistance) {
- closestPointT = { segmentIndex: i, value: segmentClosestPointT };
- minSquaredDistance = squaredDistance;
- }
- }
- }
- if (closestPointT) {
- return closestPointT;
- }
- return { segmentIndex: this.segments.length - 1, value: 1 };
- }
- closestPointTangent(p, options = {}) {
- if (this.segments.length === 0) {
- return null;
- }
- const precision = this.getPrecision(options);
- const segmentSubdivisions = this.getSubdivisions(options);
- let closestPointTangent;
- let minSquaredDistance = Infinity;
- for (let i = 0, ii = this.segments.length; i < ii; i += 1) {
- const segment = this.segments[i];
- const subdivisions = segmentSubdivisions[i];
- if (segment.isDifferentiable()) {
- const segmentClosestPointT = segment.closestPointT(p, {
- precision,
- subdivisions,
- });
- const segmentClosestPoint = segment.pointAtT(segmentClosestPointT);
- const squaredDistance = util_1.GeometryUtil.squaredLength(segmentClosestPoint, p);
- if (squaredDistance < minSquaredDistance) {
- closestPointTangent = segment.tangentAtT(segmentClosestPointT);
- minSquaredDistance = squaredDistance;
- }
- }
- }
- if (closestPointTangent) {
- return closestPointTangent;
- }
- return null;
- }
- containsPoint(p, options = {}) {
- const polylines = this.toPolylines(options);
- if (!polylines) {
- return false;
- }
- let numIntersections = 0;
- for (let i = 0, ii = polylines.length; i < ii; i += 1) {
- const polyline = polylines[i];
- if (polyline.containsPoint(p)) {
- numIntersections += 1;
- }
- }
- // returns `true` for odd numbers of intersections (even-odd algorithm)
- return numIntersections % 2 === 1;
- }
- pointAt(ratio, options = {}) {
- if (this.segments.length === 0) {
- return null;
- }
- if (ratio <= 0) {
- return this.start.clone();
- }
- if (ratio >= 1) {
- return this.end.clone();
- }
- const opts = this.getOptions(options);
- const pathLength = this.length(opts);
- const length = pathLength * ratio;
- return this.pointAtLength(length, opts);
- }
- pointAtLength(length, options = {}) {
- if (this.segments.length === 0) {
- return null;
- }
- if (length === 0) {
- return this.start.clone();
- }
- let fromStart = true;
- if (length < 0) {
- fromStart = false;
- length = -length; // eslint-disable-line
- }
- const precision = this.getPrecision(options);
- const segmentSubdivisions = this.getSubdivisions(options);
- let lastVisibleSegment;
- let memo = 0;
- for (let i = 0, ii = this.segments.length; i < ii; i += 1) {
- const index = fromStart ? i : ii - 1 - i;
- const segment = this.segments[index];
- const subdivisions = segmentSubdivisions[index];
- const d = segment.length({
- precision,
- subdivisions,
- });
- if (segment.isVisible) {
- if (length <= memo + d) {
- return segment.pointAtLength((fromStart ? 1 : -1) * (length - memo), {
- precision,
- subdivisions,
- });
- }
- lastVisibleSegment = segment;
- }
- memo += d;
- }
- // if length requested is higher than the length of the path,
- // return last visible segment endpoint
- if (lastVisibleSegment) {
- return fromStart ? lastVisibleSegment.end : lastVisibleSegment.start;
- }
- // if no visible segment, return last segment end point
- const lastSegment = this.segments[this.segments.length - 1];
- return lastSegment.end.clone();
- }
- pointAtT(t) {
- const segments = this.segments;
- const numSegments = segments.length;
- if (numSegments === 0)
- return null; // if segments is an empty array
- const segmentIndex = t.segmentIndex;
- if (segmentIndex < 0)
- return segments[0].pointAtT(0);
- if (segmentIndex >= numSegments) {
- return segments[numSegments - 1].pointAtT(1);
- }
- const tValue = util_1.GeometryUtil.clamp(t.value, 0, 1);
- return segments[segmentIndex].pointAtT(tValue);
- }
- divideAt(ratio, options = {}) {
- if (this.segments.length === 0) {
- return null;
- }
- const rate = util_1.GeometryUtil.clamp(ratio, 0, 1);
- const opts = this.getOptions(options);
- const len = this.length(opts);
- const length = len * rate;
- return this.divideAtLength(length, opts);
- }
- divideAtLength(length, options = {}) {
- if (this.segments.length === 0) {
- return null;
- }
- let fromStart = true;
- if (length < 0) {
- fromStart = false;
- length = -length; // eslint-disable-line
- }
- const precision = this.getPrecision(options);
- const segmentSubdivisions = this.getSubdivisions(options);
- let memo = 0;
- let divided;
- let dividedSegmentIndex;
- let lastValidSegment;
- let lastValidSegmentIndex;
- let t;
- for (let i = 0, ii = this.segments.length; i < ii; i += 1) {
- const index = fromStart ? i : ii - 1 - i;
- const segment = this.getSegment(index);
- const subdivisions = segmentSubdivisions[index];
- const opts = { precision, subdivisions };
- const len = segment.length(opts);
- if (segment.isDifferentiable()) {
- lastValidSegment = segment;
- lastValidSegmentIndex = index;
- if (length <= memo + len) {
- dividedSegmentIndex = index;
- divided = segment.divideAtLength((fromStart ? 1 : -1) * (length - memo), opts);
- break;
- }
- }
- memo += len;
- }
- if (!lastValidSegment) {
- return null;
- }
- if (!divided) {
- dividedSegmentIndex = lastValidSegmentIndex;
- t = fromStart ? 1 : 0;
- divided = lastValidSegment.divideAtT(t);
- }
- // create a copy of this path and replace the identified segment with its two divided parts:
- const pathCopy = this.clone();
- const index = dividedSegmentIndex;
- pathCopy.replaceSegment(index, divided);
- const divisionStartIndex = index;
- let divisionMidIndex = index + 1;
- let divisionEndIndex = index + 2;
- // do not insert the part if it looks like a point
- if (!divided[0].isDifferentiable()) {
- pathCopy.removeSegment(divisionStartIndex);
- divisionMidIndex -= 1;
- divisionEndIndex -= 1;
- }
- // insert a Moveto segment to ensure secondPath will be valid:
- const movetoEnd = pathCopy.getSegment(divisionMidIndex).start;
- pathCopy.insertSegment(divisionMidIndex, Path.createSegment('M', movetoEnd));
- divisionEndIndex += 1;
- // do not insert the part if it looks like a point
- if (!divided[1].isDifferentiable()) {
- pathCopy.removeSegment(divisionEndIndex - 1);
- divisionEndIndex -= 1;
- }
- // ensure that Closepath segments in secondPath will be assigned correct subpathStartSegment:
- const secondPathSegmentIndexConversion = divisionEndIndex - divisionStartIndex - 1;
- for (let i = divisionEndIndex, ii = pathCopy.segments.length; i < ii; i += 1) {
- const originalSegment = this.getSegment(i - secondPathSegmentIndexConversion);
- const segment = pathCopy.getSegment(i);
- if (segment.type === 'Z' &&
- !originalSegment.subpathStartSegment.end.equals(segment.subpathStartSegment.end)) {
- // pathCopy segment's subpathStartSegment is different from original segment's one
- // convert this Closepath segment to a Lineto and replace it in pathCopy
- const convertedSegment = Path.createSegment('L', originalSegment.end);
- pathCopy.replaceSegment(i, convertedSegment);
- }
- }
- // distribute pathCopy segments into two paths and return those:
- const firstPath = new Path(pathCopy.segments.slice(0, divisionMidIndex));
- const secondPath = new Path(pathCopy.segments.slice(divisionMidIndex));
- return [firstPath, secondPath];
- }
- intersectsWithLine(line, options = {}) {
- const polylines = this.toPolylines(options);
- if (polylines == null) {
- return null;
- }
- let intersections = null;
- for (let i = 0, ii = polylines.length; i < ii; i += 1) {
- const polyline = polylines[i];
- const intersection = line.intersect(polyline);
- if (intersection) {
- if (intersections == null) {
- intersections = [];
- }
- if (Array.isArray(intersection)) {
- intersections.push(...intersection);
- }
- else {
- intersections.push(intersection);
- }
- }
- }
- return intersections;
- }
- isDifferentiable() {
- for (let i = 0, ii = this.segments.length; i < ii; i += 1) {
- const segment = this.segments[i];
- if (segment.isDifferentiable()) {
- return true;
- }
- }
- return false;
- }
- isValid() {
- const segments = this.segments;
- const isValid = segments.length === 0 || segments[0].type === 'M';
- return isValid;
- }
- length(options = {}) {
- if (this.segments.length === 0) {
- return 0;
- }
- const segmentSubdivisions = this.getSubdivisions(options);
- let length = 0;
- for (let i = 0, ii = this.segments.length; i < ii; i += 1) {
- const segment = this.segments[i];
- const subdivisions = segmentSubdivisions[i];
- length += segment.length({ subdivisions });
- }
- return length;
- }
- lengthAtT(t, options = {}) {
- const count = this.segments.length;
- if (count === 0) {
- return 0;
- }
- let segmentIndex = t.segmentIndex;
- if (segmentIndex < 0) {
- return 0;
- }
- let tValue = util_1.GeometryUtil.clamp(t.value, 0, 1);
- if (segmentIndex >= count) {
- segmentIndex = count - 1;
- tValue = 1;
- }
- const precision = this.getPrecision(options);
- const segmentSubdivisions = this.getSubdivisions(options);
- let length = 0;
- for (let i = 0; i < segmentIndex; i += 1) {
- const segment = this.segments[i];
- const subdivisions = segmentSubdivisions[i];
- length += segment.length({ precision, subdivisions });
- }
- const segment = this.segments[segmentIndex];
- const subdivisions = segmentSubdivisions[segmentIndex];
- length += segment.lengthAtT(tValue, { precision, subdivisions });
- return length;
- }
- tangentAt(ratio, options = {}) {
- if (this.segments.length === 0) {
- return null;
- }
- const rate = util_1.GeometryUtil.clamp(ratio, 0, 1);
- const opts = this.getOptions(options);
- const len = this.length(opts);
- const length = len * rate;
- return this.tangentAtLength(length, opts);
- }
- tangentAtLength(length, options = {}) {
- if (this.segments.length === 0) {
- return null;
- }
- let fromStart = true;
- if (length < 0) {
- fromStart = false;
- length = -length; // eslint-disable-line
- }
- const precision = this.getPrecision(options);
- const segmentSubdivisions = this.getSubdivisions(options);
- let lastValidSegment;
- let memo = 0;
- for (let i = 0, ii = this.segments.length; i < ii; i += 1) {
- const index = fromStart ? i : ii - 1 - i;
- const segment = this.segments[index];
- const subdivisions = segmentSubdivisions[index];
- const len = segment.length({ precision, subdivisions });
- if (segment.isDifferentiable()) {
- if (length <= memo + len) {
- return segment.tangentAtLength((fromStart ? 1 : -1) * (length - memo), {
- precision,
- subdivisions,
- });
- }
- lastValidSegment = segment;
- }
- memo += len;
- }
- // if length requested is higher than the length of the path, return tangent of endpoint of last valid segment
- if (lastValidSegment) {
- const t = fromStart ? 1 : 0;
- return lastValidSegment.tangentAtT(t);
- }
- // if no valid segment, return null
- return null;
- }
- tangentAtT(t) {
- const count = this.segments.length;
- if (count === 0) {
- return null;
- }
- const segmentIndex = t.segmentIndex;
- if (segmentIndex < 0) {
- return this.segments[0].tangentAtT(0);
- }
- if (segmentIndex >= count) {
- return this.segments[count - 1].tangentAtT(1);
- }
- const tValue = util_1.GeometryUtil.clamp(t.value, 0, 1);
- return this.segments[segmentIndex].tangentAtT(tValue);
- }
- getPrecision(options = {}) {
- return options.precision == null ? this.PRECISION : options.precision;
- }
- getSubdivisions(options = {}) {
- if (options.segmentSubdivisions == null) {
- const precision = this.getPrecision(options);
- return this.getSegmentSubdivisions({ precision });
- }
- return options.segmentSubdivisions;
- }
- getOptions(options = {}) {
- const precision = this.getPrecision(options);
- const segmentSubdivisions = this.getSubdivisions(options);
- return { precision, segmentSubdivisions };
- }
- toPoints(options = {}) {
- const segments = this.segments;
- const count = segments.length;
- if (count === 0) {
- return null;
- }
- const segmentSubdivisions = this.getSubdivisions(options);
- const points = [];
- let partialPoints = [];
- for (let i = 0; i < count; i += 1) {
- const segment = segments[i];
- if (segment.isVisible) {
- const divisions = segmentSubdivisions[i];
- if (divisions.length > 0) {
- // eslint-disable-next-line no-loop-func
- divisions.forEach((c) => partialPoints.push(c.start));
- }
- else {
- partialPoints.push(segment.start);
- }
- }
- else if (partialPoints.length > 0) {
- partialPoints.push(segments[i - 1].end);
- points.push(partialPoints);
- partialPoints = [];
- }
- }
- if (partialPoints.length > 0) {
- partialPoints.push(this.end);
- points.push(partialPoints);
- }
- return points;
- }
- toPolylines(options = {}) {
- const points = this.toPoints(options);
- if (!points) {
- return null;
- }
- return points.map((arr) => new polyline_1.Polyline(arr));
- }
- scale(sx, sy, origin) {
- this.segments.forEach((s) => s.scale(sx, sy, origin));
- return this;
- }
- rotate(angle, origin) {
- this.segments.forEach((segment) => segment.rotate(angle, origin));
- return this;
- }
- translate(tx, ty) {
- if (typeof tx === 'number') {
- this.segments.forEach((s) => s.translate(tx, ty));
- }
- else {
- this.segments.forEach((s) => s.translate(tx));
- }
- return this;
- }
- clone() {
- const path = new Path();
- this.segments.forEach((s) => path.appendSegment(s.clone()));
- return path;
- }
- equals(p) {
- if (p == null) {
- return false;
- }
- const segments = this.segments;
- const otherSegments = p.segments;
- const count = segments.length;
- if (otherSegments.length !== count) {
- return false;
- }
- for (let i = 0; i < count; i += 1) {
- const a = segments[i];
- const b = otherSegments[i];
- if (a.type !== b.type || !a.equals(b)) {
- return false;
- }
- }
- return true;
- }
- toJSON() {
- return this.segments.map((s) => s.toJSON());
- }
- serialize() {
- if (!this.isValid()) {
- throw new Error('Invalid path segments.');
- }
- return this.segments.map((s) => s.serialize()).join(' ');
- }
- toString() {
- return this.serialize();
- }
- }
- exports.Path = Path;
- (function (Path) {
- function isPath(instance) {
- return instance != null && instance instanceof Path;
- }
- Path.isPath = isPath;
- })(Path = exports.Path || (exports.Path = {}));
- (function (Path) {
- function parse(pathData) {
- if (!pathData) {
- return new Path();
- }
- const path = new Path();
- const commandRe = /(?:[a-zA-Z] *)(?:(?:-?\d+(?:\.\d+)?(?:e[-+]?\d+)? *,? *)|(?:-?\.\d+ *,? *))+|(?:[a-zA-Z] *)(?! |\d|-|\.)/g;
- const commands = Path.normalize(pathData).match(commandRe);
- if (commands != null) {
- for (let i = 0, ii = commands.length; i < ii; i += 1) {
- const command = commands[i];
- const argRe = /(?:[a-zA-Z])|(?:(?:-?\d+(?:\.\d+)?(?:e[-+]?\d+)?))|(?:(?:-?\.\d+))/g;
- const args = command.match(argRe); // [type, coordinate1, coordinate2...]
- if (args != null) {
- const type = args[0];
- const coords = args.slice(1).map((a) => +a);
- const segment = createSegment.call(null, type, ...coords);
- path.appendSegment(segment);
- }
- }
- }
- return path;
- }
- Path.parse = parse;
- function createSegment(type, ...args) {
- if (type === 'M') {
- return moveto_1.MoveTo.create.call(null, ...args);
- }
- if (type === 'L') {
- return lineto_1.LineTo.create.call(null, ...args);
- }
- if (type === 'C') {
- return curveto_1.CurveTo.create.call(null, ...args);
- }
- if (type === 'z' || type === 'Z') {
- return close_1.Close.create();
- }
- throw new Error(`Invalid path segment type "${type}"`);
- }
- Path.createSegment = createSegment;
- })(Path = exports.Path || (exports.Path = {}));
- (function (Path) {
- Path.normalize = normalize_1.normalizePathData;
- Path.isValid = PathUtil.isValid;
- Path.drawArc = PathUtil.drawArc;
- Path.drawPoints = PathUtil.drawPoints;
- Path.arcToCurves = PathUtil.arcToCurves;
- })(Path = exports.Path || (exports.Path = {}));
- //# sourceMappingURL=path.js.map
|