add jspoly and checkpoint thinwall v3
This commit is contained in:
parent
ad0b2c8fc0
commit
c76085f6f9
3 changed files with 7428 additions and 34 deletions
7295
src/ext/jspoly.js
Normal file
7295
src/ext/jspoly.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -257,32 +257,14 @@ export class Polygon {
|
||||||
// including inner polys. return the noodle and the remainder
|
// including inner polys. return the noodle and the remainder
|
||||||
// of the polygon with the noodle removed (for the next pass)
|
// of the polygon with the noodle removed (for the next pass)
|
||||||
noodle(width) {
|
noodle(width) {
|
||||||
// inset outer polygon
|
let clone = this.clone(true);
|
||||||
let inner = this.inner;
|
let ins = clone.offset(width);
|
||||||
let inset = this.clone().offset(width);
|
let nood = POLY.nest(POLY.flatten([ clone, ...ins ], [], true));
|
||||||
let noodot = [ this.clone().setInner(inset) ];
|
return { noodle: nood, remain: ins };
|
||||||
let noodin = [];
|
|
||||||
// subtract inners from the inset
|
|
||||||
if (inner) {
|
|
||||||
noodot = POLY.subtract(noodot, inner, []);
|
|
||||||
// for each inner, offset and subtract noodle + itself
|
|
||||||
let nood = [];
|
|
||||||
for (let innie of inner) {
|
|
||||||
let inexp = innie.clone().offset(-width);
|
|
||||||
let intrm = POLY.trimTo(inexp, [ this ]);
|
|
||||||
let inood = POLY.subtract(intrm, [ ...noodot, innie ], []);
|
|
||||||
nood.push(...inood);
|
|
||||||
}
|
|
||||||
noodin = POLY.union(nood, 0, true);
|
|
||||||
}
|
|
||||||
// unify inner noodles and outer noodle
|
|
||||||
let noodle = POLY.union([ ...noodot, ...noodin ], 0, true);
|
|
||||||
// subtract noodle from poly for next noodle calc
|
|
||||||
let remain = POLY.subtract([ this ], noodle, []);
|
|
||||||
return { noodle, remain };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate center crossing point cloud
|
// generate center crossing point cloud
|
||||||
|
// only used for fdm thin-wall type 1 (fdm/post.js)
|
||||||
centers(step, z, min, max, opt = {}) {
|
centers(step, z, min, max, opt = {}) {
|
||||||
let cloud = [],
|
let cloud = [],
|
||||||
bounds = this.bounds,
|
bounds = this.bounds,
|
||||||
|
|
@ -555,6 +537,7 @@ export class Polygon {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only used in fdm/slice.js for enclosing supports
|
||||||
createConvexHull(points) {
|
createConvexHull(points) {
|
||||||
function removeMiddle(a, b, c) {
|
function removeMiddle(a, b, c) {
|
||||||
let cross = (a.x - b.x) * (c.y - b.y) - (a.y - b.y) * (c.x - b.x);
|
let cross = (a.x - b.x) * (c.y - b.y) - (a.y - b.y) * (c.x - b.x);
|
||||||
|
|
@ -886,6 +869,7 @@ export class Polygon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hint fill angle hinting from longest segment
|
* hint fill angle hinting from longest segment
|
||||||
|
* only used in fdm/slice.js for projected infill orientation
|
||||||
*/
|
*/
|
||||||
hintFillAngle() {
|
hintFillAngle() {
|
||||||
let index = 0,
|
let index = 0,
|
||||||
|
|
@ -1217,6 +1201,8 @@ export class Polygon {
|
||||||
* 2. ease-down starts, following the polygonal path, decreasing Z at a fixed slope until target Z is hit,
|
* 2. ease-down starts, following the polygonal path, decreasing Z at a fixed slope until target Z is hit,
|
||||||
* 3. then the rest of the path is completed and repeated at target Z until touchdown point is reached.
|
* 3. then the rest of the path is completed and repeated at target Z until touchdown point is reached.
|
||||||
* 4. this function should probably move to CAM prepare since it's only called from there
|
* 4. this function should probably move to CAM prepare since it's only called from there
|
||||||
|
*
|
||||||
|
* possibly no longer used anywhere
|
||||||
*/
|
*/
|
||||||
forEachPointEaseDown(fn, fromPoint, degrees = 45) {
|
forEachPointEaseDown(fn, fromPoint, degrees = 45) {
|
||||||
let index = this.findClosestPointTo(fromPoint).index,
|
let index = this.findClosestPointTo(fromPoint).index,
|
||||||
|
|
@ -1537,6 +1523,7 @@ export class Polygon {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used in geo/slicer.js to free memory
|
||||||
freeParentRefs() {
|
freeParentRefs() {
|
||||||
if (this.inner && this.inner.length > 0) {
|
if (this.inner && this.inner.length > 0) {
|
||||||
for (let inner of this.inner) {
|
for (let inner of this.inner) {
|
||||||
|
|
@ -1549,6 +1536,7 @@ export class Polygon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// possibly ununsed
|
||||||
newUndeleted() {
|
newUndeleted() {
|
||||||
let poly = newPolygon();
|
let poly = newPolygon();
|
||||||
this.forEachPoint(p => {
|
this.forEachPoint(p => {
|
||||||
|
|
@ -1888,6 +1876,7 @@ export class Polygon {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// possibly unused
|
||||||
shortestSegmentLength() {
|
shortestSegmentLength() {
|
||||||
let len = Infinity;
|
let len = Infinity;
|
||||||
this.forEachSegment((p1, p2) => {
|
this.forEachSegment((p1, p2) => {
|
||||||
|
|
@ -2362,6 +2351,8 @@ export class Polygon {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only used by cam/op-pocket.js
|
||||||
|
// for any poly points closer than `dist`, replace them with their midpoint
|
||||||
midpoints(dist = 0.01) {
|
midpoints(dist = 0.01) {
|
||||||
const newp = [];
|
const newp = [];
|
||||||
const points = this.points;
|
const points = this.points;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||||
|
|
||||||
|
import '../../../ext/jspoly.js';
|
||||||
import { base } from '../../../geo/base.js';
|
import { base } from '../../../geo/base.js';
|
||||||
|
import { Line } from '../../../geo/line.js';
|
||||||
import { polygons as POLY, fillArea } from '../../../geo/polygons.js';
|
import { polygons as POLY, fillArea } from '../../../geo/polygons.js';
|
||||||
import { getRangeParameters } from './driver.js';
|
import { getRangeParameters } from './driver.js';
|
||||||
import { slicer } from '../../../geo/slicer.js';
|
import { slicer } from '../../../geo/slicer.js';
|
||||||
|
import { Point } from '../../../geo/point.js';
|
||||||
|
|
||||||
slicer.slicePost.FDM = slicePost;
|
slicer.slicePost.FDM = slicePost;
|
||||||
|
|
||||||
|
|
@ -164,19 +167,124 @@ function thin_type_3(params) {
|
||||||
top.thin_fill = [];
|
top.thin_fill = [];
|
||||||
top.fill_sparse = [];
|
top.fill_sparse = [];
|
||||||
|
|
||||||
let { noodle, remain } = top.poly.noodle(offsetN);
|
let { noodle, remain } = top.poly.noodle(offsetN * 2);
|
||||||
top.shells = noodle;
|
top.shells = noodle;
|
||||||
top.gaps = remain;
|
top.gaps = remain;
|
||||||
// top.fill_off = noodle;
|
|
||||||
|
|
||||||
// if (remain.length) {
|
let thin = top.thin_fill;
|
||||||
// top.gaps = [];
|
let scale = 5000;
|
||||||
// for (let poly of remain) {
|
let minR = offsetN / 2;
|
||||||
// let { noodle } = poly.noodle(offsetN);
|
let minSpur = offsetN * 3;
|
||||||
// console.log({ next_noodle: noodle });
|
|
||||||
// top.gaps.push(...noodle);
|
let pointMap = new Map();
|
||||||
// }
|
let lineMap = new Map();
|
||||||
// }
|
|
||||||
|
function pointToRec(point) {
|
||||||
|
let key = `${(point.x*100)|0}|${(point.y*100)|0}`;
|
||||||
|
let rec = pointMap.get(key);
|
||||||
|
if (!rec) {
|
||||||
|
rec = {
|
||||||
|
key,
|
||||||
|
count: 0,
|
||||||
|
x: point.x/scale,
|
||||||
|
y: point.y/scale,
|
||||||
|
r: point.radius/scale,
|
||||||
|
};
|
||||||
|
pointMap.set(key, rec);
|
||||||
|
}
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pointsToLine(p0, p1) {
|
||||||
|
p0 = pointToRec(p0);
|
||||||
|
p1 = pointToRec(p1);
|
||||||
|
let key = p0.key > p1.key ? `${p1.key}:${p0.key}` : `${p0.key}:${p1.key}`;
|
||||||
|
let rec = lineMap.get(key);
|
||||||
|
if (rec) {
|
||||||
|
rec.count++;
|
||||||
|
} else {
|
||||||
|
rec = {
|
||||||
|
p0,
|
||||||
|
p1,
|
||||||
|
key,
|
||||||
|
count: 1,
|
||||||
|
};
|
||||||
|
p0.count++;
|
||||||
|
p1.count++;
|
||||||
|
lineMap.set(key, rec);
|
||||||
|
}
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
let chains = [];
|
||||||
|
|
||||||
|
for (let poly of noodle) {
|
||||||
|
poly = poly.clone(true).scale({ x:scale, y:scale, z:scale });
|
||||||
|
let out = poly.points.map(p => ({ x: p.x|0, y: p.y|0 }));
|
||||||
|
let inr = (poly.inner ?? []).map(p => p.points.map(p => ({ x: p.x|0, y: p.y|0 })));
|
||||||
|
let ma = JSPoly.construct_medial_axis(out, inr);
|
||||||
|
for (let { point0, point1 } of ma) {
|
||||||
|
pointsToLine(point0, point1);
|
||||||
|
}
|
||||||
|
for (let seg of lineMap.values()) {
|
||||||
|
let { p0, p1 } = seg;
|
||||||
|
let len = seg.len = Math.hypot(p0.x-p1.x, p0.y-p1.y);
|
||||||
|
if (p0.r < minR || p1.r < minR) {
|
||||||
|
if (p0.r > minR && len > minSpur) {
|
||||||
|
// move p1 toward p0 until minR met
|
||||||
|
let pct = (minR - p1.r) / (p0.r - p1.r);
|
||||||
|
let dx = p1.x - p0.x;
|
||||||
|
let dy = p1.y - p0.y;
|
||||||
|
p1.x -= dx * pct;
|
||||||
|
p1.y -= dy * pct;
|
||||||
|
p1.r = minR;
|
||||||
|
pointMap.delete(p1.key);
|
||||||
|
} else if (p1.r > minR && len > minSpur) {
|
||||||
|
// move p0 toward p1 until minR met
|
||||||
|
let pct = (minR - p0.r) / (p1.r - p0.r);
|
||||||
|
let dx = p0.x - p1.x;
|
||||||
|
let dy = p0.y - p1.y;
|
||||||
|
p0.x -= dx * pct;
|
||||||
|
p0.y -= dy * pct;
|
||||||
|
p0.r = minR;
|
||||||
|
pointMap.delete(p0.key);
|
||||||
|
} else {
|
||||||
|
lineMap.delete(seg.key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// thin.push(new Point(p0.x, p0.y));
|
||||||
|
// thin.push(new Point(p1.x, p1.y));
|
||||||
|
let add;
|
||||||
|
for (let chain of chains) {
|
||||||
|
if (p0.count === 2 && p0 === chain[0]) {
|
||||||
|
chain.splice(0,0,p1);
|
||||||
|
} else if (p0.count === 2 && p0 === chain.peek()) {
|
||||||
|
chain.push(p1);
|
||||||
|
add = true;
|
||||||
|
} else if (p1.count === 2 && p1 === chain[0]) {
|
||||||
|
chain.splice(0,0,p0);
|
||||||
|
add = true;
|
||||||
|
} else if (p1.count ===2 && p1 === chain.last) {
|
||||||
|
chain.push(p0);
|
||||||
|
add = true;
|
||||||
|
}
|
||||||
|
if (add) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!add) {
|
||||||
|
chains.push([ p0, p1 ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let chain of chains) {
|
||||||
|
for (let i=0; i<chain.length-1; i++) {
|
||||||
|
thin.push(new Point(chain[i].x, chain[i].y));
|
||||||
|
thin.push(new Point(chain[i+1].x, chain[i+1].y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return { last, gaps };
|
return { last, gaps };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue