@flatten-js/core
Advanced tools
Comparing version 1.5.8 to 1.6.0
@@ -187,2 +187,3 @@ // Type definitions for flatten-js library | ||
contains(shape: AnyShape): boolean; | ||
distanceTo(shape: AnyShape): [number, Point]; | ||
merge(box: Box): Box; | ||
@@ -573,2 +574,3 @@ less_than(box: Box): boolean; | ||
get box(): Box; | ||
get length(): number; | ||
@@ -578,3 +580,7 @@ clone(): Multiline; | ||
split(ip: Point[]) : Multiline; | ||
pointAtLength(length: number): Point|null; | ||
findEdgeByPoint(pt: Point): MultilineEdge | undefined; | ||
contains(shape: AnyShape): boolean; | ||
distanceTo(shape: AnyShape): [number, Segment]; | ||
intersect(shape: AnyShape): Point[]; | ||
rotate(angle?: number, center?: Point): Multiline; | ||
@@ -607,3 +613,3 @@ transform(matrix?: Matrix): Multiline; | ||
type AnyShape = Point | Vector | Line | Ray | Circle | Box | Segment | Arc | Polygon; | ||
type AnyShape = Point | Vector | Line | Ray | Circle | Box | Segment | Arc | Polygon | Multiline; | ||
@@ -610,0 +616,0 @@ function point(x?: number, y?: number): Point; |
@@ -33,3 +33,3 @@ /** | ||
export {SmartIntersections}; | ||
export { parseWKT, isWktString } from './src/utils/parseWKT' | ||
// export { parseWKT, isWktString } from './src/utils/parseWKT' | ||
@@ -36,0 +36,0 @@ Flatten.BooleanOperations = BooleanOperations; |
{ | ||
"name": "@flatten-js/core", | ||
"version": "1.5.8", | ||
"version": "1.6.0", | ||
"description": "Javascript library for 2d geometry", | ||
@@ -78,4 +78,4 @@ "main": "dist/main.cjs", | ||
"dependencies": { | ||
"@flatten-js/interval-tree": "^1.0.21" | ||
"@flatten-js/interval-tree": "^1.1.3" | ||
} | ||
} |
@@ -246,3 +246,3 @@ [![npm version](https://badge.fury.io/js/%40flatten-js%2Fcore.svg)](https://badge.fury.io/js/%40flatten-js%2Fcore) | ||
* `inside` - shape a lies in the interior of shape b | ||
* `contain` - shape b lies in the interior of shape b | ||
* `contain` - shape b lies in the interior of shape a | ||
* `covered` - every point of a lies or in the interior or on the boundary of shape b | ||
@@ -249,0 +249,0 @@ * `covered` - every point of b lies or in the interior or on the boundary of shape a |
@@ -8,2 +8,3 @@ "use strict"; | ||
export class Distance { | ||
@@ -14,3 +15,3 @@ /** | ||
* @param pt2 | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -25,3 +26,3 @@ static point2point(pt1, pt2) { | ||
* @param line | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -38,3 +39,3 @@ static point2line(pt, line) { | ||
* @param circle | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -57,3 +58,3 @@ static point2circle(pt, circle) { | ||
* @param segment | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -94,3 +95,3 @@ static point2segment(pt, segment) { | ||
* @param arc | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -114,6 +115,18 @@ static point2arc(pt, arc) { | ||
/** | ||
* Calculate distance and shortest segment between point and edge | ||
* @param pt | ||
* @param edge | ||
* @returns {[number, Flatten.Segment]} | ||
*/ | ||
static point2edge(pt, edge) { | ||
return edge.shape instanceof Flatten.Segment ? | ||
Distance.point2segment(pt, edge.shape) : | ||
Distance.point2arc(pt, edge.shape); | ||
} | ||
/** | ||
* Calculate distance and shortest segment between segment and line | ||
* @param seg | ||
* @param line | ||
* @returns {Number | Segment} | ||
* @returns {[number, Flatten.Segment]} | ||
*/ | ||
@@ -138,3 +151,3 @@ static segment2line(seg, line) { | ||
* @param seg2 | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -165,3 +178,3 @@ static segment2segment(seg1, seg2) { | ||
* @param circle | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -199,3 +212,3 @@ static segment2circle(seg, circle) { | ||
* @param arc | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -245,3 +258,3 @@ static segment2arc(seg, arc) { | ||
* @param circle2 | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -281,3 +294,3 @@ static circle2circle(circle1, circle2) { | ||
* @param line | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -300,3 +313,3 @@ static circle2line(circle, line) { | ||
* @param line | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -337,3 +350,3 @@ static arc2line(arc, line) { | ||
* @param circle2 | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -367,3 +380,3 @@ static arc2circle(arc, circle2) { | ||
* @param arc2 | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -429,3 +442,3 @@ static arc2arc(arc1, arc2) { | ||
* @param polygon | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -435,4 +448,3 @@ static point2polygon(point, polygon) { | ||
for (let edge of polygon.edges) { | ||
let [dist, shortest_segment] = (edge.shape instanceof Flatten.Segment) ? | ||
Distance.point2segment(point, edge.shape) : Distance.point2arc(point, edge.shape); | ||
let [dist, shortest_segment] = Distance.point2edge(point, edge); | ||
if (Flatten.Utils.LT(dist, min_dist_and_segment[0])) { | ||
@@ -460,3 +472,3 @@ min_dist_and_segment = [dist, shortest_segment]; | ||
* @param polygon2 | ||
* @returns {Number | Segment} - distance and shortest segment | ||
* @returns {[number, Flatten.Segment]} - distance and shortest segment | ||
*/ | ||
@@ -616,4 +628,40 @@ static polygon2polygon(polygon1, polygon2) { | ||
} | ||
/** | ||
* Calculate distance and shortest segment any shape and multiline | ||
* @param shape | ||
* @param multiline | ||
* @returns {[number, Flatten.Segment]} | ||
*/ | ||
static shape2multiline(shape, multiline) { | ||
let min_dist_and_segment = [Number.POSITIVE_INFINITY, new Flatten.Segment()]; | ||
for (let edge of multiline) { | ||
let [dist, shortest_segment] = Distance.distance(shape, edge.shape); | ||
if (Flatten.Utils.LT(dist, min_dist_and_segment[0])) { | ||
min_dist_and_segment = [dist, shortest_segment]; | ||
} | ||
} | ||
return min_dist_and_segment; | ||
} | ||
/** | ||
* Calculate distance and shortest segment between two multilines | ||
* @param multiline1 | ||
* @param multiline2 | ||
* @returns {[number, Flatten.Segment]} | ||
*/ | ||
static multiline2multiline(multiline1, multiline2) { | ||
let min_dist_and_segment = [Number.POSITIVE_INFINITY, new Flatten.Segment()]; | ||
for (let edge1 of multiline1) { | ||
for (let edge2 of multiline2) { | ||
let [dist, shortest_segment] = Distance.distance(edge1.shape, edge2.shape); | ||
if (Flatten.Utils.LT(dist, min_dist_and_segment[0])) { | ||
min_dist_and_segment = [dist, shortest_segment]; | ||
} | ||
} | ||
} | ||
return min_dist_and_segment; | ||
} | ||
} | ||
Flatten.Distance = Distance; |
@@ -10,2 +10,3 @@ /** | ||
import Flatten from "../flatten"; | ||
import {Errors} from "../utils/errors"; | ||
@@ -638,1 +639,26 @@ export function intersectLine2Line(line1, line2) { | ||
} | ||
export function intersectShape2Shape(shape1, shape2) { | ||
if (shape1.intersect && shape1.intersect instanceof Function) { | ||
return shape1.intersect(shape2) | ||
} | ||
throw Errors.UNSUPPORTED_SHAPE_TYPE | ||
} | ||
export function intersectShape2Multiline(shape, multiline) { | ||
let ip = []; | ||
for (let edge of multiline) { | ||
ip = [...ip, ...intersectShape2Shape(edge, edge.shape)]; | ||
} | ||
return ip; | ||
} | ||
export function intersectMultiline2Multiline(multiline1, multiline2) { | ||
let ip = []; | ||
for (let edge1 of multiline1) { | ||
for (let edge2 of multiline2) { | ||
ip = [...ip, ...intersectShape2Shape(edge1, edge2)]; | ||
} | ||
} | ||
return ip; | ||
} |
@@ -264,2 +264,5 @@ /** | ||
} | ||
if (shape instanceof Flatten.Multiline) { | ||
return Intersection.intersectShape2Multiline(this, shape); | ||
} | ||
} | ||
@@ -311,2 +314,6 @@ | ||
} | ||
if (shape instanceof Flatten.Multiline) { | ||
return Flatten.Distance.shape2multiline(this, shape); | ||
} | ||
} | ||
@@ -313,0 +320,0 @@ |
@@ -288,2 +288,23 @@ /** | ||
/** | ||
* Calculate distance and shortest segment from box to shape and return as array [distance, shortest segment] | ||
* @param {Shape} shape Shape of the one of supported types Point, Line, Circle, Segment, Arc, Polygon or Planar Set | ||
* @returns {number} distance from box to shape | ||
* @returns {Segment} shortest segment between box and shape (started at box, ended at shape) | ||
*/ | ||
distanceTo(shape) { | ||
const distanceInfos = this.toSegments() | ||
.map(segment => segment.distanceTo(shape)); | ||
let shortestDistanceInfo = [ | ||
Number.MAX_SAFE_INTEGER, | ||
null, | ||
]; | ||
distanceInfos.forEach(distanceInfo => { | ||
if (distanceInfo[0] < shortestDistanceInfo[0]) { | ||
shortestDistanceInfo = distanceInfo; | ||
} | ||
}); | ||
return shortestDistanceInfo; | ||
} | ||
get name() { | ||
@@ -301,3 +322,3 @@ return "box" | ||
const height = this.ymax - this.ymin; | ||
return `\n<rect x="${this.xmin}" y="${this.ymin}" width=${width} height=${height} | ||
return `\n<rect x="${this.xmin}" y="${this.ymin}" width="${width}" height="${height}" | ||
${convertToString({fill: "none", ...attrs})} />`; | ||
@@ -304,0 +325,0 @@ }; |
@@ -178,2 +178,5 @@ /** | ||
} | ||
if (shape instanceof Flatten.Multiline) { | ||
return Intersection.intersectShape2Multiline(this, shape); | ||
} | ||
} | ||
@@ -226,2 +229,7 @@ | ||
} | ||
if (shape instanceof Flatten.Multiline) { | ||
let [dist, shortest_segment] = Flatten.Distance.shape2multiline(this, shape); | ||
return [dist, shortest_segment]; | ||
} | ||
} | ||
@@ -228,0 +236,0 @@ |
@@ -13,3 +13,3 @@ /** | ||
* Class representing a face (closed loop) in a [polygon]{@link Flatten.Polygon} object. | ||
* Face is a circular bidirectional linked list of [edges]{@link Flatten.Edge}. | ||
* Face is a circular bidirectionally linked list of [edges]{@link Flatten.Edge}. | ||
* Face object cannot be instantiated with a constructor. | ||
@@ -16,0 +16,0 @@ * Instead, use [polygon.addFace()]{@link Flatten.Polygon#addFace} method. |
@@ -242,2 +242,6 @@ /** | ||
if (shape instanceof Flatten.Multiline) { | ||
return Intersection.intersectShape2Multiline(this, shape); | ||
} | ||
} | ||
@@ -244,0 +248,0 @@ |
@@ -6,2 +6,3 @@ "use strict"; | ||
import {convertToString} from "../utils/attributes"; | ||
import * as Intersection from "../algorithms/intersection"; | ||
@@ -15,23 +16,27 @@ /** | ||
super(); | ||
this.isInfinite = false; | ||
if (args.length === 0) { | ||
return; | ||
} | ||
if (args.length === 1 && args[0] instanceof Array && args[0].length > 0) { | ||
// there may be only one line and | ||
// only first and last may be rays | ||
let validShapes = false | ||
const shapes = args[0] | ||
const L = shapes.length | ||
const anyShape = (s) => | ||
s instanceof Flatten.Segment || s instanceof Flatten.Arc || | ||
s instanceof Flatten.Ray || s instanceof Flatten.Line; | ||
const anyShapeExceptLine = (s) => | ||
s instanceof Flatten.Segment || s instanceof Flatten.Arc || s instanceof Flatten.Ray; | ||
const shapeSegmentOrArc = (s) => s instanceof Flatten.Segment || s instanceof Flatten.Arc; | ||
validShapes = | ||
L === 1 && anyShape(shapes[0]) || | ||
L > 1 && anyShapeExceptLine(shapes[0]) && anyShapeExceptLine(shapes[L - 1]) && | ||
shapes.slice(1, L - 1).every(shapeSegmentOrArc) | ||
if (args.length === 1) { | ||
if (args[0] instanceof Array) { | ||
let shapes = args[0]; | ||
if (shapes.length === 0) | ||
return; | ||
if (validShapes) { | ||
this.isInfinite = shapes.some(shape => | ||
shape instanceof Flatten.Ray || | ||
shape instanceof Flatten.Line | ||
); | ||
// TODO: more strict validation: | ||
// there may be only one line | ||
// only first and last may be rays | ||
let validShapes = shapes.every((shape) => { | ||
return shape instanceof Flatten.Segment || | ||
shape instanceof Flatten.Arc || | ||
shape instanceof Flatten.Ray || | ||
shape instanceof Flatten.Line | ||
}); | ||
for (let shape of shapes) { | ||
@@ -43,2 +48,4 @@ let edge = new Flatten.Edge(shape); | ||
this.setArcLength() | ||
} else { | ||
throw Flatten.Errors.ILLEGAL_PARAMETERS; | ||
} | ||
@@ -75,2 +82,17 @@ } | ||
/** | ||
* (Getter) Returns length of the multiline, return POSITIVE_INFINITY if multiline is infinite | ||
* @returns {number} | ||
*/ | ||
get length() { | ||
if (this.isEmpty()) return 0; | ||
if (this.isInfinite) return Number.POSITIVE_INFINITY; | ||
let len = 0 | ||
for (let edge of this) { | ||
len += edge.length; | ||
} | ||
return len | ||
} | ||
/** | ||
* Return new cloned instance of Multiline | ||
@@ -84,4 +106,4 @@ * @returns {Multiline} | ||
/** | ||
* Set arc_length property for each of the edges in the face. | ||
* Arc_length of the edge it the arc length from the first edge of the face | ||
* Set arc_length property for each of the edges in the multiline. | ||
* Arc_length of the edge is the arc length from the multiline start vertex to the edge start vertex | ||
*/ | ||
@@ -103,2 +125,22 @@ setArcLength() { | ||
/** | ||
* Return point on multiline at given length from the start of the multiline | ||
* @param length | ||
* @returns {Point | null} | ||
*/ | ||
pointAtLength(length) { | ||
if (length > this.length || length < 0) return null; | ||
if (this.isInfinite) return null | ||
let point = null; | ||
for (let edge of this) { | ||
if (length >= edge.arc_length && | ||
(edge === this.last || length < edge.next.arc_length)) { | ||
point = edge.pointAtLength(length - edge.arc_length); | ||
break; | ||
} | ||
} | ||
return point; | ||
} | ||
/** | ||
* Split edge and add new vertex, return new edge inserted | ||
@@ -169,2 +211,67 @@ * @param {Point} pt - point on edge that will be added as new vertex | ||
/** | ||
* Calculate distance and shortest segment from any shape to multiline | ||
* @param shape | ||
* @returns {[number,Flatten.Segment]} | ||
*/ | ||
distanceTo(shape) { | ||
if (shape instanceof Point) { | ||
const [dist, shortest_segment] = Flatten.Distance.shape2multiline(shape, this); | ||
return [dist, shortest_segment.reverse()]; | ||
} | ||
if (shape instanceof Flatten.Line) { | ||
const [dist, shortest_segment] = Flatten.Distance.shape2multiline(shape, this); | ||
return [dist, shortest_segment.reverse()]; | ||
} | ||
if (shape instanceof Flatten.Circle) { | ||
const [dist, shortest_segment] = Flatten.Distance.shape2multiline(shape, this); | ||
return [dist, shortest_segment.reverse()]; | ||
} | ||
if (shape instanceof Flatten.Segment) { | ||
const [dist, shortest_segment] = Flatten.Distance.shape2multiline(shape, this); | ||
return [dist, shortest_segment.reverse()]; | ||
} | ||
if (shape instanceof Flatten.Arc) { | ||
const [dist, shortest_segment] = Flatten.Distance.shape2multiline(shape, this); | ||
return [dist, shortest_segment.reverse()]; | ||
} | ||
if (shape instanceof Flatten.Multiline) { | ||
return Flatten.Distance.multiline2multiline(this, shape); | ||
} | ||
throw Flatten.Errors.UNSUPPORTED_SHAPE_TYPE; | ||
} | ||
/** | ||
* Calculate intersection of multiline with other shape | ||
* @param {Shape} shape | ||
* @returns {Point[]} | ||
*/ | ||
intersect(shape) { | ||
if (shape instanceof Flatten.Multiline) { | ||
return Intersection.intersectMultiline2Multiline(this, shape); | ||
} | ||
else { | ||
return Intersection.intersectShape2Multiline(shape, this); | ||
} | ||
} | ||
/** | ||
* Return true if multiline contains the shape: no point of shape lies outside | ||
* @param shape | ||
* @returns {boolean} | ||
*/ | ||
contains(shape) { | ||
if (shape instanceof Flatten.Point) { | ||
return this.edges.some(edge => edge.shape.contains(shape)); | ||
} | ||
throw Flatten.Errors.UNSUPPORTED_SHAPE_TYPE; | ||
} | ||
/** | ||
* Returns new multiline translated by vector vec | ||
@@ -171,0 +278,0 @@ * @param {Vector} vec |
@@ -184,2 +184,6 @@ /** | ||
} | ||
if (shape instanceof Flatten.Multiline) { | ||
return Flatten.Distance.shape2multiline(this, shape); | ||
} | ||
} | ||
@@ -197,29 +201,7 @@ | ||
if (shape instanceof Flatten.Box) { | ||
if (shape.contains && shape.contains instanceof Function) { | ||
return shape.contains(this); | ||
} | ||
if (shape instanceof Flatten.Line) { | ||
return shape.contains(this); | ||
} | ||
if (shape instanceof Flatten.Ray) { | ||
return shape.contains(this) | ||
} | ||
if (shape instanceof Flatten.Circle) { | ||
return shape.contains(this); | ||
} | ||
if (shape instanceof Flatten.Segment) { | ||
return shape.contains(this); | ||
} | ||
if (shape instanceof Flatten.Arc) { | ||
return shape.contains(this); | ||
} | ||
if (shape instanceof Flatten.Polygon) { | ||
return shape.contains(this); | ||
} | ||
throw Flatten.Errors.UNSUPPORTED_SHAPE_TYPE; | ||
} | ||
@@ -226,0 +208,0 @@ |
@@ -18,3 +18,3 @@ /** | ||
import {Multiline} from "./multiline"; | ||
import {intersectEdge2Edge} from "../algorithms/intersection"; | ||
import {intersectEdge2Edge, intersectMultiline2Polygon} from "../algorithms/intersection"; | ||
import {INSIDE, BOUNDARY} from "../utils/constants"; | ||
@@ -556,2 +556,6 @@ import {convertToString} from "../utils/attributes"; | ||
} | ||
if (shape instanceof Flatten.Multiline) { | ||
return Intersection.intersectMultiline2Polygon(shape, this); | ||
} | ||
} | ||
@@ -558,0 +562,0 @@ |
@@ -140,3 +140,3 @@ /** | ||
* Returns true if equals to query segment, false otherwise | ||
* @param {Seg} seg - query segment | ||
* @param {Segment} seg - query segment | ||
* @returns {boolean} | ||
@@ -194,2 +194,6 @@ */ | ||
} | ||
if (shape instanceof Flatten.Multiline) { | ||
return Intersection.intersectShape2Multiline(this, shape); | ||
} | ||
} | ||
@@ -200,4 +204,3 @@ | ||
* @param {Shape} shape Shape of the one of supported types Point, Line, Circle, Segment, Arc, Polygon or Planar Set | ||
* @returns {number} distance from segment to shape | ||
* @returns {Segment} shortest segment between segment and shape (started at segment, ended at shape) | ||
* @returns {[number, Segment]} shortest segment between segment and shape (started at segment, ended at shape) | ||
*/ | ||
@@ -240,2 +243,6 @@ distanceTo(shape) { | ||
} | ||
if (shape instanceof Flatten.Multiline) { | ||
return Flatten.Distance.shape2multiline(this, shape); | ||
} | ||
} | ||
@@ -242,0 +249,0 @@ |
@@ -55,4 +55,8 @@ /** | ||
} | ||
static get UNSUPPORTED_SHAPE_TYPE() { | ||
return new Error('Unsupported shape type') | ||
} | ||
} | ||
Flatten.Errors = Errors; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1246245
31934