You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.6 KiB
JavaScript
101 lines
3.6 KiB
JavaScript
4 years ago
|
import { lineLength, lineIntersection, doIntersect, isPointInPolygon } from '../geometry';
|
||
|
import { polygonHachureLines } from './scan-line-hachure';
|
||
|
export class HachureFiller {
|
||
|
constructor(helper) {
|
||
|
this.helper = helper;
|
||
|
}
|
||
|
fillPolygon(points, o) {
|
||
|
return this._fillPolygon(points, o);
|
||
|
}
|
||
|
_fillPolygon(points, o, connectEnds = false) {
|
||
|
let lines = polygonHachureLines(points, o);
|
||
|
if (connectEnds) {
|
||
|
const connectingLines = this.connectingLines(points, lines);
|
||
|
lines = lines.concat(connectingLines);
|
||
|
}
|
||
|
const ops = this.renderLines(lines, o);
|
||
|
return { type: 'fillSketch', ops };
|
||
|
}
|
||
|
renderLines(lines, o) {
|
||
|
const ops = [];
|
||
|
for (const line of lines) {
|
||
|
ops.push(...this.helper.doubleLineOps(line[0][0], line[0][1], line[1][0], line[1][1], o));
|
||
|
}
|
||
|
return ops;
|
||
|
}
|
||
|
connectingLines(polygon, lines) {
|
||
|
const result = [];
|
||
|
if (lines.length > 1) {
|
||
|
for (let i = 1; i < lines.length; i++) {
|
||
|
const prev = lines[i - 1];
|
||
|
if (lineLength(prev) < 3) {
|
||
|
continue;
|
||
|
}
|
||
|
const current = lines[i];
|
||
|
const segment = [current[0], prev[1]];
|
||
|
if (lineLength(segment) > 3) {
|
||
|
const segSplits = this.splitOnIntersections(polygon, segment);
|
||
|
result.push(...segSplits);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
midPointInPolygon(polygon, segment) {
|
||
|
return isPointInPolygon(polygon, (segment[0][0] + segment[1][0]) / 2, (segment[0][1] + segment[1][1]) / 2);
|
||
|
}
|
||
|
splitOnIntersections(polygon, segment) {
|
||
|
const error = Math.max(5, lineLength(segment) * 0.1);
|
||
|
const intersections = [];
|
||
|
for (let i = 0; i < polygon.length; i++) {
|
||
|
const p1 = polygon[i];
|
||
|
const p2 = polygon[(i + 1) % polygon.length];
|
||
|
if (doIntersect(p1, p2, ...segment)) {
|
||
|
const ip = lineIntersection(p1, p2, segment[0], segment[1]);
|
||
|
if (ip) {
|
||
|
const d0 = lineLength([ip, segment[0]]);
|
||
|
const d1 = lineLength([ip, segment[1]]);
|
||
|
if (d0 > error && d1 > error) {
|
||
|
intersections.push({
|
||
|
point: ip,
|
||
|
distance: d0
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (intersections.length > 1) {
|
||
|
const ips = intersections.sort((a, b) => a.distance - b.distance).map((d) => d.point);
|
||
|
if (!isPointInPolygon(polygon, ...segment[0])) {
|
||
|
ips.shift();
|
||
|
}
|
||
|
if (!isPointInPolygon(polygon, ...segment[1])) {
|
||
|
ips.pop();
|
||
|
}
|
||
|
if (ips.length <= 1) {
|
||
|
if (this.midPointInPolygon(polygon, segment)) {
|
||
|
return [segment];
|
||
|
}
|
||
|
else {
|
||
|
return [];
|
||
|
}
|
||
|
}
|
||
|
const spoints = [segment[0], ...ips, segment[1]];
|
||
|
const slines = [];
|
||
|
for (let i = 0; i < (spoints.length - 1); i += 2) {
|
||
|
const subSegment = [spoints[i], spoints[i + 1]];
|
||
|
if (this.midPointInPolygon(polygon, subSegment)) {
|
||
|
slines.push(subSegment);
|
||
|
}
|
||
|
}
|
||
|
return slines;
|
||
|
}
|
||
|
else if (this.midPointInPolygon(polygon, segment)) {
|
||
|
return [segment];
|
||
|
}
|
||
|
else {
|
||
|
return [];
|
||
|
}
|
||
|
}
|
||
|
}
|