geometrix 0.5.10 → 0.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/index.d.ts +505 -0
  2. package/dist/index.js +3848 -0
  3. package/dist/index.js.map +1 -0
  4. package/package.json +6 -1
  5. package/.eslintignore +0 -17
  6. package/.eslintrc.cjs +0 -24
  7. package/.prettierignore +0 -15
  8. package/.prettierrc +0 -8
  9. package/src/aaExportContent.ts +0 -213
  10. package/src/aaExportFile.ts +0 -141
  11. package/src/aaParamGeom.ts +0 -62
  12. package/src/angle_utils.test.ts +0 -83
  13. package/src/angle_utils.ts +0 -98
  14. package/src/arc_to_stroke.ts +0 -73
  15. package/src/canvas_utils.test.ts +0 -28
  16. package/src/canvas_utils.ts +0 -159
  17. package/src/contour.test.ts +0 -37
  18. package/src/contour.ts +0 -806
  19. package/src/designParams.ts +0 -178
  20. package/src/figure.test.ts +0 -21
  21. package/src/figure.ts +0 -400
  22. package/src/index.ts +0 -16
  23. package/src/line.test.ts +0 -78
  24. package/src/line.ts +0 -359
  25. package/src/paramFile.ts +0 -52
  26. package/src/point.test.ts +0 -36
  27. package/src/point.ts +0 -246
  28. package/src/prepare_pax.ts +0 -102
  29. package/src/segment.test.ts +0 -26
  30. package/src/segment.ts +0 -701
  31. package/src/sub_design.ts +0 -16
  32. package/src/triangle_utils.test.ts +0 -38
  33. package/src/triangle_utils.ts +0 -112
  34. package/src/vector.test.ts +0 -28
  35. package/src/vector.ts +0 -122
  36. package/src/volume.ts +0 -50
  37. package/src/write_dxf.ts +0 -100
  38. package/src/write_openjscad.ts +0 -284
  39. package/src/write_openscad.ts +0 -305
  40. package/src/write_pax.ts +0 -73
  41. package/src/write_svg.ts +0 -101
  42. package/svg/any_triangle.svg +0 -156
  43. package/svg/arc_definition.svg +0 -506
  44. package/svg/construct_corner_rounded_ext_arc_ext_arc.svg +0 -378
  45. package/svg/construct_corner_rounded_int_arc_ext_arc.svg +0 -359
  46. package/svg/construct_corner_rounded_int_arc_int_arc.svg +0 -356
  47. package/svg/construct_corner_rounded_stroke_ext_arc.svg +0 -374
  48. package/svg/construct_corner_rounded_stroke_ext_arc_obtuse.svg +0 -370
  49. package/svg/construct_corner_rounded_stroke_ext_arc_obtuse_method2.svg +0 -311
  50. package/svg/construct_corner_rounded_stroke_int_arc.svg +0 -364
  51. package/svg/construct_corner_rounded_stroke_int_arc_obtuse.svg +0 -358
  52. package/svg/construct_corner_rounded_stroke_int_arc_obtuse_method2.svg +0 -237
  53. package/svg/construct_corner_rounded_stroke_stroke.svg +0 -280
  54. package/svg/construct_corner_wideacc.svg +0 -286
  55. package/svg/construct_corner_widened.svg +0 -278
  56. package/svg/construction_of_line_intersection_1.svg +0 -187
  57. package/svg/construction_of_line_intersection_2.svg +0 -189
  58. package/svg/contour_arc_definition_options.svg +0 -324
  59. package/svg/contour_point_absolute_relative.svg +0 -258
  60. package/svg/contour_tangential_two_arcs.svg +0 -531
  61. package/svg/contour_tangential_two_arcs_impossible_case.svg +0 -175
  62. package/svg/contour_tangential_two_arcs_requirements.svg +0 -364
  63. package/svg/corner_rounded_ext_arc_ext_arc.svg +0 -281
  64. package/svg/corner_rounded_int_arc_ext_arc.svg +0 -281
  65. package/svg/corner_rounded_int_arc_int_arc.svg +0 -279
  66. package/svg/corner_rounded_stroke_ext_arc.svg +0 -218
  67. package/svg/corner_rounded_stroke_int_arc.svg +0 -225
  68. package/svg/corner_rounded_stroke_stroke.svg +0 -174
  69. package/svg/geom_dev.svg +0 -14708
  70. package/svg/geom_modules.svg +0 -246
  71. package/svg/geom_user.svg +0 -58
  72. package/svg/line_axis_x_cases.svg +0 -1408
  73. package/svg/line_axis_y_cases.svg +0 -1369
  74. package/svg/line_distanceOrig.svg +0 -318
  75. package/svg/line_getAxisXIntersection.svg +0 -262
  76. package/svg/line_getAxisXIntersection_2.svg +0 -244
  77. package/svg/line_getAxisYIntersection.svg +0 -304
  78. package/svg/line_getAxisYIntersection_2.svg +0 -285
  79. package/svg/line_getAxisYIntersection_3.svg +0 -277
  80. package/svg/line_intersection.svg +0 -346
  81. package/svg/line_projectPoint.svg +0 -311
  82. package/svg/point_1.svg +0 -243
  83. package/svg/point_2.svg +0 -409
  84. package/svg/point_3.svg +0 -298
  85. package/svg/point_4.svg +0 -272
  86. package/svg/point_5.svg +0 -356
  87. package/svg/right_triangle.svg +0 -194
  88. package/svg/vector_definition.svg +0 -130
  89. package/tsconfig.json +0 -13
  90. package/vitest.config.ts +0 -7
package/src/contour.ts DELETED
@@ -1,806 +0,0 @@
1
- // contour.ts
2
- // contour.ts deals with open and closed path composed of segments and arcs
3
- // contour.ts depends on point.ts, line.ts, vector.ts and segment.ts
4
- // contour.ts is used by figure.ts
5
-
6
- import type { tCanvasAdjust } from './canvas_utils';
7
- //import type { tPolar } from './point';
8
- //import { colorCanvasPoint } from '$lib/style/colors.scss';
9
- import {
10
- //degToRad,
11
- //radToDeg,
12
- roundZero,
13
- //withinZero2Pi,
14
- withinPiPi,
15
- //withinZeroPi,
16
- //withinHPiHPi,
17
- ffix
18
- } from './angle_utils';
19
- import { colors, point2canvas, radius2canvas } from './canvas_utils';
20
- //import {
21
- // //rightTriLaFromLbLc,
22
- // rightTriLbFromLaLc
23
- // //lcFromLaLbAc,
24
- // //aCFromLaLbLc,
25
- // //aCFromAaAb,
26
- // //lbFromLaAaAb,
27
- // //aBFromLaLbAa
28
- //} from './triangle_utils';
29
- import { point, Point } from './point';
30
- import { line, Line, bisector, circleCenter } from './line';
31
- //import { vector, Vector } from './vector';
32
- import * as segLib from './segment';
33
- import { svgPath, svgCircleString } from './write_svg';
34
- import type { DxfSeg } from './write_dxf';
35
- import { dxfSegLine, dxfSegArc, dxfSegCircle } from './write_dxf';
36
- import type { tPaxContourPath, tPaxContourCircle, tPaxContour } from './prepare_pax';
37
- import { paxPath, paxCircle } from './prepare_pax';
38
-
39
- /* AContour abstract class */
40
-
41
- abstract class AContour {
42
- abstract circle: boolean;
43
- abstract imposedColor: string;
44
- abstract draw(ctx: CanvasRenderingContext2D, cAdjust: tCanvasAdjust, color: string): void;
45
- abstract extractSkeleton(): AContour;
46
- abstract generateContour(): AContour;
47
- abstract generatePoints(): Point[];
48
- abstract generateLines(): Line[];
49
- abstract check(): string;
50
- abstract toSvg(yCeiling: number, color?: string): string;
51
- abstract toDxfSeg(): DxfSeg[];
52
- abstract toPax(): tPaxContour;
53
- }
54
-
55
- /* Contour class */
56
-
57
- class Contour extends AContour {
58
- circle = false;
59
- segments: segLib.Segment1[];
60
- points: Point[];
61
- debugPoints: Point[];
62
- debugLines: Line[];
63
- lastPoint: Point;
64
- imposedColor: string;
65
- constructor(ix: number, iy: number, icolor = '') {
66
- super();
67
- this.segments = [new segLib.Segment1(segLib.SegEnum.eStart, ix, iy, 0)];
68
- this.points = [];
69
- this.debugPoints = [];
70
- this.debugLines = [];
71
- this.lastPoint = point(ix, iy);
72
- this.imposedColor = icolor;
73
- }
74
- setLastPoint(ix: number, iy: number) {
75
- this.lastPoint = point(ix, iy);
76
- }
77
- getLastPoint(): Point {
78
- return this.lastPoint;
79
- }
80
- addPointA(ax: number, ay: number): Contour {
81
- if (this.points.length > 2) {
82
- throw `err311: contour add too much point ${ax} ${ay}`;
83
- }
84
- this.points.push(point(ax, ay));
85
- return this;
86
- }
87
- addPointAP(aa: number, al: number): Contour {
88
- const p1 = point(0, 0).translatePolar(aa, al);
89
- this.addPointA(p1.cx, p1.cy);
90
- return this;
91
- }
92
- addPointR(rx: number, ry: number): Contour {
93
- const plast = this.getLastPoint();
94
- const p1 = plast.translate(rx, ry);
95
- this.addPointA(p1.cx, p1.cy);
96
- return this;
97
- }
98
- addPointRP(ra: number, rl: number): Contour {
99
- const plast = this.getLastPoint();
100
- const p1 = plast.translatePolar(ra, rl);
101
- this.addPointA(p1.cx, p1.cy);
102
- return this;
103
- }
104
- addSeg(iSeg: segLib.Segment1): Contour {
105
- this.segments.push(iSeg);
106
- return this;
107
- }
108
- addSegStroke(): Contour {
109
- if (this.points.length !== 1) {
110
- throw `err554: contour addSegStroke with unexpected points.length ${this.points.length}`;
111
- }
112
- const p1 = this.points.pop();
113
- if (p1 !== undefined) {
114
- const seg = new segLib.Segment1(segLib.SegEnum.eStroke, p1.cx, p1.cy, 0);
115
- if (!p1.isEqual(this.getLastPoint())) {
116
- this.addSeg(seg);
117
- this.setLastPoint(p1.cx, p1.cy);
118
- }
119
- // else no warning in order to avoid warning in gears
120
- } else {
121
- throw `err284: contour p1 is undefined`;
122
- }
123
- return this;
124
- }
125
- addSegStrokeA(ax: number, ay: number): Contour {
126
- this.addPointA(ax, ay).addSegStroke();
127
- return this;
128
- }
129
- addSegStrokeAP(aa: number, al: number): Contour {
130
- this.addPointAP(aa, al).addSegStroke();
131
- return this;
132
- }
133
- addSegStrokeR(rx: number, ry: number): Contour {
134
- this.addPointR(rx, ry).addSegStroke();
135
- return this;
136
- }
137
- addSegStrokeRP(ra: number, rl: number): Contour {
138
- this.addPointRP(ra, rl).addSegStroke();
139
- return this;
140
- }
141
- addSegArc(iRadius: number, iLarge: boolean, iCcw: boolean): Contour {
142
- if (this.points.length !== 1) {
143
- throw `err954: contour addSegArc with unexpected points.length ${this.points.length}`;
144
- }
145
- const p1 = this.points.pop();
146
- if (p1 !== undefined) {
147
- const seg = new segLib.Segment1(
148
- segLib.SegEnum.eArc,
149
- p1.cx,
150
- p1.cy,
151
- iRadius,
152
- iLarge,
153
- iCcw
154
- );
155
- if (!p1.isEqual(this.getLastPoint())) {
156
- this.addSeg(seg);
157
- this.setLastPoint(p1.cx, p1.cy);
158
- } else {
159
- console.log(
160
- `warn144: addSegArc last and new point identical ${ffix(p1.cx)} ${ffix(p1.cy)}`
161
- );
162
- }
163
- //this.debugPoints.push(p1);
164
- } else {
165
- throw `err482: contour p1 is undefined`;
166
- }
167
- return this;
168
- }
169
- addSegArc2(): Contour {
170
- if (this.points.length !== 2) {
171
- throw `err958: contour addSegArc2 with unexpected points.length ${this.points.length}`;
172
- }
173
- const p2 = this.points.pop();
174
- const p1 = this.points.pop();
175
- if (p1 !== undefined && p2 !== undefined) {
176
- const p0 = this.getLastPoint();
177
- const p3 = circleCenter(p0, p1, p2);
178
- const radius = p3.distanceToPoint(p0);
179
- const p0p2middle = p0.middlePoint(p2);
180
- const a0 = p0p2middle.angleToPoint(p0);
181
- const a1 = p0p2middle.angleToPoint(p1);
182
- const a3 = p0p2middle.angleToPoint(p3);
183
- const a01 = withinPiPi(a1 - a0);
184
- const a03 = withinPiPi(a3 - a0);
185
- let large = false;
186
- let ccw = false;
187
- if (Math.sign(a03) * Math.sign(a01) > 0) {
188
- large = true;
189
- }
190
- if (Math.sign(a01) > 0) {
191
- ccw = true;
192
- }
193
- //console.log(`dbg437: ${radius.toFixed(2)} ${large} ${ccw}`);
194
- this.addPointA(p2.cx, p2.cy).addSegArc(radius, large, ccw);
195
- this.debugPoints.push(p1);
196
- //this.debugPoints.push(p2);
197
- } else {
198
- throw `err488: contour p1 or p2 or seg is undefined`;
199
- }
200
- return this;
201
- }
202
- addSegArc3(iTangentAngle1: number, firstNlast: boolean): Contour {
203
- if (this.points.length !== 1) {
204
- throw `err914: contour addSegArc3 with unexpected points.length ${this.points.length}`;
205
- }
206
- const p1 = this.points.pop();
207
- if (p1 !== undefined) {
208
- const p0 = this.getLastPoint();
209
- const lbi = bisector(p0, p1);
210
- let pref = p1;
211
- if (firstNlast) {
212
- pref = p0;
213
- }
214
- const lradial = line(pref.cx, pref.cy, iTangentAngle1 + Math.PI / 2);
215
- const pArcCenter = lbi.intersection(lradial);
216
- const radius = pArcCenter.distanceToPoint(p0);
217
- const pmid = p0.middlePoint(p1);
218
- const amid = pref.angleToPoint(pmid);
219
- const aref = withinPiPi(iTangentAngle1 - amid);
220
- let large = false;
221
- if (Math.abs(aref) > Math.PI / 2) {
222
- large = true;
223
- }
224
- let ccw = false;
225
- if (aref < 0) {
226
- ccw = true;
227
- }
228
- if (!firstNlast) {
229
- ccw = !ccw;
230
- }
231
- this.addPointA(p1.cx, p1.cy).addSegArc(radius, large, ccw);
232
- this.debugPoints.push(pmid);
233
- this.debugPoints.push(pArcCenter);
234
- } else {
235
- throw `err282: contour p1 is undefined`;
236
- }
237
- return this;
238
- }
239
- addSeg2Arcs(ita1: number, ita2: number): Contour {
240
- if (this.points.length !== 1) {
241
- throw `err214: contour addSeg2Arcs with unexpected points.length ${this.points.length}`;
242
- }
243
- const p1 = this.points.pop();
244
- if (p1 !== undefined) {
245
- const p0 = this.getLastPoint();
246
- const l01 = p0.distanceToPoint(p1);
247
- const a01 = p0.angleToPoint(p1);
248
- const a10 = p1.angleToPoint(p0);
249
- const au = withinPiPi(ita1 - a01);
250
- const av = -1 * withinPiPi(ita2 - a10);
251
- //console.log(`dbg998: addSeg2Arcs au ${au} av ${av}`);
252
- if (Math.abs(au) >= Math.PI / 2) {
253
- throw `err545: addSeg2Arcs with too large au ${au}`;
254
- }
255
- if (Math.abs(av) >= Math.PI / 2) {
256
- throw `err546: addSeg2Arcs with too large av ${av}`;
257
- }
258
- if (roundZero(au) === 0) {
259
- throw `err765: addSeg2Arcs with almost zero au ${au}`;
260
- }
261
- if (roundZero(av) === 0) {
262
- throw `err766: addSeg2Arcs with almost zero av ${av}`;
263
- }
264
- if (Math.sign(au) * Math.sign(av) < 1) {
265
- throw `err767: addSeg2Arcs with au/av bad orientation ${au} ${av}`;
266
- }
267
- // l01=BH+HC
268
- // HG=BH*tan(au/2)=HC*tan(av/2)
269
- // l01=HG*(1/tan(au/2)+1/tan(av/2))
270
- // l01*tan(au/2)*tan(av/2)=HG*tan(av/2)+HG*tan(au/2)
271
- // HG=l01*tan(au/2)*tan(av/2)/(tan(av/2)+tan(au/2))
272
- // trigonometry half-angle formula: tan(a/2)=(1-cos(a))/sin(a)
273
- // trigonometry tan(a+b)=(tan(a)+tan(b))/(1-tan(a)*tan(b))
274
- const tanu2 = Math.tan(au / 2);
275
- const tanv2 = Math.tan(av / 2);
276
- //const lHG = (l01 * tanu2 * tanv2) / (tanv2 + tanu2); // only for console.log()
277
- //const lBH = lHG/tanu2;
278
- const lBH = (l01 * tanv2) / (tanv2 + tanu2);
279
- // cos(PI/2-au)=sin(u)=lBH/lJB
280
- // lJB=lBH/sin(au)
281
- const lJB = Math.abs(lBH / Math.sin(au));
282
- //const lJH = lBH / Math.cotan(au);
283
- const lBG = lBH / Math.cos(au / 2);
284
- const lHC = (l01 * tanu2) / (tanv2 + tanu2);
285
- const lIC = Math.abs(lHC / Math.sin(av));
286
- //const lCG = lHC / Math.cos(av / 2); // only for console.log()
287
- const p2 = p0.translatePolar(a01 + au / 2, lBG);
288
- let ccw = false;
289
- if (Math.sign(au) < 0) {
290
- ccw = true;
291
- }
292
- //console.log(`dbg401: addSeg2Arcs l01 ${l01} lHG ${lHG}`);
293
- //console.log(`dbg409: addSeg2Arcs lBH ${lBH} lBG ${lBG} lJB ${lJB}`);
294
- //console.log(`dbg408: addSeg2Arcs lHC ${lHC} lCG ${lCG} lIC ${lIC}`);
295
- this.addPointA(p2.cx, p2.cy).addSegArc(lJB, false, ccw);
296
- this.addPointA(p1.cx, p1.cy).addSegArc(lIC, false, ccw);
297
- //this.debugPoints.push(p2);
298
- this.debugPoints.push(p0.translatePolar(a01, lBH)); // H
299
- this.debugPoints.push(p0.translatePolar(a01 + au - (Math.sign(au) * Math.PI) / 2, lJB)); // J
300
- //this.debugPoints.push(p1.translatePolar(a10, lHC)); // H
301
- this.debugPoints.push(p1.translatePolar(a10 - av + (Math.sign(au) * Math.PI) / 2, lIC)); // I
302
- } else {
303
- throw `err182: contour p1 is undefined`;
304
- }
305
- return this;
306
- }
307
- addCornerPointed(): Contour {
308
- const seg = new segLib.Segment1(segLib.SegEnum.ePointed, 0, 0, 0);
309
- this.addSeg(seg);
310
- return this;
311
- }
312
- addCornerRounded(iRadius: number): Contour {
313
- const seg = new segLib.Segment1(segLib.SegEnum.eRounded, 0, 0, iRadius);
314
- this.addSeg(seg);
315
- return this;
316
- }
317
- addCornerWidened(iRadius: number): Contour {
318
- const seg = new segLib.Segment1(segLib.SegEnum.eWidened, 0, 0, iRadius);
319
- this.addSeg(seg);
320
- return this;
321
- }
322
- addCornerWideAcc(iRadius: number): Contour {
323
- const seg = new segLib.Segment1(segLib.SegEnum.eWideAcc, 0, 0, iRadius);
324
- this.addSeg(seg);
325
- return this;
326
- }
327
- closeSegStroke(): Contour {
328
- const px = this.segments[0].px;
329
- const py = this.segments[0].py;
330
- this.addSegStrokeA(px, py);
331
- return this;
332
- }
333
- closeSegArc(iRadius: number, iLarge: boolean, iCcw: boolean): Contour {
334
- const px = this.segments[0].px;
335
- const py = this.segments[0].py;
336
- this.addPointA(px, py).addSegArc(iRadius, iLarge, iCcw);
337
- return this;
338
- }
339
- clone(): Contour {
340
- const rctr = new Contour(this.segments[0].px, this.segments[0].py);
341
- for (const seg of this.segments) {
342
- const nseg = seg.clone();
343
- if (nseg.sType !== segLib.SegEnum.eStart) {
344
- rctr.addSeg(nseg);
345
- if (segLib.isSeg(nseg.sType)) {
346
- rctr.setLastPoint(nseg.px, nseg.py);
347
- }
348
- }
349
- }
350
- return rctr;
351
- }
352
- translate(ix: number, iy: number): Contour {
353
- const p0x = this.segments[0].px + ix;
354
- const p0y = this.segments[0].py + iy;
355
- const rctr = new Contour(p0x, p0y);
356
- for (const seg of this.segments) {
357
- const nseg = seg.clone();
358
- if (segLib.isSeg(seg.sType)) {
359
- nseg.px += ix;
360
- nseg.py += iy;
361
- }
362
- if (nseg.sType !== segLib.SegEnum.eStart) {
363
- rctr.addSeg(nseg);
364
- if (segLib.isSeg(nseg.sType)) {
365
- rctr.setLastPoint(nseg.px, nseg.py);
366
- }
367
- }
368
- }
369
- return rctr;
370
- }
371
- translatePolar(ia: number, il: number): Contour {
372
- return this.translate(il * Math.cos(ia), il * Math.sin(ia));
373
- }
374
- rotate(ix: number, iy: number, ia: number): Contour {
375
- const ic = point(ix, iy);
376
- const pStart = point(this.segments[0].px, this.segments[0].py);
377
- const pStartRot = pStart.rotate(ic, ia);
378
- const rctr = new Contour(pStartRot.cx, pStartRot.cy);
379
- for (const seg of this.segments) {
380
- const nseg = seg.clone();
381
- if (segLib.isSeg(seg.sType)) {
382
- const pt = point(nseg.px, nseg.py);
383
- const ptRot = pt.rotate(ic, ia);
384
- nseg.px = ptRot.cx;
385
- nseg.py = ptRot.cy;
386
- }
387
- if (nseg.sType !== segLib.SegEnum.eStart) {
388
- rctr.addSeg(nseg);
389
- if (segLib.isSeg(nseg.sType)) {
390
- rctr.setLastPoint(nseg.px, nseg.py);
391
- }
392
- }
393
- }
394
- return rctr;
395
- }
396
- scale(ix: number, iy: number, ir: number, scaleCorner = false): Contour {
397
- const ic = point(ix, iy);
398
- const pStart = point(this.segments[0].px, this.segments[0].py);
399
- const pStartScale = pStart.scale(ic, ir);
400
- const rctr = new Contour(pStartScale.cx, pStartScale.cy);
401
- for (const seg of this.segments) {
402
- const nseg = seg.clone();
403
- if (segLib.isSeg(seg.sType)) {
404
- const pt = point(nseg.px, nseg.py);
405
- const ptScale = pt.scale(ic, ir);
406
- nseg.px = ptScale.cx;
407
- nseg.py = ptScale.cy;
408
- }
409
- if (seg.sType === segLib.SegEnum.eArc) {
410
- nseg.radius *= ir;
411
- }
412
- if (segLib.isActiveCorner(seg.sType) && scaleCorner) {
413
- nseg.radius *= ir;
414
- }
415
- if (nseg.sType !== segLib.SegEnum.eStart) {
416
- rctr.addSeg(nseg);
417
- if (segLib.isSeg(nseg.sType)) {
418
- rctr.setLastPoint(nseg.px, nseg.py);
419
- }
420
- }
421
- }
422
- return rctr;
423
- }
424
- addPartial(iContour: Contour): Contour {
425
- if (this.points.length > 0) {
426
- throw `err911: addPartial, points should be used ${this.points.length}`;
427
- }
428
- for (const seg of iContour.segments) {
429
- if (seg.sType !== segLib.SegEnum.eStart) {
430
- this.addSeg(seg);
431
- if (segLib.isSeg(seg.sType)) {
432
- this.setLastPoint(seg.px, seg.py);
433
- }
434
- }
435
- }
436
- return this;
437
- }
438
- draw(ctx: CanvasRenderingContext2D, cAdjust: tCanvasAdjust, color: string = colors.contour) {
439
- const theColor = this.imposedColor === '' ? color : this.imposedColor;
440
- let px1 = 0;
441
- let py1 = 0;
442
- for (const seg of this.segments) {
443
- if (seg.sType === segLib.SegEnum.eStroke) {
444
- const [cx1, cy1] = point2canvas(px1, py1, cAdjust);
445
- const [cx2, cy2] = point2canvas(seg.px, seg.py, cAdjust);
446
- ctx.beginPath();
447
- ctx.moveTo(cx1, cy1);
448
- ctx.lineTo(cx2, cy2);
449
- ctx.strokeStyle = theColor;
450
- ctx.stroke();
451
- }
452
- if (seg.sType === segLib.SegEnum.eArc) {
453
- try {
454
- const seg2 = segLib.arcSeg1To2(px1, py1, seg);
455
- const [cx3, cy3] = point2canvas(seg2.pc.cx, seg2.pc.cy, cAdjust);
456
- const cRadius = radius2canvas(seg.radius, cAdjust);
457
- ctx.beginPath();
458
- ctx.arc(cx3, cy3, cRadius, -seg2.a1, -seg2.a2, seg.arcCcw);
459
- ctx.strokeStyle = theColor;
460
- ctx.stroke();
461
- } catch (emsg) {
462
- console.log('err413: ' + (emsg as string));
463
- }
464
- }
465
- if (segLib.isAddPoint(seg.sType)) {
466
- px1 = seg.px;
467
- py1 = seg.py;
468
- }
469
- }
470
- }
471
- extractSkeleton(): Contour {
472
- const seg0 = this.segments[0];
473
- const rContour = new Contour(seg0.px, seg0.py);
474
- for (const seg of this.segments) {
475
- if (segLib.isSeg(seg.sType)) {
476
- rContour.addSeg(seg);
477
- }
478
- }
479
- return rContour;
480
- }
481
- generateContour(): Contour {
482
- segLib.gSegDbg.clearPoints();
483
- segLib.gSegDbg.clearLines();
484
- const segStack: segLib.Segment2[] = [];
485
- const segStackEnd: segLib.Segment2[] = [];
486
- let coType = 0;
487
- let px1 = 0;
488
- let py1 = 0;
489
- for (const seg of this.segments) {
490
- if (seg.sType === segLib.SegEnum.eStroke) {
491
- const p1 = point(px1, py1);
492
- const p2 = point(seg.px, seg.py);
493
- const p0 = point(0, 0);
494
- segStack.push(new segLib.Segment2(seg.sType, p1, p2, p0, 0, 0, 0, false));
495
- coType = 1;
496
- }
497
- if (seg.sType === segLib.SegEnum.eArc) {
498
- const seg2 = segLib.arcSeg1To2(px1, py1, seg);
499
- segStack.push(seg2);
500
- coType = 1;
501
- }
502
- const segz1 = segStack.at(-1);
503
- const segz2 = segStack.at(-2);
504
- if (segz1 !== undefined && segz2 !== undefined) {
505
- if (segLib.isSeg(segz1.sType) && segLib.isCorner(segz2.sType)) {
506
- const s3 = segStack.pop();
507
- const s2 = segStack.pop();
508
- const s1 = segStack.pop();
509
- if (s1 !== undefined && s2 !== undefined && s3 !== undefined) {
510
- const segs = segLib.makeCorner(s1, s2, s3);
511
- segStack.push(...segs);
512
- } else {
513
- throw `err603: contour generateContour internal error`;
514
- }
515
- }
516
- }
517
- if (segLib.isCorner(seg.sType)) {
518
- if (coType === 2) {
519
- throw `err419: generateContour with two consecutive corners ${seg.sType}`;
520
- }
521
- if (coType === 0 && segLib.isActiveCorner(seg.sType) && seg.radius > 0) {
522
- const p0 = point(0, 0);
523
- segStackEnd.push(
524
- new segLib.Segment2(seg.sType, p0, p0, p0, seg.radius, 0, 0, false)
525
- );
526
- }
527
- if (coType === 1 && segLib.isActiveCorner(seg.sType) && seg.radius > 0) {
528
- const p0 = point(0, 0);
529
- segStack.push(
530
- new segLib.Segment2(seg.sType, p0, p0, p0, seg.radius, 0, 0, false)
531
- );
532
- }
533
- coType = 2;
534
- }
535
- if (segLib.isAddPoint(seg.sType)) {
536
- px1 = seg.px;
537
- py1 = seg.py;
538
- }
539
- }
540
- if (segStackEnd.length > 0) {
541
- if (coType === 1) {
542
- segStack.push(...segStackEnd);
543
- } else {
544
- throw `err397: contour generateContour Corners defined at end and begining`;
545
- }
546
- }
547
- const segz1 = segStack.at(-1);
548
- if (segz1 !== undefined) {
549
- if (segLib.isCorner(segz1.sType)) {
550
- const s3 = segStack[0];
551
- const s2 = segStack.pop();
552
- const s1 = segStack.pop();
553
- if (s1 !== undefined && s2 !== undefined && s3 !== undefined) {
554
- const segs = segLib.makeCorner(s1, s2, s3);
555
- segStack.push(...segs.slice(0, -1));
556
- const s4 = segs.at(-1);
557
- if (s4 !== undefined) {
558
- segStack[0] = s4;
559
- } else {
560
- throw `err606: contour generateContour internal error`;
561
- }
562
- } else {
563
- throw `err602: contour generateContour internal error`;
564
- }
565
- }
566
- }
567
- const seg0 = segStack[0];
568
- const rContour = new Contour(seg0.p1.cx, seg0.p1.cy, this.imposedColor);
569
- rContour.debugPoints.push(...segLib.gSegDbg.getPoints());
570
- rContour.debugLines.push(...segLib.gSegDbg.getLines());
571
- //console.log(`dbg290: ${segLib.gSegDbg.debugPoints.length}`);
572
- for (const seg2 of segStack) {
573
- if (seg2.sType === segLib.SegEnum.eStroke) {
574
- rContour.addSegStrokeA(seg2.p2.cx, seg2.p2.cy);
575
- } else if (seg2.sType === segLib.SegEnum.eArc) {
576
- const seg1 = segLib.arcSeg2To1(seg2);
577
- rContour
578
- .addPointA(seg2.p2.cx, seg2.p2.cy)
579
- .addSegArc(seg1.radius, seg1.arcLarge, seg1.arcCcw);
580
- } else {
581
- throw `err986: contour generateContour unexpected in seg2 Enum ${seg2.sType}`;
582
- }
583
- }
584
- return rContour;
585
- }
586
- generatePoints(): Point[] {
587
- const rPoints = [];
588
- rPoints.push(...this.debugPoints);
589
- const seg0 = this.segments[0];
590
- rPoints.push(point(seg0.px, seg0.py));
591
- let px1 = 0;
592
- let py1 = 0;
593
- for (const seg of this.segments) {
594
- if (seg.sType === segLib.SegEnum.eArc) {
595
- try {
596
- const seg2 = segLib.arcSeg1To2(px1, py1, seg);
597
- const p3 = point(seg2.pc.cx, seg2.pc.cy);
598
- const a12h = withinPiPi((seg2.a2 - seg2.a1) / 2);
599
- let a3 = seg2.a1 + a12h;
600
- if (
601
- (Math.sign(a12h) > 0 && !seg.arcCcw) ||
602
- (Math.sign(a12h) < 0 && seg.arcCcw)
603
- ) {
604
- a3 += Math.PI;
605
- }
606
- const p4 = p3.translatePolar(a3, seg.radius);
607
- rPoints.push(p4);
608
- } catch (emsg) {
609
- console.log('err453: ' + (emsg as string));
610
- }
611
- }
612
- if (segLib.isAddPoint(seg.sType)) {
613
- px1 = seg.px;
614
- py1 = seg.py;
615
- rPoints.push(point(px1, py1));
616
- }
617
- }
618
- return rPoints;
619
- }
620
- generateLines(): Line[] {
621
- const rLines = [];
622
- rLines.push(...this.debugLines);
623
- return rLines;
624
- }
625
- checkContour(ctr: Contour) {
626
- if (ctr.segments[0].sType !== segLib.SegEnum.eStart) {
627
- throw `err412: contour check first seg is not eStart ${ctr.segments[0].sType}`;
628
- }
629
- let px1 = 0;
630
- let py1 = 0;
631
- for (const seg of ctr.segments) {
632
- if (seg.sType === segLib.SegEnum.eArc) {
633
- try {
634
- segLib.arcSeg1To2(px1, py1, seg);
635
- } catch (emsg) {
636
- throw `err778: ${emsg as string}`;
637
- }
638
- }
639
- if (segLib.isAddPoint(seg.sType)) {
640
- px1 = seg.px;
641
- py1 = seg.py;
642
- }
643
- }
644
- const px0 = ctr.segments[0].px;
645
- const py0 = ctr.segments[0].py;
646
- if (roundZero(px1 - px0) !== 0 || roundZero(py1 - py0) !== 0) {
647
- throw `err414: contour check, contour is not closed px ${px0} ${px1} py ${px0} ${py0}`;
648
- }
649
- }
650
- check(): string {
651
- segLib.gSegDbg.clearMsg();
652
- this.checkContour(this);
653
- const ctrG = this.generateContour();
654
- this.checkContour(ctrG);
655
- return segLib.gSegDbg.getMsg();
656
- }
657
- toSvg(yCeiling: number, color = ''): string {
658
- const sPath = svgPath();
659
- for (const seg of this.segments) {
660
- if (seg.sType === segLib.SegEnum.eStart) {
661
- sPath.addStart(seg.px, yCeiling - seg.py);
662
- } else if (seg.sType === segLib.SegEnum.eStroke) {
663
- sPath.addStroke(seg.px, yCeiling - seg.py);
664
- } else if (seg.sType === segLib.SegEnum.eArc) {
665
- sPath.addArc(seg.px, yCeiling - seg.py, seg.radius, seg.arcLarge, !seg.arcCcw);
666
- } else {
667
- console.log(`err631: contour.toSvg has unknown segment type ${seg.sType}`);
668
- }
669
- }
670
- const rSvg = sPath.stringify(color);
671
- return rSvg;
672
- }
673
- toDxfSeg(): DxfSeg[] {
674
- const rDxfSeg: DxfSeg[] = [];
675
- let px1 = 0;
676
- let py1 = 0;
677
- for (const seg of this.segments) {
678
- if (seg.sType === segLib.SegEnum.eStroke) {
679
- rDxfSeg.push(dxfSegLine(px1, py1, seg.px, seg.py));
680
- } else if (seg.sType === segLib.SegEnum.eArc) {
681
- try {
682
- const seg2 = segLib.arcSeg1To2(px1, py1, seg);
683
- rDxfSeg.push(
684
- dxfSegArc(seg2.pc.cx, seg2.pc.cy, seg.radius, seg2.a1, seg2.a2, seg2.arcCcw)
685
- );
686
- } catch (emsg) {
687
- console.log('err413: ' + (emsg as string));
688
- }
689
- }
690
- if (segLib.isAddPoint(seg.sType)) {
691
- px1 = seg.px;
692
- py1 = seg.py;
693
- }
694
- }
695
- return rDxfSeg;
696
- }
697
- toPax(): tPaxContourPath {
698
- const pPath = paxPath();
699
- for (const seg of this.segments) {
700
- if (seg.sType === segLib.SegEnum.eStart) {
701
- pPath.addStart(seg.px, seg.py);
702
- } else if (seg.sType === segLib.SegEnum.eStroke) {
703
- pPath.addStroke(seg.px, seg.py);
704
- } else if (seg.sType === segLib.SegEnum.eArc) {
705
- pPath.addArc(seg.px, seg.py, seg.radius, seg.arcLarge, seg.arcCcw);
706
- } else {
707
- console.log(`err709: contour.toPax has unknown segment type ${seg.sType}`);
708
- }
709
- }
710
- const rPaxC = pPath.toJson();
711
- return rPaxC;
712
- }
713
- }
714
-
715
- /* ContourCircle class */
716
-
717
- class ContourCircle extends AContour {
718
- circle = true;
719
- px: number;
720
- py: number;
721
- radius: number;
722
- imposedColor: string;
723
- constructor(ix: number, iy: number, iRadius: number, icolor = '') {
724
- super();
725
- this.px = ix;
726
- this.py = iy;
727
- this.radius = iRadius;
728
- this.imposedColor = icolor;
729
- }
730
- clone(): ContourCircle {
731
- const rctr = new ContourCircle(this.px, this.py, this.radius, this.imposedColor);
732
- return rctr;
733
- }
734
- translate(ix: number, iy: number): ContourCircle {
735
- const rctr = new ContourCircle(this.px + ix, this.py + iy, this.radius, this.imposedColor);
736
- return rctr;
737
- }
738
- translatePolar(ia: number, il: number): ContourCircle {
739
- return this.translate(il * Math.cos(ia), il * Math.sin(ia));
740
- }
741
- rotate(ix: number, iy: number, ia: number): ContourCircle {
742
- const ic = point(ix, iy);
743
- const nCenter = point(this.px, this.py).rotate(ic, ia);
744
- const rctr = new ContourCircle(nCenter.cx, nCenter.cy, this.radius, this.imposedColor);
745
- return rctr;
746
- }
747
- draw(ctx: CanvasRenderingContext2D, cAdjust: tCanvasAdjust, color: string = colors.contour) {
748
- const [cx3, cy3] = point2canvas(this.px, this.py, cAdjust);
749
- const cRadius = radius2canvas(this.radius, cAdjust);
750
- const theColor = this.imposedColor === '' ? color : this.imposedColor;
751
- ctx.beginPath();
752
- ctx.arc(cx3, cy3, cRadius, 0, 2 * Math.PI, true);
753
- ctx.strokeStyle = theColor;
754
- ctx.stroke();
755
- }
756
- extractSkeleton(): ContourCircle {
757
- const rContour = new ContourCircle(this.px, this.py, this.radius);
758
- return rContour;
759
- }
760
- generateContour(): ContourCircle {
761
- const rContour = new ContourCircle(this.px, this.py, this.radius, this.imposedColor);
762
- return rContour;
763
- }
764
- generatePoints(): Point[] {
765
- const rPoints = [];
766
- const p1 = point(this.px, this.py);
767
- rPoints.push(p1);
768
- for (let i = 0; i < 4; i++) {
769
- const p2 = p1.translatePolar((i * Math.PI) / 2, this.radius);
770
- rPoints.push(p2);
771
- }
772
- return rPoints;
773
- }
774
- generateLines(): Line[] {
775
- return [];
776
- }
777
- check(): string {
778
- return '';
779
- }
780
- toSvg(yCeiling: number, color = ''): string {
781
- const rSvg = svgCircleString(this.px, yCeiling - this.py, this.radius, color);
782
- return rSvg;
783
- }
784
- toDxfSeg(): DxfSeg[] {
785
- const rDxfSeg: DxfSeg[] = [];
786
- rDxfSeg.push(dxfSegCircle(this.px, this.py, this.radius));
787
- return rDxfSeg;
788
- }
789
- toPax(): tPaxContourCircle {
790
- const rPaxC = paxCircle(this.px, this.py, this.radius);
791
- return rPaxC;
792
- }
793
- }
794
-
795
- // instantiation functions
796
- function contour(ix: number, iy: number, icolor = ''): Contour {
797
- return new Contour(ix, iy, icolor);
798
- }
799
- function contourCircle(ix: number, iy: number, iRadius: number, icolor = ''): ContourCircle {
800
- return new ContourCircle(ix, iy, iRadius, icolor);
801
- }
802
-
803
- type tContour = Contour | ContourCircle;
804
-
805
- export type { tContour };
806
- export { Contour, ContourCircle, contour, contourCircle };