@bitbybit-dev/base 0.20.11 → 0.20.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.
@@ -0,0 +1,3 @@
1
+ export declare class GlobalCDNProvider {
2
+ static BITBYBIT_CDN_URL: string;
3
+ }
@@ -0,0 +1,3 @@
1
+ export class GlobalCDNProvider {
2
+ }
3
+ GlobalCDNProvider.BITBYBIT_CDN_URL = "https://cdn.jsdelivr.net/gh/bitbybit-dev/bitbybit-assets@0.20.12";
@@ -1 +1,2 @@
1
1
  export * from "./services";
2
+ export * from "./GlobalCDNProvider";
package/lib/api/index.js CHANGED
@@ -1 +1,2 @@
1
1
  export * from "./services";
2
+ export * from "./GlobalCDNProvider";
@@ -143,11 +143,25 @@ export declare namespace IO {
143
143
  * Main DXF model containing all path parts
144
144
  */
145
145
  class DxfModelDto {
146
- constructor(dxfPathsParts?: DxfPathsPartDto[]);
146
+ constructor(dxfPathsParts?: DxfPathsPartDto[], colorFormat?: "aci" | "truecolor", acadVersion?: "AC1009" | "AC1015");
147
147
  /**
148
148
  * Array of path parts, each containing paths with segments
149
149
  * @default undefined
150
150
  */
151
151
  dxfPathsParts: DxfPathsPartDto[];
152
+ /**
153
+ * Color format to use in the DXF file
154
+ * - "aci": AutoCAD Color Index (1-255) - Better compatibility with older CAD software like Design CAD 3D Max
155
+ * - "truecolor": 24-bit RGB true color - Full color spectrum, requires newer CAD software
156
+ * @default aci
157
+ */
158
+ colorFormat?: "aci" | "truecolor";
159
+ /**
160
+ * AutoCAD version format for DXF file
161
+ * - "AC1009": AutoCAD R12/R11 - Maximum compatibility with older CAD software (e.g., Design CAD 3D Max)
162
+ * - "AC1015": AutoCAD 2000 - Modern format with extended features
163
+ * @default AC1009
164
+ */
165
+ acadVersion?: "AC1009" | "AC1015";
152
166
  }
153
167
  }
@@ -142,10 +142,30 @@ export var IO;
142
142
  * Main DXF model containing all path parts
143
143
  */
144
144
  class DxfModelDto {
145
- constructor(dxfPathsParts) {
145
+ constructor(dxfPathsParts, colorFormat, acadVersion) {
146
+ /**
147
+ * Color format to use in the DXF file
148
+ * - "aci": AutoCAD Color Index (1-255) - Better compatibility with older CAD software like Design CAD 3D Max
149
+ * - "truecolor": 24-bit RGB true color - Full color spectrum, requires newer CAD software
150
+ * @default aci
151
+ */
152
+ this.colorFormat = "aci";
153
+ /**
154
+ * AutoCAD version format for DXF file
155
+ * - "AC1009": AutoCAD R12/R11 - Maximum compatibility with older CAD software (e.g., Design CAD 3D Max)
156
+ * - "AC1015": AutoCAD 2000 - Modern format with extended features
157
+ * @default AC1009
158
+ */
159
+ this.acadVersion = "AC1009";
146
160
  if (dxfPathsParts !== undefined) {
147
161
  this.dxfPathsParts = dxfPathsParts;
148
162
  }
163
+ if (colorFormat !== undefined) {
164
+ this.colorFormat = colorFormat;
165
+ }
166
+ if (acadVersion !== undefined) {
167
+ this.acadVersion = acadVersion;
168
+ }
149
169
  }
150
170
  }
151
171
  IO.DxfModelDto = DxfModelDto;
@@ -1,6 +1,8 @@
1
1
  import * as Inputs from "../../../inputs";
2
2
  export declare class DxfGenerator {
3
3
  private entityHandle;
4
+ private colorFormat;
5
+ private acadVersion;
4
6
  /**
5
7
  * Generate a complete DXF file content from path-based entities
6
8
  */
@@ -13,6 +15,38 @@ export declare class DxfGenerator {
13
15
  * Generate DXF tables section (layers, line types, etc.)
14
16
  */
15
17
  private generateTables;
18
+ /**
19
+ * Generate line type table
20
+ */
21
+ private generateLineTypeTable;
22
+ /**
23
+ * Generate text style table
24
+ */
25
+ private generateStyleTable;
26
+ /**
27
+ * Generate VPORT table (viewport configuration)
28
+ */
29
+ private generateVportTable;
30
+ /**
31
+ * Generate VIEW table (empty but required for AC1009)
32
+ */
33
+ private generateViewTable;
34
+ /**
35
+ * Generate UCS table (user coordinate system - empty but required for AC1009)
36
+ */
37
+ private generateUcsTable;
38
+ /**
39
+ * Generate APPID table (application ID - required for AC1009)
40
+ */
41
+ private generateAppidTable;
42
+ /**
43
+ * Generate DIMSTYLE table (dimension style - empty but required for AC1009)
44
+ */
45
+ private generateDimstyleTable;
46
+ /**
47
+ * Generate blocks section (empty but required)
48
+ */
49
+ private generateBlocks;
16
50
  /**
17
51
  * Generate layer table based on unique layers in all parts
18
52
  */
@@ -76,7 +110,12 @@ export declare class DxfGenerator {
76
110
  /**
77
111
  * Convert color to DXF format
78
112
  * Accepts hex color (#RRGGBB) or ACI color index (1-255)
79
- * Returns appropriate DXF color codes
113
+ * Returns appropriate DXF color codes based on colorFormat setting
80
114
  */
81
115
  private convertColorToDxf;
116
+ /**
117
+ * Convert RGB values to nearest AutoCAD Color Index (ACI)
118
+ * Uses a simplified mapping to standard ACI colors
119
+ */
120
+ private rgbToAciColorIndex;
82
121
  }
@@ -1,16 +1,23 @@
1
1
  export class DxfGenerator {
2
2
  constructor() {
3
- this.entityHandle = 1;
3
+ this.entityHandle = 256; // Start at 256 to avoid conflicts with system handles
4
+ this.colorFormat = "aci";
5
+ this.acadVersion = "AC1009";
4
6
  }
5
7
  /**
6
8
  * Generate a complete DXF file content from path-based entities
7
9
  */
8
10
  generateDxf(dxfInputs) {
11
+ // Set format options from input
12
+ this.colorFormat = dxfInputs.colorFormat || "aci";
13
+ this.acadVersion = dxfInputs.acadVersion || "AC1009";
9
14
  const dxfContent = [];
10
15
  // Header section
11
16
  dxfContent.push(...this.generateHeader());
12
17
  // Tables section
13
18
  dxfContent.push(...this.generateTables(dxfInputs));
19
+ // Blocks section (required by many CAD programs)
20
+ dxfContent.push(...this.generateBlocks());
14
21
  // Entities section
15
22
  dxfContent.push(...this.generateEntities(dxfInputs));
16
23
  // End of file
@@ -21,7 +28,7 @@ export class DxfGenerator {
21
28
  * Generate DXF header section
22
29
  */
23
30
  generateHeader() {
24
- return [
31
+ const header = [
25
32
  "0",
26
33
  "SECTION",
27
34
  "2",
@@ -29,22 +36,18 @@ export class DxfGenerator {
29
36
  "9",
30
37
  "$ACADVER",
31
38
  "1",
32
- "AC1015",
33
- "9",
34
- "$DWGCODEPAGE",
35
- "3",
36
- "ANSI_1252",
37
- "9",
38
- "$LASTSAVEDBY",
39
- "1",
40
- "bitbybit.dev",
41
- "9",
42
- "$HANDSEED",
43
- "5",
44
- "20000",
45
- "0",
46
- "ENDSEC"
39
+ this.acadVersion
47
40
  ];
41
+ if (this.acadVersion === "AC1009") {
42
+ // AC1009 (AutoCAD R12) - minimal header for maximum compatibility
43
+ header.push("9", "$DWGCODEPAGE", "3", "ascii", "9", "$HANDSEED", "5", "0");
44
+ }
45
+ else {
46
+ // AC1015 (AutoCAD 2000) - modern format
47
+ header.push("9", "$DWGCODEPAGE", "3", "ANSI_1252", "9", "$LASTSAVEDBY", "1", "bitbybit.dev", "9", "$HANDSEED", "5", "20000");
48
+ }
49
+ header.push("0", "ENDSEC");
50
+ return header;
48
51
  }
49
52
  /**
50
53
  * Generate DXF tables section (layers, line types, etc.)
@@ -56,11 +59,236 @@ export class DxfGenerator {
56
59
  "2",
57
60
  "TABLES"
58
61
  ];
62
+ // VPORT table (required for AC1009)
63
+ if (this.acadVersion === "AC1009") {
64
+ tables.push(...this.generateVportTable());
65
+ }
66
+ // Line type table (required)
67
+ tables.push(...this.generateLineTypeTable());
59
68
  // Layer table
60
69
  tables.push(...this.generateLayerTable(dxfInputs));
70
+ // Text style table (required for text entities, included for completeness)
71
+ tables.push(...this.generateStyleTable());
72
+ // Additional tables for AC1009
73
+ if (this.acadVersion === "AC1009") {
74
+ tables.push(...this.generateViewTable());
75
+ tables.push(...this.generateUcsTable());
76
+ tables.push(...this.generateAppidTable());
77
+ tables.push(...this.generateDimstyleTable());
78
+ }
61
79
  tables.push("0", "ENDSEC");
62
80
  return tables;
63
81
  }
82
+ /**
83
+ * Generate line type table
84
+ */
85
+ generateLineTypeTable() {
86
+ const ltype = [
87
+ "0",
88
+ "TABLE",
89
+ "2",
90
+ "LTYPE",
91
+ "70",
92
+ "1" // Number of line types
93
+ ];
94
+ if (this.acadVersion === "AC1015") {
95
+ ltype.push("5", "5", "100", "AcDbSymbolTable");
96
+ }
97
+ ltype.push("0", "LTYPE", "2", "CONTINUOUS", "70", this.acadVersion === "AC1009" ? "64" : "0", "3", "Solid line", "72", "65", "73", "0", "40", "0.0");
98
+ if (this.acadVersion === "AC1015") {
99
+ ltype.splice(ltype.indexOf("LTYPE") + 1, 0, "5", "14", "100", "AcDbSymbolTableRecord", "100", "AcDbLinetypeTableRecord");
100
+ }
101
+ ltype.push("0", "ENDTAB");
102
+ return ltype;
103
+ }
104
+ /**
105
+ * Generate text style table
106
+ */
107
+ generateStyleTable() {
108
+ const style = [
109
+ "0",
110
+ "TABLE",
111
+ "2",
112
+ "STYLE",
113
+ "70",
114
+ "1" // Number of styles
115
+ ];
116
+ if (this.acadVersion === "AC1015") {
117
+ style.push("5", "3", "100", "AcDbSymbolTable");
118
+ }
119
+ style.push("0", "STYLE", "2", "STANDARD", "70", "0", "40", "0.0", "41", "1.0", "50", "0.0", "71", "0", "42", "0.2", "3", "txt", "4", "");
120
+ if (this.acadVersion === "AC1015") {
121
+ style.splice(style.indexOf("STYLE") + 1, 0, "5", "11", "100", "AcDbSymbolTableRecord", "100", "AcDbTextStyleTableRecord");
122
+ }
123
+ style.push("0", "ENDTAB");
124
+ return style;
125
+ }
126
+ /**
127
+ * Generate VPORT table (viewport configuration)
128
+ */
129
+ generateVportTable() {
130
+ return [
131
+ "0",
132
+ "TABLE",
133
+ "2",
134
+ "VPORT",
135
+ "70",
136
+ "2",
137
+ "0",
138
+ "VPORT",
139
+ "2",
140
+ "*ACTIVE",
141
+ "70",
142
+ "0",
143
+ "10",
144
+ "0.0",
145
+ "20",
146
+ "0.0",
147
+ "11",
148
+ "1.0",
149
+ "21",
150
+ "1.0",
151
+ "12",
152
+ "15.0",
153
+ "22",
154
+ "11.101231",
155
+ "13",
156
+ "0.0",
157
+ "23",
158
+ "0.0",
159
+ "14",
160
+ "0.1",
161
+ "24",
162
+ "0.1",
163
+ "15",
164
+ "0.5",
165
+ "25",
166
+ "0.5",
167
+ "16",
168
+ "0.0",
169
+ "26",
170
+ "0.0",
171
+ "36",
172
+ "1.0",
173
+ "17",
174
+ "0.0",
175
+ "27",
176
+ "0.0",
177
+ "37",
178
+ "0.0",
179
+ "40",
180
+ "22.202462",
181
+ "41",
182
+ "1.351201",
183
+ "42",
184
+ "50.0",
185
+ "43",
186
+ "0.0",
187
+ "44",
188
+ "0.0",
189
+ "50",
190
+ "0.0",
191
+ "51",
192
+ "0.0",
193
+ "71",
194
+ "0",
195
+ "72",
196
+ "100",
197
+ "73",
198
+ "1",
199
+ "74",
200
+ "1",
201
+ "75",
202
+ "1",
203
+ "76",
204
+ "0",
205
+ "77",
206
+ "0",
207
+ "78",
208
+ "0",
209
+ "0",
210
+ "ENDTAB"
211
+ ];
212
+ }
213
+ /**
214
+ * Generate VIEW table (empty but required for AC1009)
215
+ */
216
+ generateViewTable() {
217
+ return [
218
+ "0",
219
+ "TABLE",
220
+ "2",
221
+ "VIEW",
222
+ "70",
223
+ "0",
224
+ "0",
225
+ "ENDTAB"
226
+ ];
227
+ }
228
+ /**
229
+ * Generate UCS table (user coordinate system - empty but required for AC1009)
230
+ */
231
+ generateUcsTable() {
232
+ return [
233
+ "0",
234
+ "TABLE",
235
+ "2",
236
+ "UCS",
237
+ "70",
238
+ "0",
239
+ "0",
240
+ "ENDTAB"
241
+ ];
242
+ }
243
+ /**
244
+ * Generate APPID table (application ID - required for AC1009)
245
+ */
246
+ generateAppidTable() {
247
+ return [
248
+ "0",
249
+ "TABLE",
250
+ "2",
251
+ "APPID",
252
+ "70",
253
+ "1",
254
+ "0",
255
+ "APPID",
256
+ "2",
257
+ "ACAD",
258
+ "70",
259
+ "64",
260
+ "0",
261
+ "ENDTAB"
262
+ ];
263
+ }
264
+ /**
265
+ * Generate DIMSTYLE table (dimension style - empty but required for AC1009)
266
+ */
267
+ generateDimstyleTable() {
268
+ return [
269
+ "0",
270
+ "TABLE",
271
+ "2",
272
+ "DIMSTYLE",
273
+ "70",
274
+ "0",
275
+ "0",
276
+ "ENDTAB"
277
+ ];
278
+ }
279
+ /**
280
+ * Generate blocks section (empty but required)
281
+ */
282
+ generateBlocks() {
283
+ return [
284
+ "0",
285
+ "SECTION",
286
+ "2",
287
+ "BLOCKS",
288
+ "0",
289
+ "ENDSEC"
290
+ ];
291
+ }
64
292
  /**
65
293
  * Generate layer table based on unique layers in all parts
66
294
  */
@@ -83,18 +311,22 @@ export class DxfGenerator {
83
311
  "TABLE",
84
312
  "2",
85
313
  "LAYER",
86
- "5",
87
- "2",
88
- "100",
89
- "AcDbSymbolTable",
90
314
  "70",
91
315
  layers.size.toString()
92
316
  ];
317
+ if (this.acadVersion === "AC1015") {
318
+ layerTable.splice(4, 0, "5", "2", "100", "AcDbSymbolTable");
319
+ }
93
320
  // Generate layer entries
94
321
  layers.forEach(layerName => {
95
- layerTable.push("0", "LAYER", "5", this.getNextHandle(), "100", "AcDbSymbolTableRecord", "100", "AcDbLayerTableRecord", "2", layerName, "70", "0", "62", "7", // Default color (white)
322
+ layerTable.push("0", "LAYER", "2", layerName, "70", "0", "62", "7", // Default color (white)
96
323
  "6", "CONTINUOUS" // Line type
97
324
  );
325
+ // Add AC1015-specific subclass markers
326
+ if (this.acadVersion === "AC1015") {
327
+ const insertIdx = layerTable.lastIndexOf("LAYER") + 1;
328
+ layerTable.splice(insertIdx, 0, "5", this.getNextHandle(), "100", "AcDbSymbolTableRecord", "100", "AcDbLayerTableRecord");
329
+ }
98
330
  });
99
331
  layerTable.push("0", "ENDTAB");
100
332
  return layerTable;
@@ -184,21 +416,23 @@ export class DxfGenerator {
184
416
  const entity = [
185
417
  "0",
186
418
  "LINE",
187
- "5",
188
- this.getNextHandle(),
189
- "100",
190
- "AcDbEntity"
419
+ "8",
420
+ part.layer || "0"
191
421
  ];
192
- // Add layer
193
- entity.push("8", part.layer || "0");
194
422
  // Add color if specified
195
423
  if (part.color !== undefined) {
196
424
  const colorCodes = this.convertColorToDxf(part.color);
197
425
  colorCodes.forEach(cc => entity.push(cc.code, cc.value));
198
426
  }
199
- entity.push("100", "AcDbLine", "10", line.start[0].toString(), "20", line.start[1].toString(), "30", "0", // Z coordinate (2D)
200
- "11", line.end[0].toString(), "21", line.end[1].toString(), "31", "0" // Z coordinate (2D)
427
+ entity.push("10", line.start[0].toFixed(6), "20", line.start[1].toFixed(6), "30", "0.00", // Z coordinate (2D)
428
+ "11", line.end[0].toFixed(6), "21", line.end[1].toFixed(6), "31", "0.00" // Z coordinate (2D)
201
429
  );
430
+ // Add AC1015-specific codes
431
+ if (this.acadVersion === "AC1015") {
432
+ entity.splice(2, 0, "5", this.getNextHandle(), "100", "AcDbEntity");
433
+ const coordIdx = entity.indexOf("10");
434
+ entity.splice(coordIdx, 0, "100", "AcDbLine");
435
+ }
202
436
  return entity;
203
437
  }
204
438
  /**
@@ -208,20 +442,21 @@ export class DxfGenerator {
208
442
  const entity = [
209
443
  "0",
210
444
  "CIRCLE",
211
- "5",
212
- this.getNextHandle(),
213
- "100",
214
- "AcDbEntity"
445
+ "8",
446
+ part.layer || "0"
215
447
  ];
216
- // Add layer
217
- entity.push("8", part.layer || "0");
218
448
  // Add color if specified
219
449
  if (part.color !== undefined) {
220
450
  const colorCodes = this.convertColorToDxf(part.color);
221
451
  colorCodes.forEach(cc => entity.push(cc.code, cc.value));
222
452
  }
223
- entity.push("100", "AcDbCircle", "10", circle.center[0].toString(), "20", circle.center[1].toString(), "30", "0", // Z coordinate (2D)
224
- "40", circle.radius.toString());
453
+ entity.push("10", circle.center[0].toFixed(6), "20", circle.center[1].toFixed(6), "30", "0.00", "40", circle.radius.toFixed(6));
454
+ // Add AC1015-specific codes
455
+ if (this.acadVersion === "AC1015") {
456
+ entity.splice(2, 0, "5", this.getNextHandle(), "100", "AcDbEntity");
457
+ const coordIdx = entity.indexOf("10");
458
+ entity.splice(coordIdx, 0, "100", "AcDbCircle");
459
+ }
225
460
  return entity;
226
461
  }
227
462
  /**
@@ -231,20 +466,27 @@ export class DxfGenerator {
231
466
  const entity = [
232
467
  "0",
233
468
  "ARC",
234
- "5",
235
- this.getNextHandle(),
236
- "100",
237
- "AcDbEntity"
469
+ "8",
470
+ part.layer || "0"
238
471
  ];
239
- // Add layer
240
- entity.push("8", part.layer || "0");
472
+ // Add line type for AC1009 (optional empty)
473
+ if (this.acadVersion === "AC1009") {
474
+ entity.push("6", " ");
475
+ }
241
476
  // Add color if specified
242
477
  if (part.color !== undefined) {
243
478
  const colorCodes = this.convertColorToDxf(part.color);
244
479
  colorCodes.forEach(cc => entity.push(cc.code, cc.value));
245
480
  }
246
- entity.push("100", "AcDbCircle", "10", arc.center[0].toString(), "20", arc.center[1].toString(), "30", "0", // Z coordinate (2D)
247
- "40", arc.radius.toString(), "100", "AcDbArc", "50", arc.startAngle.toString(), "51", arc.endAngle.toString());
481
+ entity.push("10", arc.center[0].toFixed(6), "20", arc.center[1].toFixed(6), "30", this.acadVersion === "AC1009" ? "" : "0.0", "40", arc.radius.toFixed(6), "50", arc.startAngle.toFixed(6), "51", arc.endAngle.toFixed(6));
482
+ // Add AC1015-specific codes
483
+ if (this.acadVersion === "AC1015") {
484
+ entity.splice(2, 0, "5", this.getNextHandle(), "100", "AcDbEntity");
485
+ const coordIdx = entity.indexOf("10");
486
+ entity.splice(coordIdx, 0, "100", "AcDbCircle");
487
+ const angleIdx = entity.indexOf("50");
488
+ entity.splice(angleIdx, 0, "100", "AcDbArc");
489
+ }
248
490
  return entity;
249
491
  }
250
492
  /**
@@ -254,28 +496,30 @@ export class DxfGenerator {
254
496
  const entity = [
255
497
  "0",
256
498
  "LWPOLYLINE",
257
- "5",
258
- this.getNextHandle(),
259
- "100",
260
- "AcDbEntity"
499
+ "8",
500
+ part.layer || "0"
261
501
  ];
262
- // Add layer
263
- entity.push("8", part.layer || "0");
264
502
  // Add color if specified
265
503
  if (part.color !== undefined) {
266
504
  const colorCodes = this.convertColorToDxf(part.color);
267
505
  colorCodes.forEach(cc => entity.push(cc.code, cc.value));
268
506
  }
269
507
  const isClosed = polyline.closed || (polyline.points.length > 2 && this.isClosedPolyline(polyline.points));
270
- entity.push("100", "AcDbPolyline", "90", polyline.points.length.toString(), "70", isClosed ? "1" : "0");
508
+ entity.push("90", polyline.points.length.toString(), "70", isClosed ? "1" : "0");
509
+ // Add AC1015-specific codes
510
+ if (this.acadVersion === "AC1015") {
511
+ entity.splice(2, 0, "5", this.getNextHandle(), "100", "AcDbEntity");
512
+ const pointIdx = entity.indexOf("90");
513
+ entity.splice(pointIdx, 0, "100", "AcDbPolyline");
514
+ }
271
515
  // Add vertices
272
516
  polyline.points.forEach((point, index) => {
273
- entity.push("10", point[0].toString(), "20", point[1].toString());
517
+ entity.push("10", point[0].toFixed(6), "20", point[1].toFixed(6));
274
518
  // Add bulge value if specified (for arc segments)
275
519
  if (polyline.bulges && polyline.bulges.length > index) {
276
520
  const bulge = polyline.bulges[index];
277
521
  if (bulge !== 0) {
278
- entity.push("42", bulge.toString());
522
+ entity.push("42", bulge.toFixed(6));
279
523
  }
280
524
  }
281
525
  });
@@ -288,13 +532,9 @@ export class DxfGenerator {
288
532
  const entity = [
289
533
  "0",
290
534
  "SPLINE",
291
- "5",
292
- this.getNextHandle(),
293
- "100",
294
- "AcDbEntity"
535
+ "8",
536
+ part.layer || "0"
295
537
  ];
296
- // Add layer
297
- entity.push("8", part.layer || "0");
298
538
  // Add color if specified
299
539
  if (part.color !== undefined) {
300
540
  const colorCodes = this.convertColorToDxf(part.color);
@@ -304,17 +544,23 @@ export class DxfGenerator {
304
544
  const numControlPoints = spline.controlPoints.length;
305
545
  const numKnots = numControlPoints + degree + 1;
306
546
  // Spline flags: 1 = closed, 2 = periodic, 4 = rational, 8 = planar, 16 = linear
307
- const flags = spline.closed ? 1 : 0;
308
- entity.push("100", "AcDbSpline", "210", "0", "220", "0", "230", "1", // Normal vector (Z-axis for 2D)
547
+ const flags = spline.closed ? 9 : 8; // Add planar flag (8) for 2D splines
548
+ entity.push("210", "0.0", "220", "0.0", "230", "1.0", // Normal vector (Z-axis for 2D)
309
549
  "70", flags.toString(), "71", degree.toString(), "72", numKnots.toString(), "73", numControlPoints.toString(), "74", "0" // Number of fit points (we're using control points)
310
550
  );
551
+ // Add AC1015-specific codes
552
+ if (this.acadVersion === "AC1015") {
553
+ entity.splice(2, 0, "5", this.getNextHandle(), "100", "AcDbEntity");
554
+ const normalIdx = entity.indexOf("210");
555
+ entity.splice(normalIdx, 0, "100", "AcDbSpline");
556
+ }
311
557
  // Generate knot values (uniform knot vector)
312
558
  for (let i = 0; i < numKnots; i++) {
313
- entity.push("40", i.toString());
559
+ entity.push("40", i.toFixed(6));
314
560
  }
315
561
  // Add control points
316
562
  spline.controlPoints.forEach(point => {
317
- entity.push("10", point[0].toString(), "20", point[1].toString(), "30", "0" // Z coordinate (2D)
563
+ entity.push("10", point[0].toFixed(6), "20", point[1].toFixed(6), "30", "0.0" // Z coordinate (2D)
318
564
  );
319
565
  });
320
566
  return entity;
@@ -339,7 +585,7 @@ export class DxfGenerator {
339
585
  /**
340
586
  * Convert color to DXF format
341
587
  * Accepts hex color (#RRGGBB) or ACI color index (1-255)
342
- * Returns appropriate DXF color codes
588
+ * Returns appropriate DXF color codes based on colorFormat setting
343
589
  */
344
590
  convertColorToDxf(color) {
345
591
  // If it's already a number (ACI index), use it directly
@@ -349,23 +595,64 @@ export class DxfGenerator {
349
595
  return [{ code: "62", value: color }];
350
596
  }
351
597
  }
352
- // If it's a hex color, convert to true color (24-bit RGB)
598
+ // If it's a hex color, handle based on format preference
353
599
  if (color.startsWith("#")) {
354
600
  const hex = color.substring(1);
355
601
  if (hex.length === 6) {
356
602
  const r = parseInt(hex.substring(0, 2), 16);
357
603
  const g = parseInt(hex.substring(2, 4), 16);
358
604
  const b = parseInt(hex.substring(4, 6), 16);
359
- // True color value = (R * 65536) + (G * 256) + B
360
- const trueColor = (r * 65536) + (g * 256) + b;
361
- // Use group code 420 for true color (24-bit)
362
- return [
363
- { code: "62", value: "256" },
364
- { code: "420", value: trueColor.toString() }
365
- ];
605
+ if (this.colorFormat === "truecolor") {
606
+ // Use 24-bit true color for full color spectrum (newer CAD software)
607
+ const trueColor = (r * 65536) + (g * 256) + b;
608
+ return [
609
+ { code: "62", value: "256" },
610
+ { code: "420", value: trueColor.toString() }
611
+ ];
612
+ }
613
+ else {
614
+ // Use ACI color index for better compatibility (older CAD software)
615
+ const aciIndex = this.rgbToAciColorIndex(r, g, b);
616
+ return [{ code: "62", value: aciIndex.toString() }];
617
+ }
366
618
  }
367
619
  }
368
620
  // Default to white (7) if color can't be parsed
369
621
  return [{ code: "62", value: "7" }];
370
622
  }
623
+ /**
624
+ * Convert RGB values to nearest AutoCAD Color Index (ACI)
625
+ * Uses a simplified mapping to standard ACI colors
626
+ */
627
+ rgbToAciColorIndex(r, g, b) {
628
+ // ACI standard colors (simplified mapping)
629
+ const aciColors = {
630
+ 1: [255, 0, 0],
631
+ 2: [255, 255, 0],
632
+ 3: [0, 255, 0],
633
+ 4: [0, 255, 255],
634
+ 5: [0, 0, 255],
635
+ 6: [255, 0, 255],
636
+ 7: [255, 255, 255],
637
+ 8: [128, 128, 128],
638
+ 9: [192, 192, 192] // Light gray
639
+ };
640
+ // Special case for black or very dark colors
641
+ if (r < 30 && g < 30 && b < 30) {
642
+ return 7; // Use white for visibility on dark backgrounds
643
+ }
644
+ // Find nearest color
645
+ let nearestIndex = 7;
646
+ let minDistance = Infinity;
647
+ for (const [index, [cr, cg, cb]] of Object.entries(aciColors)) {
648
+ const distance = Math.sqrt(Math.pow(r - cr, 2) +
649
+ Math.pow(g - cg, 2) +
650
+ Math.pow(b - cb, 2));
651
+ if (distance < minDistance) {
652
+ minDistance = distance;
653
+ nearestIndex = parseInt(index);
654
+ }
655
+ }
656
+ return nearestIndex;
657
+ }
371
658
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitbybit-dev/base",
3
- "version": "0.20.11",
3
+ "version": "0.20.12",
4
4
  "description": "Bit By Bit Developers Base CAD Library to Program Geometry",
5
5
  "main": "index.js",
6
6
  "repository": {