@design-core/core 0.0.7 → 51.1.0

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 (117) hide show
  1. package/.github/workflows/DesignCoreQA.yml +3 -0
  2. package/core/designCore.js +1 -1
  3. package/core/dimensions/alignedDimension.js +7 -7
  4. package/core/dimensions/angularDimension.js +32 -32
  5. package/core/dimensions/{baseCircularDimension.js → circularDimensionBase.js} +19 -19
  6. package/core/dimensions/diametricDimension.js +10 -10
  7. package/core/dimensions/dimension.js +42 -42
  8. package/core/dimensions/{baseDimension.js → dimensionBase.js} +17 -17
  9. package/core/dimensions/{baseLinearDimension.js → linearDimensionBase.js} +9 -9
  10. package/core/dimensions/radialDimension.js +8 -8
  11. package/core/dimensions/rotatedDimension.js +8 -8
  12. package/core/entities/arc.js +22 -22
  13. package/core/entities/arctext.js +13 -13
  14. package/core/entities/circle.js +7 -7
  15. package/core/entities/hatch.js +210 -40
  16. package/core/entities/insert.js +11 -6
  17. package/core/entities/point.js +19 -19
  18. package/core/entities/polyline.js +3 -3
  19. package/core/entities/{basePolyline.js → polylineBase.js} +18 -18
  20. package/core/entities/text.js +4 -4
  21. package/core/lib/boundingBox.js +11 -11
  22. package/core/lib/canvas.js +13 -6
  23. package/core/lib/clipboard.js +2 -2
  24. package/core/lib/dxf/dxf.js +11 -11
  25. package/core/lib/dxf/dxfIterator.js +2 -2
  26. package/core/lib/entityManager.js +19 -19
  27. package/core/lib/inputManager.js +1 -1
  28. package/core/lib/matrix.js +1 -1
  29. package/core/lib/patterns.js +1 -1
  30. package/core/lib/polylineUtils.js +9 -9
  31. package/core/lib/renderers/cairoRenderer.js +5 -5
  32. package/core/lib/renderers/canvasRenderer.js +4 -4
  33. package/core/lib/renderers/pdfRenderer.js +7 -7
  34. package/core/lib/renderers/rendererBase.js +1 -1
  35. package/core/lib/scene.js +1 -1
  36. package/core/lib/selectionManager.js +18 -18
  37. package/core/lib/utils.js +5 -5
  38. package/core/properties/entityProperties.js +2 -1
  39. package/core/properties/flags.js +12 -0
  40. package/core/properties/property.js +8 -3
  41. package/core/properties/propertyManager.js +52 -37
  42. package/core/tables/block.js +50 -46
  43. package/core/tables/dimStyle.js +5 -5
  44. package/core/tables/ltypeManager.js +1 -1
  45. package/core/tables/vport.js +2 -2
  46. package/core/tools/chamfer.js +6 -6
  47. package/core/tools/chamferFilletBase.js +4 -4
  48. package/core/tools/copy.js +8 -8
  49. package/core/tools/copybase.js +3 -3
  50. package/core/tools/copyclip.js +3 -3
  51. package/core/tools/cornerEntity.js +2 -2
  52. package/core/tools/cutclip.js +3 -3
  53. package/core/tools/explode.js +6 -6
  54. package/core/tools/extend.js +13 -13
  55. package/core/tools/fillet.js +6 -6
  56. package/core/tools/matchProp.js +1 -1
  57. package/core/tools/mirror.js +11 -11
  58. package/core/tools/move.js +5 -5
  59. package/core/tools/offset.js +29 -29
  60. package/core/tools/purge.js +10 -10
  61. package/core/tools/rotate.js +16 -16
  62. package/core/tools/scale.js +6 -6
  63. package/core/tools/trim.js +15 -15
  64. package/cspell.json +323 -0
  65. package/package.json +1 -1
  66. package/test/dimensions/alignedDimension.test.js +3 -3
  67. package/test/dimensions/angularDimension.test.js +7 -7
  68. package/test/dimensions/diametricDimension.test.js +9 -9
  69. package/test/dimensions/dimension.test.js +12 -12
  70. package/test/dimensions/{baseDimension.test.js → dimensionBase.test.js} +12 -12
  71. package/test/dimensions/{baseLinearDimension.test.js → linearDimensionBase.test.js} +7 -7
  72. package/test/dimensions/radialDimension.test.js +9 -9
  73. package/test/dimensions/rotatedDimension.test.js +4 -4
  74. package/test/entities/arc.test.js +10 -10
  75. package/test/entities/arctext.test.js +6 -6
  76. package/test/entities/circle.test.js +18 -18
  77. package/test/entities/hatch.test.js +362 -39
  78. package/test/entities/insert.test.js +9 -9
  79. package/test/entities/point.test.js +3 -3
  80. package/test/entities/{basePolyline.test.js → polylineBase.test.js} +131 -62
  81. package/test/entities/text.test.js +19 -19
  82. package/test/integration/exportIntegration.test.js +3 -3
  83. package/test/integration/userInputIntegration.test.js +5 -5
  84. package/test/lib/boundingBox.test.js +3 -3
  85. package/test/lib/canvas.test.js +9 -9
  86. package/test/lib/clipboard.test.js +73 -0
  87. package/test/lib/inputManager.test.js +4 -4
  88. package/test/lib/scene.test.js +9 -9
  89. package/test/lib/selectionManager.test.js +3 -3
  90. package/test/lib/snapping.test.js +1 -1
  91. package/test/properties/flags.test.js +24 -0
  92. package/test/properties/propertyManager.test.js +93 -22
  93. package/test/renderers/pdfRenderer.test.js +2 -2
  94. package/test/tables/block.test.js +63 -14
  95. package/test/tables/layerManager.test.js +2 -2
  96. package/test/test-helpers/hatchGridRenderer.js +3 -3
  97. package/test/test-helpers/test-helpers.js +6 -6
  98. package/test/tools/chamfer.test.js +60 -60
  99. package/test/tools/chamferFilletBase.test.js +36 -36
  100. package/test/tools/copy.test.js +6 -6
  101. package/test/tools/copybase.test.js +2 -2
  102. package/test/tools/copyclip.test.js +2 -2
  103. package/test/tools/cornerEntity.test.js +8 -8
  104. package/test/tools/cutclip.test.js +2 -2
  105. package/test/tools/erase.test.js +6 -6
  106. package/test/tools/explode.test.js +2 -2
  107. package/test/tools/extend.test.js +84 -84
  108. package/test/tools/fillet.test.js +62 -62
  109. package/test/tools/matchProp.test.js +6 -6
  110. package/test/tools/mirror.test.js +26 -26
  111. package/test/tools/move.test.js +7 -7
  112. package/test/tools/offset.test.js +65 -65
  113. package/test/tools/purge.test.js +4 -4
  114. package/test/tools/rotate.test.js +10 -10
  115. package/test/tools/scale.test.js +28 -28
  116. package/test/tools/trim.test.js +109 -109
  117. package/test/tools/zoom.test.js +15 -17
@@ -91,7 +91,7 @@ test('Test LayerManager.checkStyles', () => {
91
91
  layer: newItemName,
92
92
  };
93
93
 
94
- core.scene.addItem('Line', data);
94
+ core.scene.addEntity('Line', data);
95
95
 
96
96
  layerManager.checkStyles();
97
97
  const layers = layerManager.getItems();
@@ -115,7 +115,7 @@ test('Test LayerManager.checkItems', () => {
115
115
  layer: newItemName,
116
116
  };
117
117
 
118
- core.scene.addItem('Line', data);
118
+ core.scene.addEntity('Line', data);
119
119
 
120
120
  layerManager.checkItems();
121
121
  const layers = layerManager.getItems();
@@ -15,7 +15,7 @@
15
15
 
16
16
  import { Core } from '../../core/core/core.js';
17
17
  import { Hatch } from '../../core/entities/hatch.js';
18
- import { BasePolyline } from '../../core/entities/basePolyline.js';
18
+ import { PolylineBase } from '../../core/entities/polylineBase.js';
19
19
  import { Point } from '../../core/entities/point.js';
20
20
  import { Text } from '../../core/entities/text.js';
21
21
 
@@ -136,7 +136,7 @@ export function buildHatchGrid(renderer) {
136
136
  let outlinePoints;
137
137
 
138
138
  if (i % 2 === 0) {
139
- hatchBoundary = new BasePolyline({ points: [
139
+ hatchBoundary = new PolylineBase({ points: [
140
140
  new Point(cx - SHAPE_R, cy - SHAPE_R),
141
141
  new Point(cx + SHAPE_R, cy - SHAPE_R),
142
142
  new Point(cx + SHAPE_R, cy + SHAPE_R),
@@ -145,7 +145,7 @@ export function buildHatchGrid(renderer) {
145
145
  outlinePoints = hatchBoundary.toPolylinePoints();
146
146
  } else {
147
147
  // Two exact semicircle arcs (bulge = 1) for clipping; polygon for visible outline
148
- hatchBoundary = new BasePolyline({ points: [
148
+ hatchBoundary = new PolylineBase({ points: [
149
149
  new Point(cx + SHAPE_R, cy, 1),
150
150
  new Point(cx - SHAPE_R, cy, 1),
151
151
  ] });
@@ -27,10 +27,10 @@ export class File {
27
27
  * @param {Function} testFn - async function to run with the mock active
28
28
  * @param {object} [options] - optional configuration
29
29
  * @param {object} [options.extraMethods] - additional methods to add to the mock inputManager
30
- * @param {Array} [options.selectedItems] - sequential values returned by entities.get
30
+ * @param {Array} [options.selectedEntities] - sequential values returned by entities.get
31
31
  */
32
32
  export async function withMockInput(scene, inputs, testFn, options = {}) {
33
- const { extraMethods = {}, selectedItems } = options;
33
+ const { extraMethods = {}, selectedEntities } = options;
34
34
  const origInputManager = scene.inputManager;
35
35
  let callCount = 0;
36
36
 
@@ -47,11 +47,11 @@ export async function withMockInput(scene, inputs, testFn, options = {}) {
47
47
  };
48
48
 
49
49
  let origGetItem;
50
- if (selectedItems) {
50
+ if (selectedEntities) {
51
51
  origGetItem = scene.entities.get;
52
- let selectedItemsCallCount = 0;
52
+ let selectedEntitiesCallCount = 0;
53
53
  scene.entities.get = () => {
54
- return selectedItems[selectedItemsCallCount++];
54
+ return selectedEntities[selectedEntitiesCallCount++];
55
55
  };
56
56
  }
57
57
 
@@ -59,7 +59,7 @@ export async function withMockInput(scene, inputs, testFn, options = {}) {
59
59
  await testFn();
60
60
  } finally {
61
61
  scene.inputManager = origInputManager;
62
- if (selectedItems) {
62
+ if (selectedEntities) {
63
63
  scene.entities.get = origGetItem;
64
64
  }
65
65
  }
@@ -21,7 +21,7 @@ test('Chamfer.register returns correct command object', () => {
21
21
 
22
22
  test('Chamfer.action does nothing when entities are not set', () => {
23
23
  core.scene.clear();
24
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(10, 0)] });
24
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
25
25
  const countBefore = core.scene.entities.count();
26
26
 
27
27
  const chamfer = new Chamfer();
@@ -32,8 +32,8 @@ test('Chamfer.action does nothing when entities are not set', () => {
32
32
 
33
33
  test('Chamfer.action notifies when first entity type is not supported', () => {
34
34
  core.scene.clear();
35
- core.scene.addItem('Circle', { points: [new Point(0, 0), new Point(5, 0)] });
36
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(10, 0)] });
35
+ core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(5, 0)] });
36
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
37
37
 
38
38
  const notifySpy = jest.spyOn(core, 'notify');
39
39
 
@@ -50,8 +50,8 @@ test('Chamfer.action notifies when first entity type is not supported', () => {
50
50
 
51
51
  test('Chamfer.action notifies when second entity type is not supported', () => {
52
52
  core.scene.clear();
53
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(10, 0)] });
54
- core.scene.addItem('Circle', { points: [new Point(0, 0), new Point(5, 0)] });
53
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
54
+ core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(5, 0)] });
55
55
 
56
56
  const notifySpy = jest.spyOn(core, 'notify');
57
57
 
@@ -68,8 +68,8 @@ test('Chamfer.action notifies when second entity type is not supported', () => {
68
68
 
69
69
  test('Chamfer.action notifies for parallel lines', () => {
70
70
  core.scene.clear();
71
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(10, 0)] });
72
- core.scene.addItem('Line', { points: [new Point(0, 5), new Point(10, 5)] });
71
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(10, 0)] });
72
+ core.scene.addEntity('Line', { points: [new Point(0, 5), new Point(10, 5)] });
73
73
 
74
74
  const notifySpy = jest.spyOn(core, 'notify');
75
75
 
@@ -90,8 +90,8 @@ test('Chamfer.action dist=0 trimMode=true trims both lines to intersection', ()
90
90
  // Lines only touching when extended: horizontal (0,0)→(8,0), vertical (10,-10)→(10,-2)
91
91
  // Infinite extensions meet at (10, 0).
92
92
  core.scene.clear();
93
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(8, 0)] });
94
- core.scene.addItem('Line', { points: [new Point(10, -10), new Point(10, -2)] });
93
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(8, 0)] });
94
+ core.scene.addEntity('Line', { points: [new Point(10, -10), new Point(10, -2)] });
95
95
 
96
96
  core.scene.headers.chamferDistanceA = 0;
97
97
  core.scene.headers.chamferDistanceB = 0;
@@ -122,8 +122,8 @@ test('Chamfer.action dist=0 trimMode=true trims both lines to intersection', ()
122
122
 
123
123
  test('Chamfer.action dist=0 trimMode=false makes no changes', () => {
124
124
  core.scene.clear();
125
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(8, 0)] });
126
- core.scene.addItem('Line', { points: [new Point(10, -10), new Point(10, -2)] });
125
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(8, 0)] });
126
+ core.scene.addEntity('Line', { points: [new Point(10, -10), new Point(10, -2)] });
127
127
 
128
128
  core.scene.headers.chamferDistanceA = 0;
129
129
  core.scene.headers.chamferDistanceB = 0;
@@ -146,8 +146,8 @@ test('Chamfer.action distance method trimMode=true adds chamfer line and trims',
146
146
  // Perpendicular L-corner at origin: horizontal (-10,0)→(0,0), vertical (0,0)→(0,10)
147
147
  // Equal distances of 2 → chamfer endpoints at (-2,0) and (0,2)
148
148
  core.scene.clear();
149
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
150
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
149
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
150
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
151
151
 
152
152
  core.scene.headers.chamferDistanceA = 2;
153
153
  core.scene.headers.chamferDistanceB = 2;
@@ -191,8 +191,8 @@ test('Chamfer.action distance method trimMode=true adds chamfer line and trims',
191
191
  test('Chamfer.action distance method asymmetric distances', () => {
192
192
  // L-corner at origin, distA=3 along horizontal, distB=1 along vertical
193
193
  core.scene.clear();
194
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
195
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
194
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
195
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
196
196
 
197
197
  core.scene.headers.chamferDistanceA = 3;
198
198
  core.scene.headers.chamferDistanceB = 1;
@@ -216,8 +216,8 @@ test('Chamfer.action distance method asymmetric distances', () => {
216
216
 
217
217
  test('Chamfer.action distance method trimMode=false adds chamfer line only', () => {
218
218
  core.scene.clear();
219
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
220
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
219
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
220
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
221
221
 
222
222
  core.scene.headers.chamferDistanceA = 2;
223
223
  core.scene.headers.chamferDistanceB = 2;
@@ -245,8 +245,8 @@ test('Chamfer.action distance method trimMode=false adds chamfer line only', ()
245
245
  test('Chamfer.action notifies when distance is too large for the segments', () => {
246
246
  // Lines only 5 units long from intersection — distance 10 won't fit
247
247
  core.scene.clear();
248
- core.scene.addItem('Line', { points: [new Point(-5, 0), new Point(0, 0)] });
249
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 5)] });
248
+ core.scene.addEntity('Line', { points: [new Point(-5, 0), new Point(0, 0)] });
249
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 5)] });
250
250
 
251
251
  core.scene.headers.chamferDistanceA = 10;
252
252
  core.scene.headers.chamferDistanceB = 10;
@@ -273,8 +273,8 @@ test('Chamfer.action angle method 45° on perpendicular lines matches distance m
273
273
  // With perpendicular lines and 45°, the chamfer endpoint on line2 should also be 2 units
274
274
  // from the intersection — matching a symmetric distance chamfer.
275
275
  core.scene.clear();
276
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
277
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
276
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
277
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
278
278
 
279
279
  core.scene.headers.chamferLength = 2;
280
280
  core.scene.headers.chamferAngle = 45; // degrees
@@ -307,8 +307,8 @@ test('Chamfer.action notifies when click coincides with intersection', () => {
307
307
  // L-corner at origin. Clicking firstClickPoint exactly at (0,0) makes
308
308
  // firstClickDistance = 0, triggering the "Selected corner cannot be chamfered" guard.
309
309
  core.scene.clear();
310
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
311
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
310
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
311
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
312
312
 
313
313
  core.scene.headers.chamferDistanceA = 2;
314
314
  core.scene.headers.chamferDistanceB = 2;
@@ -333,8 +333,8 @@ test('Chamfer.action notifies when click coincides with intersection', () => {
333
333
 
334
334
  test('Chamfer.action angle method notifies INVALIDNUMBER when angle is zero', () => {
335
335
  core.scene.clear();
336
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
337
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
336
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
337
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
338
338
 
339
339
  core.scene.headers.chamferLength = 2;
340
340
  core.scene.headers.chamferAngle = 0; // alpha = 0 * π/180 = 0, fails alpha <= 0 guard
@@ -362,8 +362,8 @@ test('Chamfer.action angle method notifies PARALLELLINES when chamfer direction
362
362
  // candidate1 = rotate(-1,0) by +π/2 = (0,-1); dot with secondClickUnit (0,1) = -1 < 0.
363
363
  // candidate2 = rotate(-1,0) by -π/2 = (0, 1) → parallel to secondLineDirection (0,1) → cross = 0.
364
364
  core.scene.clear();
365
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
366
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
365
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
366
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
367
367
 
368
368
  core.scene.headers.chamferLength = 2;
369
369
  core.scene.headers.chamferAngle = 90; // degrees
@@ -397,8 +397,8 @@ test('Chamfer.execute returns early when first input is undefined', async () =>
397
397
 
398
398
  test('Chamfer.execute selects two lines and calls executeCommand', async () => {
399
399
  core.scene.clear();
400
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
401
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
400
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
401
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
402
402
 
403
403
  const executeCommandSpy = jest.fn();
404
404
 
@@ -544,7 +544,7 @@ test('Chamfer.execute sets chamferMode to true via Method=Angle option', async (
544
544
 
545
545
  test('Chamfer.execute re-prompts and notifies when first selected entity is not a Line', async () => {
546
546
  core.scene.clear();
547
- core.scene.addItem('Circle', { points: [new Point(0, 0), new Point(5, 0)] });
547
+ core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(5, 0)] });
548
548
 
549
549
  const notifySpy = jest.spyOn(core, 'notify');
550
550
 
@@ -563,8 +563,8 @@ test('Chamfer.execute re-prompts and notifies when first selected entity is not
563
563
 
564
564
  test('Chamfer.execute re-prompts and notifies when second selected entity is not a Line', async () => {
565
565
  core.scene.clear();
566
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(10, 0)] });
567
- core.scene.addItem('Circle', { points: [new Point(0, 0), new Point(5, 0)] });
566
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(10, 0)] });
567
+ core.scene.addEntity('Circle', { points: [new Point(0, 0), new Point(5, 0)] });
568
568
 
569
569
  const notifySpy = jest.spyOn(core, 'notify');
570
570
 
@@ -594,8 +594,8 @@ test('Chamfer.execute re-prompts and notifies when second selected entity is not
594
594
  test('Chamfer.action dist>0 trimMode=true Line first + Lwpolyline second keepStart: chamfer embedded in polyline', () => {
595
595
  // Click polyline near (-15,0) → segment 1. keepStart keeps the start portion.
596
596
  core.scene.clear();
597
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
598
- core.scene.addItem('Lwpolyline', { points: [new Point(-20, 0), new Point(-10, 0), new Point(0, 0), new Point(10, 0)] });
597
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
598
+ core.scene.addEntity('Lwpolyline', { points: [new Point(-20, 0), new Point(-10, 0), new Point(0, 0), new Point(10, 0)] });
599
599
 
600
600
  core.scene.headers.chamferDistanceA = 2;
601
601
  core.scene.headers.chamferDistanceB = 2;
@@ -635,8 +635,8 @@ test('Chamfer.action dist>0 trimMode=true Line first + Lwpolyline second keepSta
635
635
 
636
636
  test('Chamfer.action dist>0 trimMode=true Lwpolyline first + Line second keepStart: same result with entities reversed', () => {
637
637
  core.scene.clear();
638
- core.scene.addItem('Lwpolyline', { points: [new Point(-20, 0), new Point(-10, 0), new Point(0, 0), new Point(10, 0)] });
639
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
638
+ core.scene.addEntity('Lwpolyline', { points: [new Point(-20, 0), new Point(-10, 0), new Point(0, 0), new Point(10, 0)] });
639
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
640
640
 
641
641
  core.scene.headers.chamferDistanceA = 2;
642
642
  core.scene.headers.chamferDistanceB = 2;
@@ -676,8 +676,8 @@ test('Chamfer.action dist>0 trimMode=true Line + Lwpolyline keepEnd: keeps end p
676
676
  // Click polyline near (8,0) → segment 3 (right of intersection). keepEnd.
677
677
  // polyChamfer = (2,0), lineChamfer = (0,2).
678
678
  core.scene.clear();
679
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
680
- core.scene.addItem('Lwpolyline', { points: [new Point(-20, 0), new Point(-10, 0), new Point(0, 0), new Point(10, 0)] });
679
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
680
+ core.scene.addEntity('Lwpolyline', { points: [new Point(-20, 0), new Point(-10, 0), new Point(0, 0), new Point(10, 0)] });
681
681
 
682
682
  core.scene.headers.chamferDistanceA = 2;
683
683
  core.scene.headers.chamferDistanceB = 2;
@@ -720,7 +720,7 @@ test('Chamfer.action dist>0 trimMode=true same Lwpolyline consecutive segments:
720
720
  // Segment 1: (-10,0)→(0,0), Segment 2: (0,0)→(0,10). Corner at (0,0).
721
721
  // dist=2 → chamfer at (-2,0) and (0,2).
722
722
  core.scene.clear();
723
- core.scene.addItem('Lwpolyline', { points: [new Point(-10, 0), new Point(0, 0), new Point(0, 10)] });
723
+ core.scene.addEntity('Lwpolyline', { points: [new Point(-10, 0), new Point(0, 0), new Point(0, 10)] });
724
724
 
725
725
  core.scene.headers.chamferDistanceA = 2;
726
726
  core.scene.headers.chamferDistanceB = 2;
@@ -763,7 +763,7 @@ test('Chamfer.action dist>0 trimMode=true same Lwpolyline open ends: separate ch
763
763
  // dist=2, clicks at (-3,0) and (1,3):
764
764
  // firstChamfer = (-1,0), secondChamfer = (1,2).
765
765
  core.scene.clear();
766
- core.scene.addItem('Lwpolyline', { points: [new Point(-5, 0), new Point(0, 0), new Point(1, 0), new Point(1, 5)] });
766
+ core.scene.addEntity('Lwpolyline', { points: [new Point(-5, 0), new Point(0, 0), new Point(1, 0), new Point(1, 5)] });
767
767
 
768
768
  core.scene.headers.chamferDistanceA = 2;
769
769
  core.scene.headers.chamferDistanceB = 2;
@@ -809,7 +809,7 @@ test('Chamfer.action dist>0 trimMode=true closed Lwpolyline seg3+closing-seg: co
809
809
  // Closing segment (idx=4) goes (0,10)→(0,0); seg 3 goes (10,10)→(0,10).
810
810
  // Corner at (0,10) — chamfer dist=2 trims to (2,10) on seg3 and (0,8) on closing seg.
811
811
  core.scene.clear();
812
- core.scene.addItem('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)] });
812
+ core.scene.addEntity('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)] });
813
813
  const polyEntity = core.scene.entities.get(0);
814
814
  polyEntity.flags.setFlagValue(1);
815
815
 
@@ -847,7 +847,7 @@ test('Chamfer.action dist>0 trimMode=true closed Lwpolyline closing-wrap (seg4+s
847
847
  // Bug: old code had no closed-poly guard, so closing-wrap was treated as open-ends.
848
848
  // Fix: closed poly must NOT enter the open-ends path → corner-splice at index 0.
849
849
  core.scene.clear();
850
- core.scene.addItem('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)] });
850
+ core.scene.addEntity('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)] });
851
851
  const polyEntity = core.scene.entities.get(0);
852
852
  polyEntity.flags.setFlagValue(1);
853
853
 
@@ -892,7 +892,7 @@ test('Chamfer.action dist>0 trimMode=true closed Lwpolyline closing-wrap (seg4+s
892
892
  test('Chamfer.action dist>0 trimMode=false closed Lwpolyline closing-wrap: standalone chamfer Line only', () => {
893
893
  // Same square, closed, trimMode=false. No polyline mutation; only chamfer Line added.
894
894
  core.scene.clear();
895
- core.scene.addItem('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)] });
895
+ core.scene.addEntity('Lwpolyline', { points: [new Point(0, 0), new Point(10, 0), new Point(10, 10), new Point(0, 10)] });
896
896
  const polyEntity = core.scene.entities.get(0);
897
897
  polyEntity.flags.setFlagValue(1);
898
898
 
@@ -922,7 +922,7 @@ test('Chamfer.action dist>0 trimMode=true open Lwpolyline seg1+lastIdx still tak
922
922
  // Open 4-point polyline (no flags). Seg 1 and seg 3 (lastIdx=3) → open-ends path still fires.
923
923
  // Regression guard: the closed-poly fix must not break the open-poly open-ends case.
924
924
  core.scene.clear();
925
- core.scene.addItem('Lwpolyline', { points: [new Point(-5, 0), new Point(0, 0), new Point(1, 0), new Point(1, 5)] });
925
+ core.scene.addEntity('Lwpolyline', { points: [new Point(-5, 0), new Point(0, 0), new Point(1, 0), new Point(1, 5)] });
926
926
  const polyEntity = core.scene.entities.get(0);
927
927
  // No flags set — open polyline
928
928
 
@@ -949,8 +949,8 @@ test('Chamfer.action dist>0 trimMode=true open Lwpolyline seg1+lastIdx still tak
949
949
 
950
950
  test('Chamfer.action dist>0 trimMode=false Line + Lwpolyline: standalone chamfer Line added, entities unchanged', () => {
951
951
  core.scene.clear();
952
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
953
- core.scene.addItem('Lwpolyline', { points: [new Point(-20, 0), new Point(-10, 0), new Point(0, 0), new Point(10, 0)] });
952
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
953
+ core.scene.addEntity('Lwpolyline', { points: [new Point(-20, 0), new Point(-10, 0), new Point(0, 0), new Point(10, 0)] });
954
954
 
955
955
  core.scene.headers.chamferDistanceA = 2;
956
956
  core.scene.headers.chamferDistanceB = 2;
@@ -984,8 +984,8 @@ test('Chamfer.action dist>0 trimMode=false Line + Lwpolyline: standalone chamfer
984
984
  test('Chamfer.action chamfer line inherits layer, lineWidth, lineType from first entity', () => {
985
985
  // Perpendicular L-corner at origin; first entity on a non-default layer.
986
986
  core.scene.clear();
987
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)], layer: 'walls', lineWidth: 5, lineType: 'DASHED' });
988
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
987
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)], layer: 'walls', lineWidth: 5, lineType: 'DASHED' });
988
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
989
989
 
990
990
  core.scene.headers.chamferDistanceA = 2;
991
991
  core.scene.headers.chamferDistanceB = 2;
@@ -1014,7 +1014,7 @@ test('Chamfer.preview does not throw', () => {
1014
1014
 
1015
1015
  test('Chamfer.preview returns early when findClosestItem returns undefined', () => {
1016
1016
  core.scene.clear();
1017
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1017
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1018
1018
  DesignCore.Scene.previewEntities.clear();
1019
1019
 
1020
1020
  const chamfer = new Chamfer();
@@ -1031,8 +1031,8 @@ test('Chamfer.preview returns early when findClosestItem returns undefined', ()
1031
1031
 
1032
1032
  test('Chamfer.preview adds chamfer line to previewEntities in no-trim mode', () => {
1033
1033
  core.scene.clear();
1034
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1035
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
1034
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1035
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
1036
1036
  DesignCore.Scene.previewEntities.clear();
1037
1037
 
1038
1038
  core.scene.headers.chamferDistanceA = 2;
@@ -1054,8 +1054,8 @@ test('Chamfer.preview adds chamfer line to previewEntities in no-trim mode', ()
1054
1054
 
1055
1055
  test('Chamfer.preview skips chamfer line in no-trim mode when distances are both 0 (sharp corner)', () => {
1056
1056
  core.scene.clear();
1057
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1058
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
1057
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1058
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
1059
1059
  DesignCore.Scene.previewEntities.clear();
1060
1060
 
1061
1061
  core.scene.headers.chamferDistanceA = 0;
@@ -1077,8 +1077,8 @@ test('Chamfer.preview skips chamfer line in no-trim mode when distances are both
1077
1077
 
1078
1078
  test('Chamfer.preview adds 5 entities to previewEntities in trim mode', () => {
1079
1079
  core.scene.clear();
1080
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1081
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
1080
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1081
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
1082
1082
  DesignCore.Scene.previewEntities.clear();
1083
1083
 
1084
1084
  core.scene.headers.chamferDistanceA = 2;
@@ -1101,8 +1101,8 @@ test('Chamfer.preview adds 5 entities to previewEntities in trim mode', () => {
1101
1101
 
1102
1102
  test('Chamfer.execute returns early when second-entity input is undefined (inner loop)', async () => {
1103
1103
  core.scene.clear();
1104
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1105
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
1104
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1105
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
1106
1106
 
1107
1107
  const executeCommandSpy = jest.fn();
1108
1108
  await withMockInput(
@@ -1121,7 +1121,7 @@ test('Chamfer.execute notifies NONCONSECUTIVESEGMENTS for non-adjacent polyline
1121
1121
  // 5-point polyline → 4 segments. Pick segment 1 (near -15,0) then segment 3 (near 5,0).
1122
1122
  // Neither consecutive nor open-ends → NONCONSECUTIVESEGMENTS, then undefined to exit.
1123
1123
  core.scene.clear();
1124
- core.scene.addItem('Lwpolyline', { points: [new Point(-20, 0), new Point(-10, 0), new Point(0, 0), new Point(10, 0), new Point(20, 0)] });
1124
+ core.scene.addEntity('Lwpolyline', { points: [new Point(-20, 0), new Point(-10, 0), new Point(0, 0), new Point(10, 0), new Point(20, 0)] });
1125
1125
 
1126
1126
  const notifySpy = jest.spyOn(core, 'notify');
1127
1127
  await withMockInput(
@@ -1169,8 +1169,8 @@ test('Chamfer.execute Trim→Trim keeps trimMode=true', async () => {
1169
1169
  test('Chamfer.action angle method angle=180 notifies INVALIDNUMBER', () => {
1170
1170
  // alpha = 180 * π/180 = π; checks alpha >= Math.PI → INVALIDNUMBER
1171
1171
  core.scene.clear();
1172
- core.scene.addItem('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1173
- core.scene.addItem('Line', { points: [new Point(0, 0), new Point(0, 10)] });
1172
+ core.scene.addEntity('Line', { points: [new Point(-10, 0), new Point(0, 0)] });
1173
+ core.scene.addEntity('Line', { points: [new Point(0, 0), new Point(0, 10)] });
1174
1174
 
1175
1175
  core.scene.headers.chamferLength = 2;
1176
1176
  core.scene.headers.chamferAngle = 180;