geometrix 0.5.10 → 0.5.12

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 (89) hide show
  1. package/dist/index.d.ts +505 -0
  2. package/dist/index.js +3848 -0
  3. package/package.json +7 -1
  4. package/.eslintignore +0 -17
  5. package/.eslintrc.cjs +0 -24
  6. package/.prettierignore +0 -15
  7. package/.prettierrc +0 -8
  8. package/src/aaExportContent.ts +0 -213
  9. package/src/aaExportFile.ts +0 -141
  10. package/src/aaParamGeom.ts +0 -62
  11. package/src/angle_utils.test.ts +0 -83
  12. package/src/angle_utils.ts +0 -98
  13. package/src/arc_to_stroke.ts +0 -73
  14. package/src/canvas_utils.test.ts +0 -28
  15. package/src/canvas_utils.ts +0 -159
  16. package/src/contour.test.ts +0 -37
  17. package/src/contour.ts +0 -806
  18. package/src/designParams.ts +0 -178
  19. package/src/figure.test.ts +0 -21
  20. package/src/figure.ts +0 -400
  21. package/src/index.ts +0 -16
  22. package/src/line.test.ts +0 -78
  23. package/src/line.ts +0 -359
  24. package/src/paramFile.ts +0 -52
  25. package/src/point.test.ts +0 -36
  26. package/src/point.ts +0 -246
  27. package/src/prepare_pax.ts +0 -102
  28. package/src/segment.test.ts +0 -26
  29. package/src/segment.ts +0 -701
  30. package/src/sub_design.ts +0 -16
  31. package/src/triangle_utils.test.ts +0 -38
  32. package/src/triangle_utils.ts +0 -112
  33. package/src/vector.test.ts +0 -28
  34. package/src/vector.ts +0 -122
  35. package/src/volume.ts +0 -50
  36. package/src/write_dxf.ts +0 -100
  37. package/src/write_openjscad.ts +0 -284
  38. package/src/write_openscad.ts +0 -305
  39. package/src/write_pax.ts +0 -73
  40. package/src/write_svg.ts +0 -101
  41. package/svg/any_triangle.svg +0 -156
  42. package/svg/arc_definition.svg +0 -506
  43. package/svg/construct_corner_rounded_ext_arc_ext_arc.svg +0 -378
  44. package/svg/construct_corner_rounded_int_arc_ext_arc.svg +0 -359
  45. package/svg/construct_corner_rounded_int_arc_int_arc.svg +0 -356
  46. package/svg/construct_corner_rounded_stroke_ext_arc.svg +0 -374
  47. package/svg/construct_corner_rounded_stroke_ext_arc_obtuse.svg +0 -370
  48. package/svg/construct_corner_rounded_stroke_ext_arc_obtuse_method2.svg +0 -311
  49. package/svg/construct_corner_rounded_stroke_int_arc.svg +0 -364
  50. package/svg/construct_corner_rounded_stroke_int_arc_obtuse.svg +0 -358
  51. package/svg/construct_corner_rounded_stroke_int_arc_obtuse_method2.svg +0 -237
  52. package/svg/construct_corner_rounded_stroke_stroke.svg +0 -280
  53. package/svg/construct_corner_wideacc.svg +0 -286
  54. package/svg/construct_corner_widened.svg +0 -278
  55. package/svg/construction_of_line_intersection_1.svg +0 -187
  56. package/svg/construction_of_line_intersection_2.svg +0 -189
  57. package/svg/contour_arc_definition_options.svg +0 -324
  58. package/svg/contour_point_absolute_relative.svg +0 -258
  59. package/svg/contour_tangential_two_arcs.svg +0 -531
  60. package/svg/contour_tangential_two_arcs_impossible_case.svg +0 -175
  61. package/svg/contour_tangential_two_arcs_requirements.svg +0 -364
  62. package/svg/corner_rounded_ext_arc_ext_arc.svg +0 -281
  63. package/svg/corner_rounded_int_arc_ext_arc.svg +0 -281
  64. package/svg/corner_rounded_int_arc_int_arc.svg +0 -279
  65. package/svg/corner_rounded_stroke_ext_arc.svg +0 -218
  66. package/svg/corner_rounded_stroke_int_arc.svg +0 -225
  67. package/svg/corner_rounded_stroke_stroke.svg +0 -174
  68. package/svg/geom_dev.svg +0 -14708
  69. package/svg/geom_modules.svg +0 -246
  70. package/svg/geom_user.svg +0 -58
  71. package/svg/line_axis_x_cases.svg +0 -1408
  72. package/svg/line_axis_y_cases.svg +0 -1369
  73. package/svg/line_distanceOrig.svg +0 -318
  74. package/svg/line_getAxisXIntersection.svg +0 -262
  75. package/svg/line_getAxisXIntersection_2.svg +0 -244
  76. package/svg/line_getAxisYIntersection.svg +0 -304
  77. package/svg/line_getAxisYIntersection_2.svg +0 -285
  78. package/svg/line_getAxisYIntersection_3.svg +0 -277
  79. package/svg/line_intersection.svg +0 -346
  80. package/svg/line_projectPoint.svg +0 -311
  81. package/svg/point_1.svg +0 -243
  82. package/svg/point_2.svg +0 -409
  83. package/svg/point_3.svg +0 -298
  84. package/svg/point_4.svg +0 -272
  85. package/svg/point_5.svg +0 -356
  86. package/svg/right_triangle.svg +0 -194
  87. package/svg/vector_definition.svg +0 -130
  88. package/tsconfig.json +0 -13
  89. 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 };