feature: vor und nachteile

This commit is contained in:
Hikyu
2026-05-31 13:54:31 +02:00
parent 552a947a1c
commit e3dad17446
23270 changed files with 3024794 additions and 200 deletions
+50
View File
@@ -0,0 +1,50 @@
import {Adder} from "d3-array";
import {abs} from "../math.js";
import noop from "../noop.js";
var areaSum = new Adder(),
areaRingSum = new Adder(),
x00,
y00,
x0,
y0;
var areaStream = {
point: noop,
lineStart: noop,
lineEnd: noop,
polygonStart: function() {
areaStream.lineStart = areaRingStart;
areaStream.lineEnd = areaRingEnd;
},
polygonEnd: function() {
areaStream.lineStart = areaStream.lineEnd = areaStream.point = noop;
areaSum.add(abs(areaRingSum));
areaRingSum = new Adder();
},
result: function() {
var area = areaSum / 2;
areaSum = new Adder();
return area;
}
};
function areaRingStart() {
areaStream.point = areaPointFirst;
}
function areaPointFirst(x, y) {
areaStream.point = areaPoint;
x00 = x0 = x, y00 = y0 = y;
}
function areaPoint(x, y) {
areaRingSum.add(y0 * x - x0 * y);
x0 = x, y0 = y;
}
function areaRingEnd() {
areaPoint(x00, y00);
}
export default areaStream;
+28
View File
@@ -0,0 +1,28 @@
import noop from "../noop.js";
var x0 = Infinity,
y0 = x0,
x1 = -x0,
y1 = x1;
var boundsStream = {
point: boundsPoint,
lineStart: noop,
lineEnd: noop,
polygonStart: noop,
polygonEnd: noop,
result: function() {
var bounds = [[x0, y0], [x1, y1]];
x1 = y1 = -(y0 = x0 = Infinity);
return bounds;
}
};
function boundsPoint(x, y) {
if (x < x0) x0 = x;
if (x > x1) x1 = x;
if (y < y0) y0 = y;
if (y > y1) y1 = y;
}
export default boundsStream;
+100
View File
@@ -0,0 +1,100 @@
import {sqrt} from "../math.js";
// TODO Enforce positive area for exterior, negative area for interior?
var X0 = 0,
Y0 = 0,
Z0 = 0,
X1 = 0,
Y1 = 0,
Z1 = 0,
X2 = 0,
Y2 = 0,
Z2 = 0,
x00,
y00,
x0,
y0;
var centroidStream = {
point: centroidPoint,
lineStart: centroidLineStart,
lineEnd: centroidLineEnd,
polygonStart: function() {
centroidStream.lineStart = centroidRingStart;
centroidStream.lineEnd = centroidRingEnd;
},
polygonEnd: function() {
centroidStream.point = centroidPoint;
centroidStream.lineStart = centroidLineStart;
centroidStream.lineEnd = centroidLineEnd;
},
result: function() {
var centroid = Z2 ? [X2 / Z2, Y2 / Z2]
: Z1 ? [X1 / Z1, Y1 / Z1]
: Z0 ? [X0 / Z0, Y0 / Z0]
: [NaN, NaN];
X0 = Y0 = Z0 =
X1 = Y1 = Z1 =
X2 = Y2 = Z2 = 0;
return centroid;
}
};
function centroidPoint(x, y) {
X0 += x;
Y0 += y;
++Z0;
}
function centroidLineStart() {
centroidStream.point = centroidPointFirstLine;
}
function centroidPointFirstLine(x, y) {
centroidStream.point = centroidPointLine;
centroidPoint(x0 = x, y0 = y);
}
function centroidPointLine(x, y) {
var dx = x - x0, dy = y - y0, z = sqrt(dx * dx + dy * dy);
X1 += z * (x0 + x) / 2;
Y1 += z * (y0 + y) / 2;
Z1 += z;
centroidPoint(x0 = x, y0 = y);
}
function centroidLineEnd() {
centroidStream.point = centroidPoint;
}
function centroidRingStart() {
centroidStream.point = centroidPointFirstRing;
}
function centroidRingEnd() {
centroidPointRing(x00, y00);
}
function centroidPointFirstRing(x, y) {
centroidStream.point = centroidPointRing;
centroidPoint(x00 = x0 = x, y00 = y0 = y);
}
function centroidPointRing(x, y) {
var dx = x - x0,
dy = y - y0,
z = sqrt(dx * dx + dy * dy);
X1 += z * (x0 + x) / 2;
Y1 += z * (y0 + y) / 2;
Z1 += z;
z = y0 * x - x0 * y;
X2 += z * (x0 + x);
Y2 += z * (y0 + y);
Z2 += z * 3;
centroidPoint(x0 = x, y0 = y);
}
export default centroidStream;
+45
View File
@@ -0,0 +1,45 @@
import {tau} from "../math.js";
import noop from "../noop.js";
export default function PathContext(context) {
this._context = context;
}
PathContext.prototype = {
_radius: 4.5,
pointRadius: function(_) {
return this._radius = _, this;
},
polygonStart: function() {
this._line = 0;
},
polygonEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._point = 0;
},
lineEnd: function() {
if (this._line === 0) this._context.closePath();
this._point = NaN;
},
point: function(x, y) {
switch (this._point) {
case 0: {
this._context.moveTo(x, y);
this._point = 1;
break;
}
case 1: {
this._context.lineTo(x, y);
break;
}
default: {
this._context.moveTo(x + this._radius, y);
this._context.arc(x, y, this._radius, 0, tau);
break;
}
}
},
result: noop
};
+76
View File
@@ -0,0 +1,76 @@
import identity from "../identity.js";
import stream from "../stream.js";
import pathArea from "./area.js";
import pathBounds from "./bounds.js";
import pathCentroid from "./centroid.js";
import PathContext from "./context.js";
import pathMeasure from "./measure.js";
import PathString from "./string.js";
export default function(projection, context) {
let digits = 3,
pointRadius = 4.5,
projectionStream,
contextStream;
function path(object) {
if (object) {
if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
stream(object, projectionStream(contextStream));
}
return contextStream.result();
}
path.area = function(object) {
stream(object, projectionStream(pathArea));
return pathArea.result();
};
path.measure = function(object) {
stream(object, projectionStream(pathMeasure));
return pathMeasure.result();
};
path.bounds = function(object) {
stream(object, projectionStream(pathBounds));
return pathBounds.result();
};
path.centroid = function(object) {
stream(object, projectionStream(pathCentroid));
return pathCentroid.result();
};
path.projection = function(_) {
if (!arguments.length) return projection;
projectionStream = _ == null ? (projection = null, identity) : (projection = _).stream;
return path;
};
path.context = function(_) {
if (!arguments.length) return context;
contextStream = _ == null ? (context = null, new PathString(digits)) : new PathContext(context = _);
if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
return path;
};
path.pointRadius = function(_) {
if (!arguments.length) return pointRadius;
pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
return path;
};
path.digits = function(_) {
if (!arguments.length) return digits;
if (_ == null) digits = null;
else {
const d = Math.floor(_);
if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`);
digits = d;
}
if (context === null) contextStream = new PathString(digits);
return path;
};
return path.projection(projection).digits(digits).context(context);
}
+45
View File
@@ -0,0 +1,45 @@
import {Adder} from "d3-array";
import {sqrt} from "../math.js";
import noop from "../noop.js";
var lengthSum = new Adder(),
lengthRing,
x00,
y00,
x0,
y0;
var lengthStream = {
point: noop,
lineStart: function() {
lengthStream.point = lengthPointFirst;
},
lineEnd: function() {
if (lengthRing) lengthPoint(x00, y00);
lengthStream.point = noop;
},
polygonStart: function() {
lengthRing = true;
},
polygonEnd: function() {
lengthRing = null;
},
result: function() {
var length = +lengthSum;
lengthSum = new Adder();
return length;
}
};
function lengthPointFirst(x, y) {
lengthStream.point = lengthPoint;
x00 = x0 = x, y00 = y0 = y;
}
function lengthPoint(x, y) {
x0 -= x, y0 -= y;
lengthSum.add(sqrt(x0 * x0 + y0 * y0));
x0 = x, y0 = y;
}
export default lengthStream;
+86
View File
@@ -0,0 +1,86 @@
// Simple caching for constant-radius points.
let cacheDigits, cacheAppend, cacheRadius, cacheCircle;
export default class PathString {
constructor(digits) {
this._append = digits == null ? append : appendRound(digits);
this._radius = 4.5;
this._ = "";
}
pointRadius(_) {
this._radius = +_;
return this;
}
polygonStart() {
this._line = 0;
}
polygonEnd() {
this._line = NaN;
}
lineStart() {
this._point = 0;
}
lineEnd() {
if (this._line === 0) this._ += "Z";
this._point = NaN;
}
point(x, y) {
switch (this._point) {
case 0: {
this._append`M${x},${y}`;
this._point = 1;
break;
}
case 1: {
this._append`L${x},${y}`;
break;
}
default: {
this._append`M${x},${y}`;
if (this._radius !== cacheRadius || this._append !== cacheAppend) {
const r = this._radius;
const s = this._;
this._ = ""; // stash the old string so we can cache the circle path fragment
this._append`m0,${r}a${r},${r} 0 1,1 0,${-2 * r}a${r},${r} 0 1,1 0,${2 * r}z`;
cacheRadius = r;
cacheAppend = this._append;
cacheCircle = this._;
this._ = s;
}
this._ += cacheCircle;
break;
}
}
}
result() {
const result = this._;
this._ = "";
return result.length ? result : null;
}
}
function append(strings) {
let i = 1;
this._ += strings[0];
for (const j = strings.length; i < j; ++i) {
this._ += arguments[i] + strings[i];
}
}
function appendRound(digits) {
const d = Math.floor(digits);
if (!(d >= 0)) throw new RangeError(`invalid digits: ${digits}`);
if (d > 15) return append;
if (d !== cacheDigits) {
const k = 10 ** d;
cacheDigits = d;
cacheAppend = function append(strings) {
let i = 1;
this._ += strings[0];
for (const j = strings.length; i < j; ++i) {
this._ += Math.round(arguments[i] * k) / k + strings[i];
}
};
}
return cacheAppend;
}