@mathigon/euclid
Advanced tools
Comparing version 0.6.4 to 0.6.5
@@ -130,2 +130,4 @@ 'use strict'; | ||
rotate(angle, c = ORIGIN) { | ||
if (fermat.nearlyEquals(angle, 0)) | ||
return this; | ||
const x0 = this.x - c.x; | ||
@@ -159,5 +161,5 @@ const y0 = this.y - c.y; | ||
} | ||
equals(other) { | ||
equals(other, precision) { | ||
// TODO Fix type signature for `other` | ||
return fermat.nearlyEquals(this.x, other.x) && fermat.nearlyEquals(this.y, other.y); | ||
return fermat.nearlyEquals(this.x, other.x, precision) && fermat.nearlyEquals(this.y, other.y, precision); | ||
} | ||
@@ -214,5 +216,5 @@ } | ||
} | ||
contains(_p) { | ||
// TODO Implement | ||
return false; | ||
contains(p) { | ||
// TODO Is there a better way to do this? | ||
return p.equals(this.project(p)); | ||
} | ||
@@ -224,2 +226,4 @@ // --------------------------------------------------------------------------- | ||
rotate(a, c = ORIGIN) { | ||
if (fermat.nearlyEquals(a, 0)) | ||
return this; | ||
return new this.constructor(this.c.rotate(a, c), this.start.rotate(a, c), this.angle); | ||
@@ -321,7 +325,7 @@ } | ||
/** Checks if a point p lies on this line. */ | ||
contains(p) { | ||
contains(p, tolerance) { | ||
// det([[p.x, p.y, 1],[p1.x, p1.y, 1],[p2.x, ,p2.y 1]]) | ||
const det = p.x * (this.p1.y - this.p2.y) + this.p1.x * (this.p2.y - p.y) + | ||
this.p2.x * (p.y - this.p1.y); | ||
return fermat.nearlyEquals(det, 0); | ||
return fermat.nearlyEquals(det, 0, tolerance); | ||
} | ||
@@ -336,2 +340,4 @@ at(t) { | ||
rotate(a, c = ORIGIN) { | ||
if (fermat.nearlyEquals(a, 0)) | ||
return this; | ||
return new this.constructor(this.p1.rotate(a, c), this.p2.rotate(a, c)); | ||
@@ -351,4 +357,6 @@ } | ||
} | ||
equals(other) { | ||
return this.contains(other.p1) && this.contains(other.p2); | ||
equals(other, tolerance) { | ||
if (other.type !== 'line') | ||
return false; | ||
return this.contains(other.p1, tolerance) && this.contains(other.p2, tolerance); | ||
} | ||
@@ -365,6 +373,6 @@ } | ||
} | ||
equals(other) { | ||
equals(other, tolerance) { | ||
if (other.type !== 'ray') | ||
return false; | ||
return this.p1.equals(other.p1) && this.contains(other.p2); | ||
return this.p1.equals(other.p1, tolerance) && this.contains(other.p2, tolerance); | ||
} | ||
@@ -378,6 +386,6 @@ } | ||
} | ||
contains(p) { | ||
contains(p, tolerance) { | ||
if (!Line.prototype.contains.call(this, p)) | ||
return false; | ||
if (fermat.nearlyEquals(this.p1.x, this.p2.x)) { | ||
if (fermat.nearlyEquals(this.p1.x, this.p2.x, tolerance)) { | ||
return fermat.isBetween(p.y, this.p1.y, this.p2.y); | ||
@@ -402,7 +410,7 @@ } | ||
} | ||
equals(other, oriented = false) { | ||
equals(other, tolerance, oriented = false) { | ||
if (other.type !== 'segment') | ||
return false; | ||
return (this.p1.equals(other.p1) && this.p2.equals(other.p2)) || | ||
(!oriented && this.p1.equals(other.p2) && this.p2.equals(other.p1)); | ||
return (this.p1.equals(other.p1, tolerance) && this.p2.equals(other.p2, tolerance)) || | ||
(!oriented && this.p1.equals(other.p2, tolerance) && this.p2.equals(other.p1, tolerance)); | ||
} | ||
@@ -477,2 +485,4 @@ } | ||
rotate(a, c) { | ||
if (fermat.nearlyEquals(a, 0)) | ||
return this; | ||
return new Angle(this.a.rotate(a, c), this.b.rotate(a, c), this.c.rotate(a, c)); | ||
@@ -523,2 +533,8 @@ } | ||
} | ||
collision(r) { | ||
const tX = (this.c.x < r.p.x) ? r.p.x : (this.c.x > r.p.x + r.w) ? r.p.x + r.w : this.c.x; | ||
const tY = (this.c.y < r.p.y) ? r.p.y : (this.c.y > r.p.y + r.h) ? r.p.y + r.h : this.c.y; | ||
const d = Point.distance(this.c, new Point(tX, tY)); | ||
return d <= this.r; | ||
} | ||
// --------------------------------------------------------------------------- | ||
@@ -542,2 +558,4 @@ project(p) { | ||
rotate(a, c = ORIGIN) { | ||
if (fermat.nearlyEquals(a, 0)) | ||
return this; | ||
return new Circle(this.c.rotate(a, c), this.r); | ||
@@ -557,4 +575,4 @@ } | ||
} | ||
equals(other) { | ||
return fermat.nearlyEquals(this.r, other.r) && this.c.equals(other.c); | ||
equals(other, tolerance) { | ||
return fermat.nearlyEquals(this.r, other.r, tolerance) && this.c.equals(other.c, tolerance); | ||
} | ||
@@ -594,2 +612,5 @@ } | ||
} | ||
function isEllipse(shape) { | ||
return shape.type === 'ellipse'; | ||
} | ||
function isArc(shape) { | ||
@@ -881,2 +902,4 @@ return shape.type === 'arc'; | ||
rotate(a, center = ORIGIN) { | ||
if (fermat.nearlyEquals(a, 0)) | ||
return this; | ||
const points = this.points.map(p => p.rotate(a, center)); | ||
@@ -975,10 +998,14 @@ return new this.constructor(...points); | ||
/** Creates the smallest rectangle containing all given points. */ | ||
static aroundPoints(...points) { | ||
const xs = points.map(p => p.x); | ||
const ys = points.map(p => p.y); | ||
const x = Math.min(...xs); | ||
const w = Math.max(...xs) - x; | ||
const y = Math.min(...ys); | ||
const h = Math.max(...ys) - y; | ||
return new Rectangle(new Point(x, y), w, h); | ||
static aroundPoints(points) { | ||
let xMin = Infinity; | ||
let xMax = -Infinity; | ||
let yMin = Infinity; | ||
let yMax = -Infinity; | ||
for (const p of points) { | ||
xMin = xMin < p.x ? xMin : p.x; | ||
xMax = xMax > p.x ? xMax : p.x; | ||
yMin = yMin < p.y ? yMin : p.y; | ||
yMax = yMax > p.y ? yMax : p.y; | ||
} | ||
return new Rectangle(new Point(xMin, yMin), xMax - xMin, yMax - yMin); | ||
} | ||
@@ -1012,6 +1039,10 @@ get center() { | ||
} | ||
collision(r) { | ||
return (this.p.x < r.p.x + r.w && this.p.x + this.w > r.p.x && | ||
this.p.y < r.p.y + r.h && this.p.y + this.h > r.p.y); | ||
} | ||
// --------------------------------------------------------------------------- | ||
contains(p) { | ||
return fermat.isBetween(p.x, this.p.x, this.p.x + this.w) && | ||
fermat.isBetween(p.y, this.p.y, this.p.y + this.h); | ||
contains(p, tolerance) { | ||
return fermat.isBetween(p.x, this.p.x, this.p.x + this.w, tolerance) && | ||
fermat.isBetween(p.y, this.p.y, this.p.y + this.h, tolerance); | ||
} | ||
@@ -1036,2 +1067,4 @@ project(p) { | ||
rotate(a, c = ORIGIN) { | ||
if (fermat.nearlyEquals(a, 0)) | ||
return this; | ||
return this.polygon.rotate(a, c); | ||
@@ -1089,2 +1122,5 @@ } | ||
} | ||
get center() { | ||
return new Point(this.xMin + this.dx / 2, this.yMin + this.dy / 2); | ||
} | ||
} | ||
@@ -1388,2 +1424,3 @@ | ||
exports.isCircle = isCircle; | ||
exports.isEllipse = isEllipse; | ||
exports.isLine = isLine; | ||
@@ -1390,0 +1427,0 @@ exports.isLineLike = isLineLike; |
@@ -126,2 +126,4 @@ import { mod, nearlyEquals, clamp, roundTo, square, lerp, Random, isBetween, subsets, quadratic } from '@mathigon/fermat'; | ||
rotate(angle, c = ORIGIN) { | ||
if (nearlyEquals(angle, 0)) | ||
return this; | ||
const x0 = this.x - c.x; | ||
@@ -155,5 +157,5 @@ const y0 = this.y - c.y; | ||
} | ||
equals(other) { | ||
equals(other, precision) { | ||
// TODO Fix type signature for `other` | ||
return nearlyEquals(this.x, other.x) && nearlyEquals(this.y, other.y); | ||
return nearlyEquals(this.x, other.x, precision) && nearlyEquals(this.y, other.y, precision); | ||
} | ||
@@ -210,5 +212,5 @@ } | ||
} | ||
contains(_p) { | ||
// TODO Implement | ||
return false; | ||
contains(p) { | ||
// TODO Is there a better way to do this? | ||
return p.equals(this.project(p)); | ||
} | ||
@@ -220,2 +222,4 @@ // --------------------------------------------------------------------------- | ||
rotate(a, c = ORIGIN) { | ||
if (nearlyEquals(a, 0)) | ||
return this; | ||
return new this.constructor(this.c.rotate(a, c), this.start.rotate(a, c), this.angle); | ||
@@ -317,7 +321,7 @@ } | ||
/** Checks if a point p lies on this line. */ | ||
contains(p) { | ||
contains(p, tolerance) { | ||
// det([[p.x, p.y, 1],[p1.x, p1.y, 1],[p2.x, ,p2.y 1]]) | ||
const det = p.x * (this.p1.y - this.p2.y) + this.p1.x * (this.p2.y - p.y) + | ||
this.p2.x * (p.y - this.p1.y); | ||
return nearlyEquals(det, 0); | ||
return nearlyEquals(det, 0, tolerance); | ||
} | ||
@@ -332,2 +336,4 @@ at(t) { | ||
rotate(a, c = ORIGIN) { | ||
if (nearlyEquals(a, 0)) | ||
return this; | ||
return new this.constructor(this.p1.rotate(a, c), this.p2.rotate(a, c)); | ||
@@ -347,4 +353,6 @@ } | ||
} | ||
equals(other) { | ||
return this.contains(other.p1) && this.contains(other.p2); | ||
equals(other, tolerance) { | ||
if (other.type !== 'line') | ||
return false; | ||
return this.contains(other.p1, tolerance) && this.contains(other.p2, tolerance); | ||
} | ||
@@ -361,6 +369,6 @@ } | ||
} | ||
equals(other) { | ||
equals(other, tolerance) { | ||
if (other.type !== 'ray') | ||
return false; | ||
return this.p1.equals(other.p1) && this.contains(other.p2); | ||
return this.p1.equals(other.p1, tolerance) && this.contains(other.p2, tolerance); | ||
} | ||
@@ -374,6 +382,6 @@ } | ||
} | ||
contains(p) { | ||
contains(p, tolerance) { | ||
if (!Line.prototype.contains.call(this, p)) | ||
return false; | ||
if (nearlyEquals(this.p1.x, this.p2.x)) { | ||
if (nearlyEquals(this.p1.x, this.p2.x, tolerance)) { | ||
return isBetween(p.y, this.p1.y, this.p2.y); | ||
@@ -398,7 +406,7 @@ } | ||
} | ||
equals(other, oriented = false) { | ||
equals(other, tolerance, oriented = false) { | ||
if (other.type !== 'segment') | ||
return false; | ||
return (this.p1.equals(other.p1) && this.p2.equals(other.p2)) || | ||
(!oriented && this.p1.equals(other.p2) && this.p2.equals(other.p1)); | ||
return (this.p1.equals(other.p1, tolerance) && this.p2.equals(other.p2, tolerance)) || | ||
(!oriented && this.p1.equals(other.p2, tolerance) && this.p2.equals(other.p1, tolerance)); | ||
} | ||
@@ -473,2 +481,4 @@ } | ||
rotate(a, c) { | ||
if (nearlyEquals(a, 0)) | ||
return this; | ||
return new Angle(this.a.rotate(a, c), this.b.rotate(a, c), this.c.rotate(a, c)); | ||
@@ -519,2 +529,8 @@ } | ||
} | ||
collision(r) { | ||
const tX = (this.c.x < r.p.x) ? r.p.x : (this.c.x > r.p.x + r.w) ? r.p.x + r.w : this.c.x; | ||
const tY = (this.c.y < r.p.y) ? r.p.y : (this.c.y > r.p.y + r.h) ? r.p.y + r.h : this.c.y; | ||
const d = Point.distance(this.c, new Point(tX, tY)); | ||
return d <= this.r; | ||
} | ||
// --------------------------------------------------------------------------- | ||
@@ -538,2 +554,4 @@ project(p) { | ||
rotate(a, c = ORIGIN) { | ||
if (nearlyEquals(a, 0)) | ||
return this; | ||
return new Circle(this.c.rotate(a, c), this.r); | ||
@@ -553,4 +571,4 @@ } | ||
} | ||
equals(other) { | ||
return nearlyEquals(this.r, other.r) && this.c.equals(other.c); | ||
equals(other, tolerance) { | ||
return nearlyEquals(this.r, other.r, tolerance) && this.c.equals(other.c, tolerance); | ||
} | ||
@@ -590,2 +608,5 @@ } | ||
} | ||
function isEllipse(shape) { | ||
return shape.type === 'ellipse'; | ||
} | ||
function isArc(shape) { | ||
@@ -877,2 +898,4 @@ return shape.type === 'arc'; | ||
rotate(a, center = ORIGIN) { | ||
if (nearlyEquals(a, 0)) | ||
return this; | ||
const points = this.points.map(p => p.rotate(a, center)); | ||
@@ -971,10 +994,14 @@ return new this.constructor(...points); | ||
/** Creates the smallest rectangle containing all given points. */ | ||
static aroundPoints(...points) { | ||
const xs = points.map(p => p.x); | ||
const ys = points.map(p => p.y); | ||
const x = Math.min(...xs); | ||
const w = Math.max(...xs) - x; | ||
const y = Math.min(...ys); | ||
const h = Math.max(...ys) - y; | ||
return new Rectangle(new Point(x, y), w, h); | ||
static aroundPoints(points) { | ||
let xMin = Infinity; | ||
let xMax = -Infinity; | ||
let yMin = Infinity; | ||
let yMax = -Infinity; | ||
for (const p of points) { | ||
xMin = xMin < p.x ? xMin : p.x; | ||
xMax = xMax > p.x ? xMax : p.x; | ||
yMin = yMin < p.y ? yMin : p.y; | ||
yMax = yMax > p.y ? yMax : p.y; | ||
} | ||
return new Rectangle(new Point(xMin, yMin), xMax - xMin, yMax - yMin); | ||
} | ||
@@ -1008,6 +1035,10 @@ get center() { | ||
} | ||
collision(r) { | ||
return (this.p.x < r.p.x + r.w && this.p.x + this.w > r.p.x && | ||
this.p.y < r.p.y + r.h && this.p.y + this.h > r.p.y); | ||
} | ||
// --------------------------------------------------------------------------- | ||
contains(p) { | ||
return isBetween(p.x, this.p.x, this.p.x + this.w) && | ||
isBetween(p.y, this.p.y, this.p.y + this.h); | ||
contains(p, tolerance) { | ||
return isBetween(p.x, this.p.x, this.p.x + this.w, tolerance) && | ||
isBetween(p.y, this.p.y, this.p.y + this.h, tolerance); | ||
} | ||
@@ -1032,2 +1063,4 @@ project(p) { | ||
rotate(a, c = ORIGIN) { | ||
if (nearlyEquals(a, 0)) | ||
return this; | ||
return this.polygon.rotate(a, c); | ||
@@ -1085,2 +1118,5 @@ } | ||
} | ||
get center() { | ||
return new Point(this.xMin + this.dx / 2, this.yMin + this.dy / 2); | ||
} | ||
} | ||
@@ -1362,2 +1398,2 @@ | ||
export { Angle, Arc, Bounds, Circle, Ellipse, Line, ORIGIN, Point, Polygon, Polyline, Ray, Rectangle, Sector, Segment, Triangle, angleSize, drawCanvas, drawSVG, intersections, isAngle, isArc, isCircle, isLine, isLineLike, isPoint, isPolygon, isPolygonLike, isPolyline, isRay, isRectangle, isSector, isSegment, rad }; | ||
export { Angle, Arc, Bounds, Circle, Ellipse, Line, ORIGIN, Point, Polygon, Polyline, Ray, Rectangle, Sector, Segment, Triangle, angleSize, drawCanvas, drawSVG, intersections, isAngle, isArc, isCircle, isEllipse, isLine, isLineLike, isPoint, isPolygon, isPolygonLike, isPolyline, isRay, isRectangle, isSector, isSegment, rad }; |
{ | ||
"name": "@mathigon/euclid", | ||
"version": "0.6.4", | ||
"version": "0.6.5", | ||
"description": "Euclidean geometry classes and tools for JavaScript.", | ||
@@ -34,12 +34,12 @@ "keywords": [ | ||
"devDependencies": { | ||
"@rollup/plugin-typescript": "6.0.0", | ||
"@rollup/plugin-typescript": "6.1.0", | ||
"@types/tape": "4.13.0", | ||
"rollup": "2.28.2", | ||
"rollup": "2.33.0", | ||
"tape": "5.0.1", | ||
"ts-node": "9.0.0", | ||
"tslib": "2.0.1", | ||
"typescript": "4.0.3", | ||
"@typescript-eslint/eslint-plugin": "4.3.0", | ||
"@typescript-eslint/parser": "4.3.0", | ||
"eslint": "7.10.0", | ||
"tslib": "2.0.3", | ||
"typescript": "4.0.5", | ||
"@typescript-eslint/eslint-plugin": "4.6.0", | ||
"@typescript-eslint/parser": "4.6.0", | ||
"eslint": "7.12.1", | ||
"eslint-config-google": "0.14.0", | ||
@@ -46,0 +46,0 @@ "eslint-plugin-import": "2.22.1" |
@@ -90,2 +90,3 @@ // ============================================================================= | ||
rotate(a: number, c?: SimplePoint) { | ||
if (nearlyEquals(a, 0)) return this; | ||
return new Angle(this.a.rotate(a, c), this.b.rotate(a, c), this.c.rotate(a, c)); | ||
@@ -92,0 +93,0 @@ } |
@@ -7,3 +7,3 @@ // ============================================================================= | ||
import {clamp} from '@mathigon/fermat'; | ||
import {clamp, nearlyEquals} from '@mathigon/fermat'; | ||
import {Line} from './line'; | ||
@@ -70,5 +70,5 @@ import {Point, ORIGIN} from './point'; | ||
contains(_p: Point) { | ||
// TODO Implement | ||
return false; | ||
contains(p: Point) { | ||
// TODO Is there a better way to do this? | ||
return p.equals(this.project(p)); | ||
} | ||
@@ -84,2 +84,3 @@ | ||
rotate(a: number, c = ORIGIN): this { | ||
if (nearlyEquals(a, 0)) return this; | ||
return new (<any> this.constructor)(this.c.rotate(a, c), | ||
@@ -86,0 +87,0 @@ this.start.rotate(a, c), this.angle); |
@@ -49,2 +49,6 @@ // ============================================================================= | ||
} | ||
get center() { | ||
return new Point(this.xMin + this.dx / 2, this.yMin + this.dy / 2); | ||
} | ||
} |
@@ -11,2 +11,3 @@ // ============================================================================= | ||
import {ORIGIN, Point} from './point'; | ||
import {Rectangle} from './rectangle'; | ||
import {GeoShape, TransformMatrix, TWO_PI} from './utilities'; | ||
@@ -42,2 +43,10 @@ | ||
collision(r: Rectangle) { | ||
const tX = (this.c.x < r.p.x) ? r.p.x : (this.c.x > r.p.x + r.w) ? r.p.x + r.w : this.c.x; | ||
const tY = (this.c.y < r.p.y) ? r.p.y : (this.c.y > r.p.y + r.h) ? r.p.y + r.h : this.c.y; | ||
const d = Point.distance(this.c, new Point(tX, tY)); | ||
return d <= this.r; | ||
} | ||
// --------------------------------------------------------------------------- | ||
@@ -67,2 +76,3 @@ | ||
rotate(a: number, c = ORIGIN) { | ||
if (nearlyEquals(a, 0)) return this; | ||
return new Circle(this.c.rotate(a, c), this.r); | ||
@@ -87,5 +97,5 @@ } | ||
equals(other: Circle) { | ||
return nearlyEquals(this.r, other.r) && this.c.equals(other.c); | ||
equals(other: Circle, tolerance?: number) { | ||
return nearlyEquals(this.r, other.r, tolerance) && this.c.equals(other.c, tolerance); | ||
} | ||
} |
@@ -96,7 +96,7 @@ // ============================================================================= | ||
/** Checks if a point p lies on this line. */ | ||
contains(p: Point) { | ||
contains(p: Point, tolerance?: number) { | ||
// det([[p.x, p.y, 1],[p1.x, p1.y, 1],[p2.x, ,p2.y 1]]) | ||
const det = p.x * (this.p1.y - this.p2.y) + this.p1.x * (this.p2.y - p.y) + | ||
this.p2.x * (p.y - this.p1.y); | ||
return nearlyEquals(det, 0); | ||
return nearlyEquals(det, 0, tolerance); | ||
} | ||
@@ -116,2 +116,3 @@ | ||
rotate(a: number, c = ORIGIN): this { | ||
if (nearlyEquals(a, 0)) return this; | ||
return new (<any> this.constructor)(this.p1.rotate(a, c), | ||
@@ -137,4 +138,5 @@ this.p2.rotate(a, c)); | ||
equals(other: Line) { | ||
return this.contains(other.p1) && this.contains(other.p2); | ||
equals(other: Line, tolerance?: number) { | ||
if (other.type !== 'line') return false; | ||
return this.contains(other.p1, tolerance) && this.contains(other.p2, tolerance); | ||
} | ||
@@ -152,5 +154,5 @@ } | ||
equals(other: Ray) { | ||
equals(other: Ray, tolerance?: number) { | ||
if (other.type !== 'ray') return false; | ||
return this.p1.equals(other.p1) && this.contains(other.p2); | ||
return this.p1.equals(other.p1, tolerance) && this.contains(other.p2, tolerance); | ||
} | ||
@@ -164,5 +166,5 @@ } | ||
contains(p: Point) { | ||
contains(p: Point, tolerance?: number) { | ||
if (!Line.prototype.contains.call(this, p)) return false; | ||
if (nearlyEquals(this.p1.x, this.p2.x)) { | ||
if (nearlyEquals(this.p1.x, this.p2.x, tolerance)) { | ||
return isBetween(p.y, this.p1.y, this.p2.y); | ||
@@ -191,7 +193,8 @@ } else { | ||
equals(other: Segment, oriented = false) { | ||
equals(other: Segment, tolerance?: number, oriented = false) { | ||
if (other.type !== 'segment') return false; | ||
return (this.p1.equals(other.p1) && this.p2.equals(other.p2)) || | ||
(!oriented && this.p1.equals(other.p2) && this.p2.equals(other.p1)); | ||
return (this.p1.equals(other.p1, tolerance) && this.p2.equals(other.p2, tolerance)) || | ||
(!oriented && this.p1.equals(other.p2, tolerance) && this.p2.equals(other.p1, tolerance)); | ||
} | ||
} |
@@ -153,2 +153,4 @@ // ============================================================================= | ||
rotate(angle: number, c: SimplePoint = ORIGIN) { | ||
if (nearlyEquals(angle, 0)) return this; | ||
const x0 = this.x - c.x; | ||
@@ -192,5 +194,5 @@ const y0 = this.y - c.y; | ||
equals(other: any) { | ||
equals(other: any, precision?: number) { | ||
// TODO Fix type signature for `other` | ||
return nearlyEquals(this.x, other.x) && nearlyEquals(this.y, other.y); | ||
return nearlyEquals(this.x, other.x, precision) && nearlyEquals(this.y, other.y, precision); | ||
} | ||
@@ -197,0 +199,0 @@ } |
@@ -8,2 +8,3 @@ // ============================================================================= | ||
import {toLinkedList, tabulate, last} from '@mathigon/core'; | ||
import {nearlyEquals} from '@mathigon/fermat'; | ||
import {Circle} from './circle'; | ||
@@ -204,2 +205,3 @@ import {intersections} from './intersection'; | ||
rotate(a: number, center = ORIGIN): this { | ||
if (nearlyEquals(a, 0)) return this; | ||
const points = this.points.map(p => p.rotate(a, center)); | ||
@@ -206,0 +208,0 @@ return new (<any> this.constructor)(...points); |
@@ -7,3 +7,3 @@ // ============================================================================= | ||
import {isBetween} from '@mathigon/fermat'; | ||
import {isBetween, nearlyEquals} from '@mathigon/fermat'; | ||
import {Line} from './line'; | ||
@@ -22,11 +22,16 @@ import {ORIGIN, Point} from './point'; | ||
/** Creates the smallest rectangle containing all given points. */ | ||
static aroundPoints(...points: Point[]) { | ||
const xs = points.map(p => p.x); | ||
const ys = points.map(p => p.y); | ||
static aroundPoints(points: Iterable<Point>) { | ||
let xMin = Infinity; | ||
let xMax = -Infinity; | ||
let yMin = Infinity; | ||
let yMax = -Infinity; | ||
const x = Math.min(...xs); | ||
const w = Math.max(...xs) - x; | ||
const y = Math.min(...ys); | ||
const h = Math.max(...ys) - y; | ||
return new Rectangle(new Point(x, y), w, h); | ||
for (const p of points) { | ||
xMin = xMin < p.x ? xMin : p.x; | ||
xMax = xMax > p.x ? xMax : p.x; | ||
yMin = yMin < p.y ? yMin : p.y; | ||
yMax = yMax > p.y ? yMax : p.y; | ||
} | ||
return new Rectangle(new Point(xMin, yMin), xMax - xMin, yMax - yMin); | ||
} | ||
@@ -68,7 +73,12 @@ | ||
collision(r: Rectangle) { | ||
return (this.p.x < r.p.x + r.w && this.p.x + this.w > r.p.x && | ||
this.p.y < r.p.y + r.h && this.p.y + this.h > r.p.y); | ||
} | ||
// --------------------------------------------------------------------------- | ||
contains(p: Point) { | ||
return isBetween(p.x, this.p.x, this.p.x + this.w) && | ||
isBetween(p.y, this.p.y, this.p.y + this.h); | ||
contains(p: Point, tolerance?: number) { | ||
return isBetween(p.x, this.p.x, this.p.x + this.w, tolerance) && | ||
isBetween(p.y, this.p.y, this.p.y + this.h, tolerance); | ||
} | ||
@@ -99,2 +109,3 @@ | ||
rotate(a: number, c = ORIGIN) { | ||
if (nearlyEquals(a, 0)) return this; | ||
return this.polygon.rotate(a, c); | ||
@@ -101,0 +112,0 @@ } |
@@ -10,2 +10,3 @@ // ============================================================================= | ||
import {Circle} from './circle'; | ||
import {Ellipse} from './ellipse'; | ||
import {Line, Ray, Segment} from './line'; | ||
@@ -54,2 +55,6 @@ import {Point} from './point'; | ||
export function isEllipse(shape: GeoElement): shape is Ellipse { | ||
return shape.type === 'ellipse'; | ||
} | ||
export function isArc(shape: GeoElement): shape is Arc { | ||
@@ -56,0 +61,0 @@ return shape.type === 'arc'; |
@@ -24,3 +24,3 @@ // ============================================================================= | ||
translate(p: Point): GeoElement; | ||
equals(other: GeoElement, oriented?: boolean): boolean; | ||
equals(other: GeoElement, tolerance?: number, oriented?: boolean): boolean; | ||
} | ||
@@ -30,4 +30,10 @@ | ||
project(p: Point): Point; | ||
contains(p: Point): boolean; | ||
contains(p: Point, tolerance?: number): boolean; | ||
at(t: number): Point; | ||
rotate(angle: number, center?: SimplePoint): GeoShape; | ||
reflect(l: Line): GeoShape; | ||
scale(sx: number, sy?: number): GeoShape; | ||
shift(x: number, y?: number): GeoShape; | ||
translate(p: Point): GeoShape; | ||
} | ||
@@ -34,0 +40,0 @@ |
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
156954
4374