+9
@@ -0,0 +1,9 @@
|
||||
import { PatternFiller, RenderHelper } from './filler-interface';
|
||||
import { ResolvedOptions, OpSet } from '../core';
|
||||
import { Point } from '../geometry';
|
||||
export declare class DashedFiller implements PatternFiller {
|
||||
private helper;
|
||||
constructor(helper: RenderHelper);
|
||||
fillPolygons(polygonList: Point[][], o: ResolvedOptions): OpSet;
|
||||
private dashedLine;
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import { lineLength } from '../geometry';
|
||||
import { polygonHachureLines } from './scan-line-hachure';
|
||||
export class DashedFiller {
|
||||
constructor(helper) {
|
||||
this.helper = helper;
|
||||
}
|
||||
fillPolygons(polygonList, o) {
|
||||
const lines = polygonHachureLines(polygonList, o);
|
||||
return { type: 'fillSketch', ops: this.dashedLine(lines, o) };
|
||||
}
|
||||
dashedLine(lines, o) {
|
||||
const offset = o.dashOffset < 0 ? (o.hachureGap < 0 ? (o.strokeWidth * 4) : o.hachureGap) : o.dashOffset;
|
||||
const gap = o.dashGap < 0 ? (o.hachureGap < 0 ? (o.strokeWidth * 4) : o.hachureGap) : o.dashGap;
|
||||
const ops = [];
|
||||
lines.forEach((line) => {
|
||||
const length = lineLength(line);
|
||||
const count = Math.floor(length / (offset + gap));
|
||||
const startOffset = (length + gap - (count * (offset + gap))) / 2;
|
||||
let p1 = line[0];
|
||||
let p2 = line[1];
|
||||
if (p1[0] > p2[0]) {
|
||||
p1 = line[1];
|
||||
p2 = line[0];
|
||||
}
|
||||
const alpha = Math.atan((p2[1] - p1[1]) / (p2[0] - p1[0]));
|
||||
for (let i = 0; i < count; i++) {
|
||||
const lstart = i * (offset + gap);
|
||||
const lend = lstart + offset;
|
||||
const start = [p1[0] + (lstart * Math.cos(alpha)) + (startOffset * Math.cos(alpha)), p1[1] + lstart * Math.sin(alpha) + (startOffset * Math.sin(alpha))];
|
||||
const end = [p1[0] + (lend * Math.cos(alpha)) + (startOffset * Math.cos(alpha)), p1[1] + (lend * Math.sin(alpha)) + (startOffset * Math.sin(alpha))];
|
||||
ops.push(...this.helper.doubleLineOps(start[0], start[1], end[0], end[1], o));
|
||||
}
|
||||
});
|
||||
return ops;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { PatternFiller, RenderHelper } from './filler-interface';
|
||||
import { ResolvedOptions, OpSet } from '../core';
|
||||
import { Point } from '../geometry';
|
||||
export declare class DotFiller implements PatternFiller {
|
||||
private helper;
|
||||
constructor(helper: RenderHelper);
|
||||
fillPolygons(polygonList: Point[][], o: ResolvedOptions): OpSet;
|
||||
private dotsOnLines;
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { lineLength } from '../geometry';
|
||||
import { polygonHachureLines } from './scan-line-hachure';
|
||||
export class DotFiller {
|
||||
constructor(helper) {
|
||||
this.helper = helper;
|
||||
}
|
||||
fillPolygons(polygonList, o) {
|
||||
o = Object.assign({}, o, { hachureAngle: 0 });
|
||||
const lines = polygonHachureLines(polygonList, o);
|
||||
return this.dotsOnLines(lines, o);
|
||||
}
|
||||
dotsOnLines(lines, o) {
|
||||
const ops = [];
|
||||
let gap = o.hachureGap;
|
||||
if (gap < 0) {
|
||||
gap = o.strokeWidth * 4;
|
||||
}
|
||||
gap = Math.max(gap, 0.1);
|
||||
let fweight = o.fillWeight;
|
||||
if (fweight < 0) {
|
||||
fweight = o.strokeWidth / 2;
|
||||
}
|
||||
const ro = gap / 4;
|
||||
for (const line of lines) {
|
||||
const length = lineLength(line);
|
||||
const dl = length / gap;
|
||||
const count = Math.ceil(dl) - 1;
|
||||
const offset = length - (count * gap);
|
||||
const x = ((line[0][0] + line[1][0]) / 2) - (gap / 4);
|
||||
const minY = Math.min(line[0][1], line[1][1]);
|
||||
for (let i = 0; i < count; i++) {
|
||||
const y = minY + offset + (i * gap);
|
||||
const cx = (x - ro) + Math.random() * 2 * ro;
|
||||
const cy = (y - ro) + Math.random() * 2 * ro;
|
||||
const el = this.helper.ellipse(cx, cy, fweight, fweight, o);
|
||||
ops.push(...el.ops);
|
||||
}
|
||||
}
|
||||
return { type: 'fillSketch', ops };
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { ResolvedOptions, OpSet, Op } from '../core';
|
||||
import { Point } from '../geometry';
|
||||
export interface PatternFiller {
|
||||
fillPolygons(polygonList: Point[][], o: ResolvedOptions): OpSet;
|
||||
}
|
||||
export interface RenderHelper {
|
||||
randOffset(x: number, o: ResolvedOptions): number;
|
||||
randOffsetWithRange(min: number, max: number, o: ResolvedOptions): number;
|
||||
ellipse(x: number, y: number, width: number, height: number, o: ResolvedOptions): OpSet;
|
||||
doubleLineOps(x1: number, y1: number, x2: number, y2: number, o: ResolvedOptions): Op[];
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import { ResolvedOptions } from '../core';
|
||||
import { PatternFiller, RenderHelper } from './filler-interface';
|
||||
export declare function getFiller(o: ResolvedOptions, helper: RenderHelper): PatternFiller;
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
import { HachureFiller } from './hachure-filler';
|
||||
import { ZigZagFiller } from './zigzag-filler';
|
||||
import { HatchFiller } from './hatch-filler';
|
||||
import { DotFiller } from './dot-filler';
|
||||
import { DashedFiller } from './dashed-filler';
|
||||
import { ZigZagLineFiller } from './zigzag-line-filler';
|
||||
const fillers = {};
|
||||
export function getFiller(o, helper) {
|
||||
let fillerName = o.fillStyle || 'hachure';
|
||||
if (!fillers[fillerName]) {
|
||||
switch (fillerName) {
|
||||
case 'zigzag':
|
||||
if (!fillers[fillerName]) {
|
||||
fillers[fillerName] = new ZigZagFiller(helper);
|
||||
}
|
||||
break;
|
||||
case 'cross-hatch':
|
||||
if (!fillers[fillerName]) {
|
||||
fillers[fillerName] = new HatchFiller(helper);
|
||||
}
|
||||
break;
|
||||
case 'dots':
|
||||
if (!fillers[fillerName]) {
|
||||
fillers[fillerName] = new DotFiller(helper);
|
||||
}
|
||||
break;
|
||||
case 'dashed':
|
||||
if (!fillers[fillerName]) {
|
||||
fillers[fillerName] = new DashedFiller(helper);
|
||||
}
|
||||
break;
|
||||
case 'zigzag-line':
|
||||
if (!fillers[fillerName]) {
|
||||
fillers[fillerName] = new ZigZagLineFiller(helper);
|
||||
}
|
||||
break;
|
||||
case 'hachure':
|
||||
default:
|
||||
fillerName = 'hachure';
|
||||
if (!fillers[fillerName]) {
|
||||
fillers[fillerName] = new HachureFiller(helper);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return fillers[fillerName];
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { PatternFiller, RenderHelper } from './filler-interface';
|
||||
import { ResolvedOptions, OpSet, Op } from '../core';
|
||||
import { Point, Line } from '../geometry';
|
||||
export declare class HachureFiller implements PatternFiller {
|
||||
private helper;
|
||||
constructor(helper: RenderHelper);
|
||||
fillPolygons(polygonList: Point[][], o: ResolvedOptions): OpSet;
|
||||
protected _fillPolygons(polygonList: Point[][], o: ResolvedOptions): OpSet;
|
||||
protected renderLines(lines: Line[], o: ResolvedOptions): Op[];
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { polygonHachureLines } from './scan-line-hachure';
|
||||
export class HachureFiller {
|
||||
constructor(helper) {
|
||||
this.helper = helper;
|
||||
}
|
||||
fillPolygons(polygonList, o) {
|
||||
return this._fillPolygons(polygonList, o);
|
||||
}
|
||||
_fillPolygons(polygonList, o) {
|
||||
const lines = polygonHachureLines(polygonList, o);
|
||||
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;
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { HachureFiller } from './hachure-filler';
|
||||
import { ResolvedOptions, OpSet } from '../core';
|
||||
import { Point } from '../geometry';
|
||||
export declare class HatchFiller extends HachureFiller {
|
||||
fillPolygons(polygonList: Point[][], o: ResolvedOptions): OpSet;
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { HachureFiller } from './hachure-filler';
|
||||
export class HatchFiller extends HachureFiller {
|
||||
fillPolygons(polygonList, o) {
|
||||
const set = this._fillPolygons(polygonList, o);
|
||||
const o2 = Object.assign({}, o, { hachureAngle: o.hachureAngle + 90 });
|
||||
const set2 = this._fillPolygons(polygonList, o2);
|
||||
set.ops = set.ops.concat(set2.ops);
|
||||
return set;
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import { Point, Line } from '../geometry';
|
||||
import { ResolvedOptions } from '../core';
|
||||
export declare function polygonHachureLines(polygonList: Point[][], o: ResolvedOptions): Line[];
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { hachureLines } from 'hachure-fill';
|
||||
export function polygonHachureLines(polygonList, o) {
|
||||
var _a;
|
||||
const angle = o.hachureAngle + 90;
|
||||
let gap = o.hachureGap;
|
||||
if (gap < 0) {
|
||||
gap = o.strokeWidth * 4;
|
||||
}
|
||||
gap = Math.round(Math.max(gap, 0.1));
|
||||
let skipOffset = 1;
|
||||
if (o.roughness >= 1) {
|
||||
if ((((_a = o.randomizer) === null || _a === void 0 ? void 0 : _a.next()) || Math.random()) > 0.7) {
|
||||
skipOffset = gap;
|
||||
}
|
||||
}
|
||||
return hachureLines(polygonList, gap, angle, skipOffset || 1);
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { HachureFiller } from './hachure-filler';
|
||||
import { ResolvedOptions, OpSet } from '../core';
|
||||
import { Point } from '../geometry';
|
||||
export declare class ZigZagFiller extends HachureFiller {
|
||||
fillPolygons(polygonList: Point[][], o: ResolvedOptions): OpSet;
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import { HachureFiller } from './hachure-filler';
|
||||
import { polygonHachureLines } from './scan-line-hachure';
|
||||
import { lineLength } from '../geometry';
|
||||
export class ZigZagFiller extends HachureFiller {
|
||||
fillPolygons(polygonList, o) {
|
||||
let gap = o.hachureGap;
|
||||
if (gap < 0) {
|
||||
gap = o.strokeWidth * 4;
|
||||
}
|
||||
gap = Math.max(gap, 0.1);
|
||||
const o2 = Object.assign({}, o, { hachureGap: gap });
|
||||
const lines = polygonHachureLines(polygonList, o2);
|
||||
const zigZagAngle = (Math.PI / 180) * o.hachureAngle;
|
||||
const zigzagLines = [];
|
||||
const dgx = gap * 0.5 * Math.cos(zigZagAngle);
|
||||
const dgy = gap * 0.5 * Math.sin(zigZagAngle);
|
||||
for (const [p1, p2] of lines) {
|
||||
if (lineLength([p1, p2])) {
|
||||
zigzagLines.push([
|
||||
[p1[0] - dgx, p1[1] + dgy],
|
||||
[...p2],
|
||||
], [
|
||||
[p1[0] + dgx, p1[1] - dgy],
|
||||
[...p2],
|
||||
]);
|
||||
}
|
||||
}
|
||||
const ops = this.renderLines(zigzagLines, o);
|
||||
return { type: 'fillSketch', ops };
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { PatternFiller, RenderHelper } from './filler-interface';
|
||||
import { ResolvedOptions, OpSet } from '../core';
|
||||
import { Point } from '../geometry';
|
||||
export declare class ZigZagLineFiller implements PatternFiller {
|
||||
private helper;
|
||||
constructor(helper: RenderHelper);
|
||||
fillPolygons(polygonList: Point[][], o: ResolvedOptions): OpSet;
|
||||
private zigzagLines;
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import { lineLength } from '../geometry';
|
||||
import { polygonHachureLines } from './scan-line-hachure';
|
||||
export class ZigZagLineFiller {
|
||||
constructor(helper) {
|
||||
this.helper = helper;
|
||||
}
|
||||
fillPolygons(polygonList, o) {
|
||||
const gap = o.hachureGap < 0 ? (o.strokeWidth * 4) : o.hachureGap;
|
||||
const zo = o.zigzagOffset < 0 ? gap : o.zigzagOffset;
|
||||
o = Object.assign({}, o, { hachureGap: gap + zo });
|
||||
const lines = polygonHachureLines(polygonList, o);
|
||||
return { type: 'fillSketch', ops: this.zigzagLines(lines, zo, o) };
|
||||
}
|
||||
zigzagLines(lines, zo, o) {
|
||||
const ops = [];
|
||||
lines.forEach((line) => {
|
||||
const length = lineLength(line);
|
||||
const count = Math.round(length / (2 * zo));
|
||||
let p1 = line[0];
|
||||
let p2 = line[1];
|
||||
if (p1[0] > p2[0]) {
|
||||
p1 = line[1];
|
||||
p2 = line[0];
|
||||
}
|
||||
const alpha = Math.atan((p2[1] - p1[1]) / (p2[0] - p1[0]));
|
||||
for (let i = 0; i < count; i++) {
|
||||
const lstart = i * 2 * zo;
|
||||
const lend = (i + 1) * 2 * zo;
|
||||
const dz = Math.sqrt(2 * Math.pow(zo, 2));
|
||||
const start = [p1[0] + (lstart * Math.cos(alpha)), p1[1] + lstart * Math.sin(alpha)];
|
||||
const end = [p1[0] + (lend * Math.cos(alpha)), p1[1] + (lend * Math.sin(alpha))];
|
||||
const middle = [start[0] + dz * Math.cos(alpha + Math.PI / 4), start[1] + dz * Math.sin(alpha + Math.PI / 4)];
|
||||
ops.push(...this.helper.doubleLineOps(start[0], start[1], middle[0], middle[1], o), ...this.helper.doubleLineOps(middle[0], middle[1], end[0], end[1], o));
|
||||
}
|
||||
});
|
||||
return ops;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user