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

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 [];
}
}
}