@design-core/core 0.0.6 → 50.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 (173) hide show
  1. package/.eslintrc.json +4 -0
  2. package/.github/workflows/DesignCoreQA.yml +3 -0
  3. package/TODO.md +49 -6
  4. package/core/core/core.js +0 -3
  5. package/core/designCore.js +1 -1
  6. package/core/dimensions/alignedDimension.js +12 -11
  7. package/core/dimensions/angularDimension.js +38 -37
  8. package/core/dimensions/{baseCircularDimension.js → circularDimensionBase.js} +22 -21
  9. package/core/dimensions/diametricDimension.js +14 -13
  10. package/core/dimensions/dimension.js +62 -55
  11. package/core/dimensions/{baseDimension.js → dimensionBase.js} +73 -107
  12. package/core/dimensions/{baseLinearDimension.js → linearDimensionBase.js} +15 -14
  13. package/core/dimensions/radialDimension.js +12 -11
  14. package/core/dimensions/rotatedDimension.js +20 -19
  15. package/core/entities/arc.js +123 -156
  16. package/core/entities/arctext.js +222 -184
  17. package/core/entities/circle.js +77 -99
  18. package/core/entities/entity.js +114 -93
  19. package/core/entities/hatch.js +346 -273
  20. package/core/entities/insert.js +68 -83
  21. package/core/entities/line.js +21 -142
  22. package/core/entities/lwpolyline.js +16 -11
  23. package/core/entities/point.js +19 -19
  24. package/core/entities/polyline.js +7 -7
  25. package/core/entities/{basePolyline.js → polylineBase.js} +47 -299
  26. package/core/entities/rectangle.js +3 -1
  27. package/core/entities/solid.js +6 -15
  28. package/core/entities/text.js +190 -201
  29. package/core/lib/auxiliary/rubberBand.js +32 -0
  30. package/core/lib/auxiliary/selectionWindow.js +63 -0
  31. package/core/lib/auxiliary/snapPoint.js +113 -0
  32. package/core/lib/auxiliary/trackingLine.js +76 -0
  33. package/core/lib/boundingBox.js +11 -11
  34. package/core/lib/canvas.js +232 -168
  35. package/core/lib/clipboard.js +9 -3
  36. package/core/lib/colour.js +16 -0
  37. package/core/lib/commandLine.js +1 -6
  38. package/core/lib/commandManager.js +18 -8
  39. package/core/lib/constants.js +28 -0
  40. package/core/lib/dxf/dxf.js +15 -14
  41. package/core/lib/dxf/dxfIterator.js +2 -2
  42. package/core/lib/entityManager.js +33 -26
  43. package/core/lib/inputManager.js +36 -12
  44. package/core/lib/intersect.js +25 -0
  45. package/core/lib/matrix.js +1 -1
  46. package/core/lib/patterns.js +9 -2
  47. package/core/lib/plotOptions.js +67 -0
  48. package/core/lib/polylineUtils.js +75 -0
  49. package/core/lib/renderers/cairoRenderer.js +371 -0
  50. package/core/lib/renderers/canvasRenderer.js +315 -0
  51. package/core/lib/renderers/pdfRenderer.js +366 -0
  52. package/core/lib/renderers/rendererBase.js +284 -0
  53. package/core/lib/renderers/svgRenderer.js +343 -0
  54. package/core/lib/scene.js +28 -6
  55. package/core/lib/selectionManager.js +20 -20
  56. package/core/lib/settings.js +4 -2
  57. package/core/lib/snapping.js +4 -191
  58. package/core/lib/stateManager.js +30 -1
  59. package/core/lib/utils.js +26 -7
  60. package/core/properties/entityProperties.js +104 -0
  61. package/core/properties/property.js +106 -2
  62. package/core/properties/propertyManager.js +60 -44
  63. package/core/tables/block.js +50 -81
  64. package/core/tables/dimStyle.js +5 -5
  65. package/core/tables/endblk.js +1 -1
  66. package/core/tables/layer.js +8 -0
  67. package/core/tables/ltypeManager.js +1 -1
  68. package/core/tables/styleManagerBase.js +3 -2
  69. package/core/tables/tableManagerBase.js +8 -3
  70. package/core/tables/vport.js +2 -2
  71. package/core/tools/chamfer.js +117 -143
  72. package/core/tools/chamferFilletBase.js +138 -37
  73. package/core/tools/copy.js +11 -11
  74. package/core/tools/copybase.js +3 -3
  75. package/core/tools/copyclip.js +3 -3
  76. package/core/tools/cornerEntity.js +2 -2
  77. package/core/tools/cutclip.js +3 -3
  78. package/core/tools/explode.js +7 -7
  79. package/core/tools/extend.js +138 -25
  80. package/core/tools/fillet.js +92 -189
  81. package/core/tools/matchProp.js +3 -12
  82. package/core/tools/mirror.js +15 -14
  83. package/core/tools/move.js +8 -8
  84. package/core/tools/offset.js +31 -33
  85. package/core/tools/pasteclip.js +1 -1
  86. package/core/tools/purge.js +10 -10
  87. package/core/tools/rotate.js +19 -16
  88. package/core/tools/scale.js +7 -7
  89. package/core/tools/trim.js +271 -29
  90. package/core/tools/zoom.js +1 -1
  91. package/cspell.json +321 -0
  92. package/jest.config.js +6 -0
  93. package/package.json +5 -3
  94. package/test/dimensions/alignedDimension.test.js +17 -10
  95. package/test/dimensions/angularDimension.test.js +13 -13
  96. package/test/dimensions/diametricDimension.test.js +15 -15
  97. package/test/dimensions/dimension.test.js +12 -12
  98. package/test/dimensions/{baseDimension.test.js → dimensionBase.test.js} +73 -12
  99. package/test/dimensions/linearDimensionBase.test.js +62 -0
  100. package/test/dimensions/radialDimension.test.js +15 -15
  101. package/test/dimensions/rotatedDimension.test.js +18 -11
  102. package/test/entities/arc.test.js +83 -86
  103. package/test/entities/arctext.test.js +184 -57
  104. package/test/entities/circle.test.js +68 -96
  105. package/test/entities/entity.test.js +42 -8
  106. package/test/entities/hatch.test.js +569 -96
  107. package/test/entities/insert.test.js +99 -4
  108. package/test/entities/line.test.js +15 -41
  109. package/test/entities/lwpolyline.test.js +104 -0
  110. package/test/entities/point.test.js +3 -3
  111. package/test/entities/polyline.test.js +11 -0
  112. package/test/entities/{basePolyline.test.js → polylineBase.test.js} +192 -57
  113. package/test/entities/rectangle.test.js +11 -0
  114. package/test/entities/solid.test.js +1 -1
  115. package/test/entities/text.test.js +302 -77
  116. package/test/integration/exportIntegration.reference.dxf +9 -9
  117. package/test/integration/exportIntegration.test.js +5 -5
  118. package/test/integration/intersectionIntegration.test.js +4 -5
  119. package/test/integration/pdfRendererIntegration.reference.pdf +17709 -0
  120. package/test/integration/pdfRendererIntegration.test.js +61 -0
  121. package/test/integration/svgRendererIntegration.reference.svg +3343 -0
  122. package/test/integration/svgRendererIntegration.test.js +61 -0
  123. package/test/integration/userInputIntegration.reference.dxf +1165 -105
  124. package/test/integration/userInputIntegration.test.js +239 -132
  125. package/test/lib/boundingBox.test.js +3 -3
  126. package/test/lib/canvas.test.js +744 -125
  127. package/test/lib/constants.test.js +27 -0
  128. package/test/lib/entityManager.test.js +4 -4
  129. package/test/lib/inputManager.test.js +81 -20
  130. package/test/lib/intersect.test.js +83 -0
  131. package/test/lib/plotOptions.test.js +179 -0
  132. package/test/lib/rubberBand.test.js +84 -0
  133. package/test/lib/scene.test.js +9 -9
  134. package/test/lib/selectionManager.test.js +3 -3
  135. package/test/lib/settings.test.js +5 -6
  136. package/test/lib/snapping.test.js +72 -130
  137. package/test/lib/stateManager.test.js +7 -7
  138. package/test/lib/utils.test.js +36 -2
  139. package/test/properties/entityProperties.test.js +132 -0
  140. package/test/properties/property.test.js +53 -0
  141. package/test/properties/propertyManager.test.js +25 -25
  142. package/test/renderers/canvasRenderer.test.js +317 -0
  143. package/test/renderers/pdfRenderer.test.js +271 -0
  144. package/test/renderers/rendererBase.test.js +213 -0
  145. package/test/renderers/svgRenderer.test.js +326 -0
  146. package/test/tables/block.test.js +92 -13
  147. package/test/tables/endblk.test.js +2 -2
  148. package/test/tables/layer.test.js +30 -0
  149. package/test/tables/layerManager.test.js +2 -2
  150. package/test/test-helpers/hatchGridRenderer.js +180 -0
  151. package/test/test-helpers/test-helpers.js +158 -6
  152. package/test/tools/chamfer.test.js +273 -51
  153. package/test/tools/chamferFilletBase.test.js +125 -36
  154. package/test/tools/copy.test.js +8 -8
  155. package/test/tools/copybase.test.js +2 -2
  156. package/test/tools/copyclip.test.js +2 -2
  157. package/test/tools/cornerEntity.test.js +8 -8
  158. package/test/tools/cutclip.test.js +2 -2
  159. package/test/tools/erase.test.js +6 -6
  160. package/test/tools/explode.test.js +5 -5
  161. package/test/tools/extend.test.js +373 -42
  162. package/test/tools/fillet.test.js +230 -49
  163. package/test/tools/matchProp.test.js +11 -11
  164. package/test/tools/mirror.test.js +39 -39
  165. package/test/tools/move.test.js +7 -7
  166. package/test/tools/offset.test.js +222 -55
  167. package/test/tools/pasteclip.test.js +5 -5
  168. package/test/tools/purge.test.js +4 -4
  169. package/test/tools/rotate.test.js +39 -9
  170. package/test/tools/scale.test.js +33 -33
  171. package/test/tools/trim.test.js +579 -53
  172. package/test/tools/zoom.test.js +12 -12
  173. package/core/lib/selectionWindow.js +0 -83
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@design-core/core",
3
- "version": "0.0.6",
3
+ "version": "50.1.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
@@ -9,7 +9,7 @@
9
9
  "eslint": "^8.26.0",
10
10
  "eslint-config-google": "^0.14.0",
11
11
  "eslint-config-standard": "^17.0.0",
12
- "eslint-plugin-import": "^2.26.0",
12
+ "eslint-plugin-import": "^2.32.0",
13
13
  "eslint-plugin-n": "^15.3.0",
14
14
  "eslint-plugin-promise": "^6.1.1",
15
15
  "jest": "^29.7.0"
@@ -17,7 +17,9 @@
17
17
  "description": "2D CAD Library",
18
18
  "exports": {
19
19
  ".": "./core/core/core.js",
20
- "./designCore.js": "./core/designCore.js"
20
+ "./designCore.js": "./core/designCore.js",
21
+ "./property.js": "./core/properties/property.js",
22
+ "./canvasRenderer.js": "./core/lib/renderers/canvasRenderer.js"
21
23
  },
22
24
  "directories": {
23
25
  "test": "test"
@@ -13,14 +13,14 @@ const scenarios = [
13
13
 
14
14
  { desc: 'Aligned dimension from point selection',
15
15
  input: [new Point(), new Point(10, 0), new Point(5, 5)],
16
- selectedItems: [],
16
+ selectedEntities: [],
17
17
  expectedDimType: 1,
18
18
  dimensionValue: 10,
19
19
  },
20
20
  ];
21
21
 
22
22
  test.each(scenarios)('Dimension.execute handles $desc', async (scenario) => {
23
- const { input, selectedItems, expectedDimType, dimensionValue } = scenario;
23
+ const { input, selectedEntities, expectedDimType, dimensionValue } = scenario;
24
24
 
25
25
  await withMockInput(DesignCore.Scene, input, async () => {
26
26
  const dim = new AlignedDimension();
@@ -34,10 +34,10 @@ test.each(scenarios)('Dimension.execute handles $desc', async (scenario) => {
34
34
  // check if the text value matches the expected dimension value
35
35
  for (const entity of dimensionBlockEntities) {
36
36
  if (entity.type === 'Text') {
37
- expect(Number(entity.string)).toBeCloseTo(dimensionValue);
37
+ expect(Number(entity.getProperty('string'))).toBeCloseTo(dimensionValue);
38
38
  }
39
39
  }
40
- }, { selectedItems });
40
+ }, { selectedEntities });
41
41
  });
42
42
 
43
43
  test('constructor sets default properties', () => {
@@ -104,23 +104,29 @@ describe('AlignedDimension.getPointsFromSelection', () => {
104
104
  });
105
105
 
106
106
  test('AlignedDimension.preview runs without error and calls createTempItem', () => {
107
- const origCreateTempItem = DesignCore.Scene.tempEntities.create;
107
+ const origAddAux = DesignCore.Scene.auxiliaryEntities.add;
108
+ const origCreateTempItem = DesignCore.Scene.previewEntities.create;
108
109
  const origPointOnScene = DesignCore.Mouse.pointOnScene;
109
110
  // Manual mock for createTempItem
110
111
  const createTempItemCalls = [];
111
- DesignCore.Scene.tempEntities.create = function(type, obj) {
112
+ DesignCore.Scene.previewEntities.create = function(type, obj) {
112
113
  createTempItemCalls.push([type, obj]);
113
114
  };
115
+ // Manual mock for auxiliaryEntities.add
116
+ const addAuxCalls = [];
117
+ DesignCore.Scene.auxiliaryEntities.add = function(item) {
118
+ addAuxCalls.push(item);
119
+ };
114
120
  // Manual mock for pointOnScene
115
121
  DesignCore.Mouse.pointOnScene = function() {
116
122
  return new Point(5, 5);
117
123
  };
118
124
 
119
- // Test with 1 point (should call createTempItem with 'Line')
125
+ // Test with 1 point (should add a RubberBand to auxiliaryEntities)
120
126
  const dim1 = new AlignedDimension();
121
127
  dim1.points = [new Point(0, 0)];
122
128
  expect(() => dim1.preview()).not.toThrow();
123
- expect(createTempItemCalls.some((call) => call[0] === 'Line')).toBe(true);
129
+ expect(addAuxCalls.length).toBeGreaterThanOrEqual(1);
124
130
 
125
131
  // Test with >1 point (should call createTempItem with this.type)
126
132
  const dim2 = new AlignedDimension();
@@ -129,7 +135,8 @@ test('AlignedDimension.preview runs without error and calls createTempItem', ()
129
135
  expect(createTempItemCalls.some((call) => call[0] === dim2.type)).toBe(true);
130
136
 
131
137
  // Restore
132
- DesignCore.Scene.tempEntities.create = origCreateTempItem;
138
+ DesignCore.Scene.auxiliaryEntities.add = origAddAux;
139
+ DesignCore.Scene.previewEntities.create = origCreateTempItem;
133
140
  DesignCore.Mouse.pointOnScene = origPointOnScene;
134
141
  });
135
142
 
@@ -204,7 +211,7 @@ AcDbAlignedDimension
204
211
  expect(file.contents).toEqual(dxfString);
205
212
 
206
213
  // create new entity from entity data to ensure all props are loaded
207
- const newDimension = new AlignedDimension(dimension);
214
+ const newDimension = new AlignedDimension({ handle: dimension.getProperty('handle'), points: dimension.points, ...dimension });
208
215
  file = new File();
209
216
  newDimension.dxf(file);
210
217
  expect(file.contents).toEqual(dxfString);
@@ -18,35 +18,35 @@ const scenarios = [
18
18
 
19
19
  { desc: 'Angular dimension from line selection - 45 degrees',
20
20
  input: [new SingleSelection(0, new Point()), new SingleSelection(1, new Point()), new Point(5, 5)],
21
- selectedItems: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
21
+ selectedEntities: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
22
22
  expectedDimType: 2,
23
23
  dimensionValue: 45,
24
24
  dimensionEntities: 5,
25
25
  },
26
26
  { desc: 'Angular dimension from line selection - 135 degrees',
27
27
  input: [new SingleSelection(0, new Point()), new SingleSelection(1, new Point()), new Point(-5, 5)],
28
- selectedItems: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
28
+ selectedEntities: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
29
29
  expectedDimType: 2,
30
30
  dimensionValue: 135,
31
31
  dimensionEntities: 6,
32
32
  },
33
33
  { desc: 'Angular dimension from line selection - 45 degrees',
34
34
  input: [new SingleSelection(0, new Point()), new SingleSelection(1, new Point()), new Point(-5, -5)],
35
- selectedItems: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
35
+ selectedEntities: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
36
36
  expectedDimType: 2,
37
37
  dimensionValue: 45,
38
38
  dimensionEntities: 7,
39
39
  },
40
40
  { desc: 'Angular dimension from line selection - 135 degrees',
41
41
  input: [new SingleSelection(0, new Point()), new SingleSelection(1, new Point()), new Point(5, -5)],
42
- selectedItems: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
42
+ selectedEntities: [new Line({ points: [new Point(0, 0), new Point(10, 0)] }), new Line({ points: [new Point(0, 0), new Point(10, 10)] })],
43
43
  expectedDimType: 2,
44
44
  dimensionValue: 135,
45
45
  dimensionEntities: 6,
46
46
  },
47
47
  { desc: 'Angular dimension from polyline selection - 45 degrees',
48
48
  input: [new SingleSelection(0, new Point(5, 0)), new SingleSelection(1, new Point(5, 5)), new Point(5, 5)],
49
- selectedItems: [new Polyline({ points: [new Point(0, 0), new Point(10, 0)] }), new Polyline({ points: [new Point(0, 0), new Point(10, 10)] })],
49
+ selectedEntities: [new Polyline({ points: [new Point(0, 0), new Point(10, 0)] }), new Polyline({ points: [new Point(0, 0), new Point(10, 10)] })],
50
50
  expectedDimType: 2,
51
51
  dimensionValue: 45,
52
52
  dimensionEntities: 5,
@@ -54,7 +54,7 @@ const scenarios = [
54
54
  ];
55
55
 
56
56
  test.each(scenarios)('Dimension.execute handles $desc', async (scenario) => {
57
- const { input, selectedItems, expectedDimType, dimensionValue, dimensionEntities } = scenario;
57
+ const { input, selectedEntities, expectedDimType, dimensionValue, dimensionEntities } = scenario;
58
58
 
59
59
  await withMockInput(DesignCore.Scene, input, async () => {
60
60
  const dim = new AngularDimension();
@@ -69,12 +69,12 @@ test.each(scenarios)('Dimension.execute handles $desc', async (scenario) => {
69
69
  for (const entity of dimensionBlockEntities) {
70
70
  if (entity.type === 'Text') {
71
71
  // remove all non-numeric characters except . and -
72
- const numbersOnly = entity.string.replace(/[^0-9.-]+/g, '');
72
+ const numbersOnly = entity.getProperty('string').replace(/[^0-9.-]+/g, '');
73
73
  expect(Number(numbersOnly)).toBeCloseTo(dimensionValue);
74
- expect(entity.string).toContain('°');
74
+ expect(entity.getProperty('string')).toContain('°');
75
75
  }
76
76
  }
77
- }, { selectedItems });
77
+ }, { selectedEntities });
78
78
  });
79
79
 
80
80
  test('constructor sets default properties', () => {
@@ -100,11 +100,11 @@ test('getPointsFromSelection returns correct sequenced points', () => {
100
100
  });
101
101
 
102
102
  test('AngularDimension.preview runs without error and calls createTempItem', () => {
103
- const origCreateTempItem = DesignCore.Scene.tempEntities.create;
103
+ const origCreateTempItem = DesignCore.Scene.previewEntities.create;
104
104
  const origPointOnScene = DesignCore.Mouse.pointOnScene;
105
105
  // Manual mock for createTempItem
106
106
  const createTempItemCalls = [];
107
- DesignCore.Scene.tempEntities.create = function(type, obj) {
107
+ DesignCore.Scene.previewEntities.create = function(type, obj) {
108
108
  createTempItemCalls.push([type, obj]);
109
109
  };
110
110
  // Manual mock for pointOnScene
@@ -138,7 +138,7 @@ test('AngularDimension.preview runs without error and calls createTempItem', ()
138
138
  expect(createTempItemCalls.some((call) => call[0] === dim2.type)).toBe(true);
139
139
 
140
140
  // Restore
141
- DesignCore.Scene.tempEntities.create = origCreateTempItem;
141
+ DesignCore.Scene.previewEntities.create = origCreateTempItem;
142
142
  DesignCore.Mouse.pointOnScene = origPointOnScene;
143
143
  });
144
144
 
@@ -234,7 +234,7 @@ AcDb2LineAngularDimension
234
234
  expect(file.contents).toEqual(dxfString);
235
235
 
236
236
  // create new entity from entity data to ensure all props are loaded
237
- const newDimension = new AngularDimension(dimension);
237
+ const newDimension = new AngularDimension({ handle: dimension.getProperty('handle'), points: dimension.points, ...dimension });
238
238
  file = new File();
239
239
  newDimension.dxf(file);
240
240
  expect(file.contents).toEqual(dxfString);
@@ -17,28 +17,28 @@ const scenarios = [
17
17
 
18
18
  { desc: 'Diametric dimension from circle selection - Text outside circle',
19
19
  input: [new SingleSelection(0, new Point()), new Point(20, 0)],
20
- selectedItems: [new Circle({ points: [new Point(0, 0), new Point(10, 0)] })],
20
+ selectedEntities: [new Circle({ points: [new Point(0, 0), new Point(10, 0)] })],
21
21
  expectedDimType: 3,
22
22
  dimensionValue: 20,
23
23
  dimensionEntities: 6,
24
24
  },
25
25
  { desc: 'Diametric dimension from circle selection - Text inside circle',
26
26
  input: [new SingleSelection(0, new Point()), new Point(0, 0)],
27
- selectedItems: [new Circle({ points: [new Point(0, 0), new Point(10, 0)] })],
27
+ selectedEntities: [new Circle({ points: [new Point(0, 0), new Point(10, 0)] })],
28
28
  expectedDimType: 3,
29
29
  dimensionValue: 20,
30
30
  dimensionEntities: 5,
31
31
  },
32
32
  { desc: 'Diametric dimension from arc selection',
33
33
  input: [new SingleSelection(0, new Point()), new Point(20, 10)],
34
- selectedItems: [new Arc({ points: [new Point(0, 0), new Point(20, 0), new Point(20, 20)] })],
34
+ selectedEntities: [new Arc({ points: [new Point(0, 0), new Point(20, 0), new Point(20, 20)] })],
35
35
  expectedDimType: 3,
36
36
  dimensionValue: 40,
37
37
  dimensionEntities: 6,
38
38
  },
39
39
  { desc: 'Diametric dimension from polyline selection',
40
40
  input: [new SingleSelection(0, new Point(30, 10)), new Point(30, 10)],
41
- selectedItems: [new Polyline({ points: [new Point(0, 0), new Point(20, 0, 1), new Point(20, 20)] })],
41
+ selectedEntities: [new Polyline({ points: [new Point(0, 0), new Point(20, 0, 1), new Point(20, 20)] })],
42
42
  expectedDimType: 3,
43
43
  dimensionValue: 20,
44
44
  dimensionEntities: 6,
@@ -46,7 +46,7 @@ const scenarios = [
46
46
  ];
47
47
 
48
48
  test.each(scenarios)('DiametricDimension.execute handles $desc', async (scenario) => {
49
- const { input, selectedItems, expectedDimType, dimensionValue, dimensionEntities } = scenario;
49
+ const { input, selectedEntities, expectedDimType, dimensionValue, dimensionEntities } = scenario;
50
50
 
51
51
  await withMockInput(DesignCore.Scene, input, async () => {
52
52
  const dim = new DiametricDimension();
@@ -61,12 +61,12 @@ test.each(scenarios)('DiametricDimension.execute handles $desc', async (scenario
61
61
  for (const entity of dimensionBlockEntities) {
62
62
  if (entity.type === 'Text') {
63
63
  // remove all none numberic characters except . and -
64
- const numbersOnly = entity.string.replace(/[^0-9.-]+/g, '');
64
+ const numbersOnly = entity.getProperty('string').replace(/[^0-9.-]+/g, '');
65
65
  expect(Number(numbersOnly)).toBeCloseTo(dimensionValue);
66
- expect(entity.string).toContain('Ø');
66
+ expect(entity.getProperty('string')).toContain('Ø');
67
67
  }
68
68
  }
69
- }, { selectedItems });
69
+ }, { selectedEntities });
70
70
  });
71
71
 
72
72
  test('constructor sets default properties', () => {
@@ -77,26 +77,26 @@ test('constructor sets default properties', () => {
77
77
 
78
78
 
79
79
  test('getPointsFromSelection returns correct sequenced points', () => {
80
- const center = new Point(0, 0);
80
+ const centre = new Point(0, 0);
81
81
  const textPos = new Point(10, 0);
82
82
  // Mock item with getRadius
83
- const item = { points: [center], getRadius: () => 10 };
83
+ const item = { points: [centre], getRadius: () => 10 };
84
84
  const result = DiametricDimension.getPointsFromSelection([item], textPos);
85
85
  expect(Array.isArray(result)).toBe(true);
86
86
  expect(result.length).toBe(3);
87
- expect(result[0].sequence).toBe(10); // center
87
+ expect(result[0].sequence).toBe(10); // centre
88
88
  expect(result[1].sequence).toBe(15); // radius point
89
89
  expect(result[2].sequence).toBe(11); // text position
90
90
  });
91
91
 
92
92
  test('DiametricDimension.preview runs without error and calls createTempItem', () => {
93
- const origCreateTempItem = DesignCore.Scene.tempEntities.create;
93
+ const origCreateTempItem = DesignCore.Scene.previewEntities.create;
94
94
  const origPointOnScene = DesignCore.Mouse.pointOnScene;
95
95
  const origSeletionSet = DesignCore.Scene.selectionManager.selectionSet.selectionSet.length;
96
96
 
97
97
  // Manual mock for createTempItem
98
98
  const createTempItemCalls = [];
99
- DesignCore.Scene.tempEntities.create = function(type, obj) {
99
+ DesignCore.Scene.previewEntities.create = function(type, obj) {
100
100
  createTempItemCalls.push([type, obj]);
101
101
  };
102
102
  // Manual mock for pointOnScene
@@ -130,7 +130,7 @@ test('DiametricDimension.preview runs without error and calls createTempItem', (
130
130
  expect(createTempItemCalls.some((call) => call[0] === dim2.type)).toBe(true);
131
131
 
132
132
  // Restore
133
- DesignCore.Scene.tempEntities.create = origCreateTempItem;
133
+ DesignCore.Scene.previewEntities.create = origCreateTempItem;
134
134
  DesignCore.Mouse.pointOnScene = origPointOnScene;
135
135
  DesignCore.Scene.selectionManager.selectionSet.selectionSet.length = origSeletionSet;
136
136
  });
@@ -196,7 +196,7 @@ AcDbDiametricDimension
196
196
  expect(file.contents).toEqual(dxfString);
197
197
 
198
198
  // create new entity from entity data to ensure all props are loaded
199
- const newDimension = new DiametricDimension(dimension);
199
+ const newDimension = new DiametricDimension({ handle: dimension.getProperty('handle'), points: dimension.points, ...dimension });
200
200
  file = new File();
201
201
  newDimension.dxf(file);
202
202
  expect(file.contents).toEqual(dxfString);
@@ -18,61 +18,61 @@ const scenarios = [
18
18
 
19
19
  { desc: 'Rotated dimension from line selection',
20
20
  input: [new SingleSelection(0, new Point()), new Point(5, 5)],
21
- selectedItems: [new Line({ points: [new Point(), new Point(10, 0)] })],
21
+ selectedEntities: [new Line({ points: [new Point(), new Point(10, 0)] })],
22
22
  expectedDimType: 0,
23
23
  },
24
24
  { desc: 'Aligned dimension from line selection',
25
25
  input: [new SingleSelection(0, new Point()), new Point(6.5, 3.5)],
26
- selectedItems: [new Line({ points: [new Point(), new Point(10, 10)] })],
26
+ selectedEntities: [new Line({ points: [new Point(), new Point(10, 10)] })],
27
27
  expectedDimType: 1,
28
28
  },
29
29
  { desc: 'Rotated dimension from point selection',
30
30
  input: [new Point(), new Point(10, 0), new Point(5, 5)],
31
- selectedItems: [],
31
+ selectedEntities: [],
32
32
  expectedDimType: 0,
33
33
  },
34
34
  { desc: 'Diametric dimension from circle selection',
35
35
  input: [new SingleSelection(0, new Point()), new Point(20, 10)],
36
- selectedItems: [new Circle({ points: [new Point(), new Point(10, 0)] })],
36
+ selectedEntities: [new Circle({ points: [new Point(), new Point(10, 0)] })],
37
37
  expectedDimType: 3,
38
38
  },
39
39
  { desc: 'Radial dimension from arc selection',
40
40
  input: [new SingleSelection(0, new Point()), new Point(20, 10)],
41
- selectedItems: [new Arc({ points: [new Point(), new Point(10, 0), new Point(10, 10)] })],
41
+ selectedEntities: [new Arc({ points: [new Point(), new Point(10, 0), new Point(10, 10)] })],
42
42
  expectedDimType: 4,
43
43
  },
44
44
  { desc: 'Angular dimension from line selection',
45
45
  input: [new SingleSelection(0, new Point()), new SingleSelection(1, new Point()), new Point(5, 5)],
46
- selectedItems: [new Line({ points: [new Point(), new Point(10, 0)] }), new Line({ points: [new Point(), new Point(10, 10)] })],
46
+ selectedEntities: [new Line({ points: [new Point(), new Point(10, 0)] }), new Line({ points: [new Point(), new Point(10, 10)] })],
47
47
  expectedDimType: 2,
48
48
  },
49
49
  { desc: 'Aligned dimension from polyline selection',
50
50
  input: [new SingleSelection(0, new Point()), new SingleSelection(1, new Point()), new Point(5, 5)],
51
- selectedItems: [new Polyline({ points: [new Point(), new Point(10, 0)] })],
51
+ selectedEntities: [new Polyline({ points: [new Point(), new Point(10, 0)] })],
52
52
  expectedDimType: 1,
53
53
  },
54
54
  { desc: 'Radial dimension from polyline selection',
55
55
  input: [new SingleSelection(0, new Point(16, 5)), new Point(20, 5)],
56
- selectedItems: [new Polyline({ points: [new Point(), new Point(10, 0, 1), new Point(10, 10)] })],
56
+ selectedEntities: [new Polyline({ points: [new Point(), new Point(10, 0, 1), new Point(10, 10)] })],
57
57
  expectedDimType: 4,
58
58
  },
59
59
  { desc: 'Angular dimension from polyline selection',
60
60
  input: [new SingleSelection(0, new Point(5, 0)), new SingleSelection(1, new Point(5, 5)), new Point(5, 5)],
61
- selectedItems: [new Polyline({ points: [new Point(), new Point(10, 0)] }), new Polyline({ points: [new Point(), new Point(10, 10)] })],
61
+ selectedEntities: [new Polyline({ points: [new Point(), new Point(10, 0)] }), new Polyline({ points: [new Point(), new Point(10, 10)] })],
62
62
  expectedDimType: 2,
63
63
  },
64
64
 
65
65
  ];
66
66
 
67
67
  test.each(scenarios)('Dimension.execute handles $desc', async (scenario) => {
68
- const { input, selectedItems, expectedDimType } = scenario;
68
+ const { input, selectedEntities, expectedDimType } = scenario;
69
69
 
70
70
  await withMockInput(DesignCore.Scene, input, async () => {
71
71
  const dim = new Dimension();
72
72
  await dim.execute();
73
73
 
74
74
  expect(dim.dimType.getBaseDimType()).toBe(expectedDimType);
75
- }, { selectedItems });
75
+ }, { selectedEntities });
76
76
  });
77
77
 
78
78
  test('constructor instantiates correct dimension type', () => {
@@ -95,7 +95,7 @@ test('get linear dimension type', () => {
95
95
 
96
96
  test('preview calls createTempItem with correct args', () => {
97
97
  const dim = new Dimension({ 70: 1 });
98
- dim.selectedItems = [1];
98
+ dim.selectedEntities = [1];
99
99
  dim.points = [{}, {}];
100
100
  // Should not throw
101
101
  expect(() => dim.preview()).not.toThrow();
@@ -1,26 +1,28 @@
1
- import { BaseDimension } from '../../core/dimensions/baseDimension.js';
1
+ import { DimensionBase } from '../../core/dimensions/dimensionBase.js';
2
2
  import { Point } from '../../core/entities/point.js';
3
3
  import { Core } from '../../core/core/core.js';
4
4
  import { Text } from '../../core/entities/text.js';
5
+ import { Line } from '../../core/entities/line.js';
6
+ import { jest } from '@jest/globals';
5
7
  // import { DimType } from '../../core/properties/dimType.js';
6
8
 
7
9
  // initialise core
8
10
  new Core();
9
11
 
10
- describe('BaseDimension', () => {
12
+ describe('DimensionBase', () => {
11
13
  let baseDim;
12
14
 
13
15
  beforeEach(() => {
14
- baseDim = new BaseDimension({});
16
+ baseDim = new DimensionBase({});
15
17
  baseDim.points = [new Point(1, 2, 0), new Point(3, 4, 0)];
16
18
  });
17
19
 
18
20
  test('constructor sets default properties', () => {
19
- expect(baseDim.textOverride).toBe('');
20
- expect(baseDim.blockName).toBe('');
21
- expect(baseDim.dimensionStyle).toBe('STANDARD');
22
- expect(baseDim.leaderLength).toBe(0);
23
- expect(baseDim.linearDimAngle).toBe(0);
21
+ expect(baseDim.getProperty('textOverride')).toBe('');
22
+ expect(baseDim.getProperty('blockName')).toBe('');
23
+ expect(baseDim.getProperty('dimensionStyle')).toBe('STANDARD');
24
+ expect(baseDim.getProperty('leaderLength')).toBe(0);
25
+ expect(baseDim.getProperty('linearDimAngle')).toBe(0);
24
26
  });
25
27
 
26
28
  test('getDimensionValue formats values by dimension type', () => {
@@ -162,21 +164,21 @@ describe('BaseDimension', () => {
162
164
  });
163
165
 
164
166
  test('constructor throws on invalid dimType', () => {
165
- expect(() => new BaseDimension({ 70: 999 })).toThrow(/Invalid Dimension Type/);
167
+ expect(() => new DimensionBase({ 70: 999 })).toThrow(/Invalid Dimension Type/);
166
168
  });
167
169
 
168
170
  test('getDimensionValue uses textOverride', () => {
169
- baseDim.textOverride = 'foo <> bar';
171
+ baseDim.setProperty('textOverride', 'foo <> bar');
170
172
  expect(baseDim.getDimensionValue(10)).toBe('foo 10.0000 bar');
171
173
  });
172
174
 
173
175
  test('getDimensionText returns a Text object with correct values', () => {
174
176
  const text = baseDim.getDimensionText(10, new Point(1, 2), Math.PI / 4);
175
177
  expect(text).toBeInstanceOf(Text);
176
- expect(text.height).toBe(0.18);
178
+ expect(text.getProperty('height')).toBe(0.18);
177
179
  expect(text.points[0].x).toBe(1);
178
180
  expect(text.points[0].y).toBe(2);
179
- expect(typeof text.string).toBe('string');
181
+ expect(typeof text.getProperty('string')).toBe('string');
180
182
  });
181
183
 
182
184
  test('getTextDirection flips angle in lower half', () => {
@@ -236,4 +238,63 @@ describe('BaseDimension', () => {
236
238
  baseDim.block = { touched: () => false };
237
239
  expect(baseDim.touched({})).toBe(false);
238
240
  });
241
+
242
+ describe('draw()', () => {
243
+ /**
244
+ * Return a DimensionBase with a stubbed buildDimension() that produces one Line.
245
+ * @return {DimensionBase}
246
+ */
247
+ function makeDim() {
248
+ const dim = new DimensionBase({});
249
+ dim.points = [new Point(0, 0), new Point(10, 0)];
250
+ dim.buildDimension = jest.fn(() => {
251
+ return [new Line({ points: [new Point(0, 0), new Point(10, 0)] })];
252
+ });
253
+ return dim;
254
+ }
255
+
256
+ test('draw() returns the block items array', () => {
257
+ const dim = makeDim();
258
+ const result = dim.draw({});
259
+ expect(result).toBe(dim.block.entities);
260
+ });
261
+
262
+ test('draw() calls refresh() (via buildDimension) when block is empty', () => {
263
+ const dim = makeDim();
264
+ expect(dim.block.entities).toHaveLength(0);
265
+ dim.draw({});
266
+ expect(dim.buildDimension).toHaveBeenCalledTimes(1);
267
+ expect(dim.block.entities.length).toBeGreaterThan(0);
268
+ });
269
+
270
+ test('draw() does not call refresh() when block already has items', () => {
271
+ const dim = makeDim();
272
+ // pre-populate the block
273
+ dim.block.addEntity(new Line({ points: [new Point(0, 0), new Point(1, 1)] }));
274
+ dim.draw({});
275
+ expect(dim.buildDimension).not.toHaveBeenCalled();
276
+ });
277
+
278
+ test('draw() returns populated items after initial refresh', () => {
279
+ const dim = makeDim();
280
+ const items = dim.draw({});
281
+ expect(items).toBeInstanceOf(Array);
282
+ expect(items.length).toBeGreaterThan(0);
283
+ });
284
+
285
+ test('draw() returns same array reference on repeated calls', () => {
286
+ const dim = makeDim();
287
+ const first = dim.draw({});
288
+ const second = dim.draw({});
289
+ expect(first).toBe(second);
290
+ });
291
+
292
+ test('draw() block items have BYBLOCK colour after refresh', () => {
293
+ const dim = makeDim();
294
+ dim.draw({});
295
+ for (const item of dim.block.entities) {
296
+ expect(item.entityColour.aci).toBe(0); // BYBLOCK = ACI 0
297
+ }
298
+ });
299
+ });
239
300
  });
@@ -0,0 +1,62 @@
1
+ import { AlignedDimension } from '../../core/dimensions/alignedDimension.js';
2
+ import { LinearDimensionBase } from '../../core/dimensions/linearDimensionBase.js';
3
+ import { Point } from '../../core/entities/point.js';
4
+ import { DesignCore } from '../../core/designCore.js';
5
+ import { Core } from '../../core/core/core.js';
6
+
7
+ // initialise core
8
+ new Core();
9
+
10
+ // ─── constructor ─────────────────────────────────────────────────────────────
11
+
12
+ test('LinearDimensionBase can be instantiated', () => {
13
+ const dim = new LinearDimensionBase();
14
+ expect(dim).toBeInstanceOf(LinearDimensionBase);
15
+ expect(dim.points).toBeDefined();
16
+ expect(Array.isArray(dim.points)).toBe(true);
17
+ });
18
+
19
+ // ─── preview ─────────────────────────────────────────────────────────────────
20
+
21
+ test('LinearDimensionBase.preview - 0 points does nothing', () => {
22
+ const dim = new AlignedDimension();
23
+ DesignCore.Scene.auxiliaryEntities.clear();
24
+ DesignCore.Scene.previewEntities.clear();
25
+
26
+ expect(() => dim.preview()).not.toThrow();
27
+ expect(DesignCore.Scene.auxiliaryEntities.count()).toBe(0);
28
+ expect(DesignCore.Scene.previewEntities.count()).toBe(0);
29
+ });
30
+
31
+ test('LinearDimensionBase.preview - 1 point adds RubberBand to auxiliaryEntities', () => {
32
+ const dim = new AlignedDimension();
33
+ dim.points = [new Point(0, 0)];
34
+
35
+ const origAdd = DesignCore.Scene.auxiliaryEntities.add;
36
+ const added = [];
37
+ DesignCore.Scene.auxiliaryEntities.add = (item) => added.push(item);
38
+ DesignCore.Scene.previewEntities.clear();
39
+
40
+ expect(() => dim.preview()).not.toThrow();
41
+ expect(added.length).toBeGreaterThanOrEqual(1);
42
+ expect(DesignCore.Scene.previewEntities.count()).toBe(0);
43
+
44
+ DesignCore.Scene.auxiliaryEntities.add = origAdd;
45
+ });
46
+
47
+ test('LinearDimensionBase.preview - >1 points creates temp entity', () => {
48
+ const dim = new AlignedDimension();
49
+ dim.points = [new Point(0, 0), new Point(10, 0)];
50
+
51
+ const origCreate = DesignCore.Scene.previewEntities.create;
52
+ const created = [];
53
+ DesignCore.Scene.previewEntities.create = (type, data) => created.push({ type, data });
54
+ DesignCore.Scene.auxiliaryEntities.clear();
55
+
56
+ expect(() => dim.preview()).not.toThrow();
57
+ expect(created.length).toBeGreaterThanOrEqual(1);
58
+ expect(created[0].type).toBe(dim.type);
59
+ expect(DesignCore.Scene.auxiliaryEntities.count()).toBe(0);
60
+
61
+ DesignCore.Scene.previewEntities.create = origCreate;
62
+ });