@design-core/core 0.0.1 → 0.0.3

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 (254) hide show
  1. package/.eslintrc.json +14 -7
  2. package/.github/workflows/DesignCoreQA.yml +3 -1
  3. package/README.md +11 -4
  4. package/TODO.md +19 -0
  5. package/core/core/core.js +49 -42
  6. package/core/designCore.js +61 -2
  7. package/core/dimensions/alignedDimension.js +142 -0
  8. package/core/dimensions/angularDimension.js +550 -0
  9. package/core/dimensions/baseCircularDimension.js +244 -0
  10. package/core/dimensions/baseDimension.js +558 -0
  11. package/core/dimensions/baseLinearDimension.js +371 -0
  12. package/core/dimensions/diametricDimension.js +82 -0
  13. package/core/dimensions/dimension.js +298 -0
  14. package/core/dimensions/linearDimension.js +29 -0
  15. package/core/dimensions/radialDimension.js +78 -0
  16. package/core/dimensions/rotatedDimension.js +167 -0
  17. package/core/entities/arc.js +314 -60
  18. package/core/entities/arctext.js +642 -0
  19. package/core/entities/basePolyline.js +553 -94
  20. package/core/entities/circle.js +181 -54
  21. package/core/entities/entity.js +154 -74
  22. package/core/entities/hatch.js +807 -0
  23. package/core/entities/insert.js +200 -39
  24. package/core/entities/line.js +196 -134
  25. package/core/entities/lwpolyline.js +21 -44
  26. package/core/entities/point.js +194 -29
  27. package/core/entities/polyline.js +54 -7
  28. package/core/entities/rectangle.js +43 -13
  29. package/core/entities/solid.js +43 -6
  30. package/core/entities/text.js +324 -181
  31. package/core/lib/boundingBox.js +73 -13
  32. package/core/lib/canvas.js +256 -65
  33. package/core/lib/clipboard.js +198 -0
  34. package/core/lib/colour.js +144 -0
  35. package/core/lib/colours.js +367 -301
  36. package/core/lib/commandLine.js +16 -28
  37. package/core/lib/commandManager.js +115 -58
  38. package/core/lib/constants.js +23 -0
  39. package/core/lib/dxf/dxf.js +249 -34
  40. package/core/lib/dxf/dxfFile.js +23 -38
  41. package/core/lib/dxf/dxfIterator.js +17 -5
  42. package/core/lib/dxf/dxfRead.js +23 -7
  43. package/core/lib/dxf/dxfWrite.js +39 -129
  44. package/core/lib/dxf/handleManager.js +97 -0
  45. package/core/lib/dxf/sections/blocks.js +16 -2
  46. package/core/lib/dxf/sections/entities.js +17 -3
  47. package/core/lib/dxf/sections/header.js +10 -1
  48. package/core/lib/dxf/sections/objects.js +36 -0
  49. package/core/lib/dxf/sections/section.js +43 -5
  50. package/core/lib/dxf/sections/tables.js +17 -3
  51. package/core/lib/entityManager.js +178 -0
  52. package/core/lib/fileio.js +14 -4
  53. package/core/lib/headers.js +229 -0
  54. package/core/lib/input.js +46 -0
  55. package/core/lib/inputManager.js +199 -194
  56. package/core/lib/intersect.js +341 -468
  57. package/core/lib/logging.js +25 -1
  58. package/core/lib/matrix.js +6 -8
  59. package/core/lib/mouse.js +24 -79
  60. package/core/lib/patterns.js +690 -0
  61. package/core/lib/promptOptions.js +133 -0
  62. package/core/lib/scene.js +71 -174
  63. package/core/lib/selectionManager.js +74 -48
  64. package/core/lib/selectionWindow.js +24 -10
  65. package/core/lib/settings.js +18 -11
  66. package/core/lib/snapping.js +129 -21
  67. package/core/lib/stateManager.js +288 -0
  68. package/core/lib/strings.js +57 -5
  69. package/core/lib/utils.js +95 -11
  70. package/core/objects/dictionary.js +43 -0
  71. package/core/objects/dictionaryManager.js +80 -0
  72. package/core/properties/dimType.js +117 -0
  73. package/core/properties/flags.js +66 -0
  74. package/core/properties/property.js +26 -0
  75. package/core/properties/propertyManager.js +65 -19
  76. package/core/tables/appId.js +31 -0
  77. package/core/tables/appIdManager.js +44 -0
  78. package/core/tables/block.js +323 -0
  79. package/core/tables/blockManager.js +48 -0
  80. package/core/tables/blockRecord.js +29 -0
  81. package/core/tables/blockRecordManager.js +37 -0
  82. package/core/tables/dimStyle.js +627 -0
  83. package/core/tables/dimStyleManager.js +187 -0
  84. package/core/tables/endblk.js +28 -0
  85. package/core/tables/layer.js +219 -0
  86. package/core/tables/layerManager.js +47 -0
  87. package/core/tables/ltype.js +85 -0
  88. package/core/tables/ltypeManager.js +65 -0
  89. package/core/tables/style.js +145 -0
  90. package/core/tables/styleManager.js +55 -0
  91. package/core/tables/styleManagerBase.js +110 -0
  92. package/core/tables/tableManagerBase.js +354 -0
  93. package/core/tables/ucs.js +28 -0
  94. package/core/tables/ucsManager.js +44 -0
  95. package/core/tables/view.js +28 -0
  96. package/core/tables/viewManager.js +44 -0
  97. package/core/tables/vport.js +70 -0
  98. package/core/tables/vportManager.js +65 -0
  99. package/core/tools/chamfer.js +343 -0
  100. package/core/tools/chamferFilletBase.js +162 -0
  101. package/core/tools/copy.js +68 -40
  102. package/core/tools/copybase.js +65 -0
  103. package/core/tools/copyclip.js +59 -0
  104. package/core/tools/cornerEntity.js +138 -0
  105. package/core/tools/cutclip.js +72 -0
  106. package/core/tools/distance.js +37 -9
  107. package/core/tools/erase.js +43 -13
  108. package/core/tools/explode.js +117 -0
  109. package/core/tools/extend.js +71 -32
  110. package/core/tools/fillet.js +336 -0
  111. package/core/tools/identify.js +33 -6
  112. package/core/tools/matchProp.js +106 -0
  113. package/core/tools/mirror.js +141 -0
  114. package/core/tools/move.js +65 -32
  115. package/core/tools/offset.js +321 -0
  116. package/core/tools/pan.js +54 -0
  117. package/core/tools/pasteclip.js +93 -0
  118. package/core/tools/purge.js +90 -0
  119. package/core/tools/rotate.js +105 -70
  120. package/core/tools/scale.js +166 -0
  121. package/core/tools/tool.js +14 -4
  122. package/core/tools/trim.js +71 -32
  123. package/core/tools/zoom.js +152 -0
  124. package/package.json +3 -305
  125. package/test/dimensions/alignedDimension.test.js +211 -0
  126. package/test/dimensions/angularDimension.test.js +243 -0
  127. package/test/dimensions/baseDimension.test.js +239 -0
  128. package/test/dimensions/diametricDimension.test.js +203 -0
  129. package/test/dimensions/dimension.test.js +102 -0
  130. package/test/dimensions/radialDimension.test.js +203 -0
  131. package/test/dimensions/rotatedDimension.test.js +224 -0
  132. package/test/entities/arc.test.js +463 -41
  133. package/test/entities/arctext.test.js +329 -0
  134. package/test/entities/basePolyline.test.js +459 -10
  135. package/test/entities/circle.test.js +312 -7
  136. package/test/entities/entity.test.js +28 -9
  137. package/test/entities/hatch.test.js +606 -0
  138. package/test/entities/insert.test.js +90 -0
  139. package/test/entities/line.test.js +182 -6
  140. package/test/entities/point.test.js +375 -37
  141. package/test/entities/solid.test.js +156 -0
  142. package/test/entities/text.test.js +533 -7
  143. package/test/integration/exportIntegration.reference.dxf +1706 -0
  144. package/test/integration/exportIntegration.test.js +186 -0
  145. package/test/integration/importExportIntegration.test.js +126 -0
  146. package/test/integration/intersectionIntegration.test.js +880 -0
  147. package/test/integration/userInputIntegration.reference.dxf +1410 -0
  148. package/test/integration/userInputIntegration.test.js +269 -0
  149. package/test/lib/boundingBox.test.js +26 -2
  150. package/test/lib/canvas.test.js +613 -5
  151. package/test/lib/clipboard.test.js +70 -0
  152. package/test/lib/colour.test.js +114 -0
  153. package/test/lib/colours.test.js +63 -18
  154. package/test/lib/commandLine.test.js +159 -22
  155. package/test/lib/commandManager.test.js +4 -4
  156. package/test/lib/constants.test.js +9 -0
  157. package/test/lib/dxf/dxfFile.test.js +6 -2
  158. package/test/lib/dxf/dxfIterator.test.js +1 -1
  159. package/test/lib/dxf/dxfWrite.test.js +173 -0
  160. package/test/lib/dxf/handleManager.test.js +137 -0
  161. package/test/lib/dxf/sections/blocks.test.js +5 -5
  162. package/test/lib/dxf/sections/entities.test.js +4 -4
  163. package/test/lib/dxf/sections/header.test.js +18 -4
  164. package/test/lib/dxf/sections/objects.test.js +132 -0
  165. package/test/lib/dxf/sections/section.test.js +29 -29
  166. package/test/lib/dxf/sections/tables.test.js +3 -3
  167. package/test/lib/entityManager.test.js +163 -0
  168. package/test/lib/headers.test.js +233 -0
  169. package/test/lib/inputManager.test.js +1144 -5
  170. package/test/lib/intersect.test.js +454 -331
  171. package/test/lib/logging.test.js +1 -1
  172. package/test/lib/matrix.test.js +1 -1
  173. package/test/lib/mouse.test.js +327 -4
  174. package/test/lib/patterns.test.js +105 -0
  175. package/test/lib/promptOptions.test.js +179 -0
  176. package/test/lib/scene.test.js +16 -52
  177. package/test/lib/selectionManager.test.js +17 -5
  178. package/test/lib/settings.test.js +111 -5
  179. package/test/lib/snapping.test.js +142 -4
  180. package/test/lib/stateManager.test.js +155 -0
  181. package/test/lib/utils.test.js +81 -1
  182. package/test/objects/dictionary.test.js +81 -0
  183. package/test/objects/dictionaryManager.test.js +34 -0
  184. package/test/properties/dimType.test.js +62 -0
  185. package/test/properties/flags.test.js +164 -0
  186. package/test/properties/property.test.js +13 -0
  187. package/test/properties/propertyManager.test.js +10 -11
  188. package/test/tables/appId.test.js +46 -0
  189. package/test/tables/appIdManager.test.js +72 -0
  190. package/test/tables/block.test.js +157 -0
  191. package/test/tables/blockManager.test.js +52 -0
  192. package/test/tables/blockRecord.test.js +39 -0
  193. package/test/tables/blockRecordManager.test.js +60 -0
  194. package/test/tables/dimstyle.test.js +72 -0
  195. package/test/tables/endblk.test.js +30 -0
  196. package/test/tables/layer.test.js +95 -0
  197. package/test/tables/layerManager.test.js +172 -0
  198. package/test/{styles → tables}/ltype.test.js +7 -7
  199. package/test/{styles → tables}/ltypeManager.test.js +2 -2
  200. package/test/tables/style.test.js +44 -0
  201. package/test/tables/stylemanagerbase.test.js +220 -0
  202. package/test/tables/tableManagerBase.test.js +194 -0
  203. package/test/tables/ucs.test.js +37 -0
  204. package/test/tables/ucsManager.test.js +48 -0
  205. package/test/tables/view.test.js +37 -0
  206. package/test/tables/viewManager.test.js +48 -0
  207. package/test/tables/vport.test.js +117 -0
  208. package/test/tables/vportManager.test.js +54 -0
  209. package/test/test-helpers/test-helpers.js +66 -0
  210. package/test/tools/chamfer.test.js +970 -0
  211. package/test/tools/chamferFilletBase.test.js +446 -0
  212. package/test/tools/copy.test.js +22 -14
  213. package/test/tools/copybase.test.js +93 -0
  214. package/test/tools/copyclip.test.js +92 -0
  215. package/test/tools/cornerEntity.test.js +201 -0
  216. package/test/tools/cutclip.test.js +94 -0
  217. package/test/tools/distance.test.js +140 -18
  218. package/test/tools/erase.test.js +12 -12
  219. package/test/tools/explode.test.js +45 -0
  220. package/test/tools/extend.test.js +326 -44
  221. package/test/tools/fillet.test.js +831 -0
  222. package/test/tools/identify.test.js +115 -16
  223. package/test/tools/matchProp.test.js +84 -0
  224. package/test/tools/mirror.test.js +475 -0
  225. package/test/tools/move.test.js +75 -19
  226. package/test/tools/offset.test.js +748 -0
  227. package/test/tools/pan.test.js +72 -0
  228. package/test/tools/pasteclip.test.js +100 -0
  229. package/test/tools/purge.test.js +89 -0
  230. package/test/tools/rotate.test.js +89 -23
  231. package/test/tools/scale.test.js +529 -0
  232. package/test/tools/trim.test.js +419 -84
  233. package/test/tools/zoom.test.js +504 -0
  234. package/core/entities/alignedDimension.js +0 -279
  235. package/core/entities/angularDimension.js +0 -194
  236. package/core/entities/baseDimension.js +0 -227
  237. package/core/entities/block.js +0 -247
  238. package/core/entities/diametricDimension.js +0 -133
  239. package/core/entities/dimension.js +0 -202
  240. package/core/entities/radialDimension.js +0 -126
  241. package/core/styles/dimStyle.js +0 -719
  242. package/core/styles/dimStyleManager.js +0 -47
  243. package/core/styles/layer.js +0 -133
  244. package/core/styles/layerManager.js +0 -40
  245. package/core/styles/ltype.js +0 -86
  246. package/core/styles/ltypeManager.js +0 -50
  247. package/core/styles/style.js +0 -158
  248. package/core/styles/styleManager.js +0 -43
  249. package/core/styles/styleManagerBase.js +0 -299
  250. package/test/entities/block.test.js +0 -22
  251. package/test/styles/dimstyle.test.js +0 -19
  252. package/test/styles/layerManager.test.js +0 -150
  253. package/test/styles/style.test.js +0 -33
  254. package/test/styles/stylemanagerbase.test.js +0 -219
@@ -1,20 +1,38 @@
1
- import {Strings} from '../lib/strings.js';
2
- import {Tool} from './tool.js';
3
- import {Input, PromptOptions} from '../lib/inputManager.js';
4
- import {Logging} from '../lib/logging.js';
5
-
6
- import {DesignCore} from '../designCore.js';
7
-
1
+ import { Strings } from '../lib/strings.js';
2
+ import { Tool } from './tool.js';
3
+ import { Input, PromptOptions } from '../lib/inputManager.js';
4
+ import { Logging } from '../lib/logging.js';
5
+ import { Point } from '../entities/point.js';
6
+
7
+ import { DesignCore } from '../designCore.js';
8
+ import { UpdateState } from '../lib/stateManager.js';
9
+
10
+ /**
11
+ * Move Command Class
12
+ * @extends Tool
13
+ */
8
14
  export class Move extends Tool {
15
+ /** Create a Move command */
9
16
  constructor() {
10
17
  super();
11
18
  }
12
19
 
20
+ /**
21
+ * Register the command
22
+ * @return {Object}
23
+ * command = name of the command
24
+ * shortcut = shortcut for the command
25
+ * type = type to group command in toolbars (omitted if not shown)
26
+ */
13
27
  static register() {
14
- const command = {command: 'Move', shortcut: 'M', type: 'Tool'};
28
+ const command = { command: 'Move', shortcut: 'M', type: 'Tool' };
15
29
  return command;
16
30
  }
17
31
 
32
+ /**
33
+ * Execute method
34
+ * executes the workflow, requesting input required to perform the command
35
+ */
18
36
  async execute() {
19
37
  try {
20
38
  const op = new PromptOptions(Strings.Input.SELECTIONSET, [Input.Type.SELECTIONSET]);
@@ -25,19 +43,13 @@ export class Move extends Tool {
25
43
 
26
44
  const op2 = new PromptOptions(Strings.Input.BASEPOINT, [Input.Type.POINT]);
27
45
  const pt1 = await DesignCore.Scene.inputManager.requestInput(op2);
46
+ if (pt1 === undefined) return;
28
47
  this.points.push(pt1);
29
48
 
30
- const op3 = new PromptOptions(Strings.Input.DESTINATION, [Input.Type.POINT, Input.Type.NUMBER]);
49
+ const op3 = new PromptOptions(Strings.Input.DESTINATION, [Input.Type.POINT, Input.Type.DYNAMIC]);
31
50
  const pt2 = await DesignCore.Scene.inputManager.requestInput(op3);
32
-
33
- if (Input.getType(pt2) === Input.Type.POINT) {
34
- this.points.push(pt2);
35
- } else if (Input.getType(pt2) === Input.Type.NUMBER) {
36
- const basePoint = this.points.at(-1);
37
- const angle = Utils.degrees2radians(DesignCore.Mouse.inputAngle());
38
- const point = basePoint.project(angle, pt2);
39
- this.points.push(point);
40
- }
51
+ if (pt2 === undefined) return;
52
+ this.points.push(pt2);
41
53
 
42
54
  DesignCore.Scene.inputManager.executeCommand();
43
55
  } catch (err) {
@@ -45,36 +57,57 @@ export class Move extends Tool {
45
57
  }
46
58
  }
47
59
 
60
+ /**
61
+ * Preview the command during execution
62
+ */
48
63
  preview() {
49
64
  if (this.points.length >= 1) {
50
65
  const mousePoint = DesignCore.Mouse.pointOnScene();
51
66
 
52
67
  // Draw a line
53
68
  const points = [this.points.at(-1), mousePoint];
69
+ DesignCore.Scene.tempEntities.create('Line', { points: points });
54
70
 
55
- DesignCore.Scene.createTempItem('Line', {points: points});
56
-
57
- const xDelta = mousePoint.x - this.points[0].x;
58
- const yDelta = mousePoint.y - this.points[0].y;
71
+ // Get the delta from the last mouse point
72
+ const delta = mousePoint.subtract(this.lastMousePoint || this.points[0]);
73
+ this.lastMousePoint = mousePoint;
59
74
 
60
- for (let i = 0; i <DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
61
- for (let j = 0; j <DesignCore.Scene.selectionManager.selectedItems[i].points.length; j++) {
62
- DesignCore.Scene.selectionManager.selectedItems[i].points[j].x = DesignCore.Scene.items[DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]].points[j].x + xDelta;
63
- DesignCore.Scene.selectionManager.selectedItems[i].points[j].y = DesignCore.Scene.items[DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]].points[j].y + yDelta;
64
- }
75
+ for (let i = 0; i < DesignCore.Scene.selectionManager.selectedItems.length; i++) {
76
+ const item = DesignCore.Scene.selectionManager.selectedItems[i];
77
+ item.setProperty('points', this.getOffsetPoints(item.points, delta));
65
78
  }
66
79
  }
67
80
  }
68
81
 
82
+ /**
83
+ * Perform the command
84
+ */
69
85
  action() {
70
86
  const xDelta = this.points[1].x - this.points[0].x;
71
87
  const yDelta = this.points[1].y - this.points[0].y;
72
88
 
73
- for (let i = 0; i <DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
74
- for (let j = 0; j <DesignCore.Scene.selectionManager.selectedItems[i].points.length; j++) {
75
- DesignCore.Scene.items[DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]].points[j].x = DesignCore.Scene.items[DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]].points[j].x + xDelta;
76
- DesignCore.Scene.items[DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]].points[j].y = DesignCore.Scene.items[DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]].points[j].y + yDelta;
77
- }
89
+ const delta = new Point(xDelta, yDelta);
90
+
91
+ const stateChanges = [];
92
+
93
+ for (let i = 0; i < DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
94
+ const index = DesignCore.Scene.selectionManager.selectionSet.selectionSet[i];
95
+ const item = DesignCore.Scene.entities.get(index);
96
+ const stateChange = new UpdateState(item, { points: this.getOffsetPoints(item.points, delta) });
97
+ stateChanges.push(stateChange);
78
98
  }
99
+
100
+ DesignCore.Scene.commit(stateChanges);
101
+ }
102
+
103
+ /**
104
+ * Get offset points
105
+ * @param {Array} points
106
+ * @param {Point} delta
107
+ * @return {Array} offsetPoints
108
+ */
109
+ getOffsetPoints(points, delta) {
110
+ const offsetPoints = points.map((p) => new Point(p.x, p.y, p.bulge, p.sequence).add(delta));
111
+ return offsetPoints;
79
112
  }
80
113
  }
@@ -0,0 +1,321 @@
1
+ import { Utils } from '../lib/utils.js';
2
+ import { Strings } from '../lib/strings.js';
3
+ import { Tool } from './tool.js';
4
+ import { Input, PromptOptions } from '../lib/inputManager.js';
5
+ import { Logging } from '../lib/logging.js';
6
+ import { Point } from '../entities/point.js';
7
+ import { AddState } from '../lib/stateManager.js';
8
+ import { Intersection } from '../lib/intersect.js';
9
+
10
+ import { DesignCore } from '../designCore.js';
11
+
12
+ /**
13
+ * Offset Command Class
14
+ * @extends Tool
15
+ */
16
+ export class Offset extends Tool {
17
+ /** Create an Offset command */
18
+ constructor() {
19
+ super();
20
+ this.selectedItem = null;
21
+ }
22
+
23
+ /**
24
+ * Register the command
25
+ * @return {Object}
26
+ * command = name of the command
27
+ * shortcut = shortcut for the command
28
+ * type = type to group command in toolbars (omitted if not shown)
29
+ */
30
+ static register() {
31
+ const command = { command: 'Offset', shortcut: 'O' }; // , type: 'Tool' };
32
+ return command;
33
+ }
34
+
35
+ /**
36
+ * Execute method
37
+ * executes the workflow, requesting input required to perform the command
38
+ */
39
+ async execute() {
40
+ try {
41
+ // Initialise from the last used offset distance stored in headers
42
+ const storedDistance = DesignCore.Scene.headers.offsetDistance;
43
+ const defaultValue = storedDistance > 0 ? storedDistance : undefined;
44
+
45
+ const op = new PromptOptions(Strings.Input.DISTANCE, [Input.Type.NUMBER], ['Through'], defaultValue);
46
+ const distanceInput = await DesignCore.Scene.inputManager.requestInput(op);
47
+ if (distanceInput === undefined) return;
48
+
49
+ const throughMode = Input.getType(distanceInput) === Input.Type.STRING && distanceInput === 'Through';
50
+
51
+ if (throughMode) {
52
+ DesignCore.Scene.headers.offsetDistance = -1;
53
+ } else {
54
+ const distance = distanceInput;
55
+ if (distance <= 0) {
56
+ DesignCore.Core.notify(`${this.type} - ${Strings.Error.NONZERO}`);
57
+ return;
58
+ }
59
+ DesignCore.Scene.headers.offsetDistance = distance;
60
+ }
61
+
62
+ const op2 = new PromptOptions(Strings.Input.SELECT, [Input.Type.SINGLESELECTION]);
63
+ const op3 = new PromptOptions(throughMode ? Strings.Input.THROUGHPOINT : Strings.Input.SIDE, [Input.Type.POINT]);
64
+
65
+ while (true) {
66
+ const preselected = DesignCore.Scene.selectionManager.selectionSet.selectionSet;
67
+ if (preselected.length === 1) {
68
+ this.selectedItem = DesignCore.Scene.entities.get(preselected[0]);
69
+ DesignCore.Scene.selectionManager.reset();
70
+ } else {
71
+ DesignCore.Scene.selectionManager.reset();
72
+ const selection = await DesignCore.Scene.inputManager.requestInput(op2);
73
+ if (selection === undefined) break;
74
+ this.selectedItem = DesignCore.Scene.entities.get(selection.selectedItemIndex);
75
+ DesignCore.Scene.selectionManager.removeLastSelection();
76
+ }
77
+
78
+ const point = await DesignCore.Scene.inputManager.requestInput(op3);
79
+ if (point === undefined) {
80
+ this.selectedItem = null;
81
+ break;
82
+ }
83
+
84
+ if (throughMode) {
85
+ DesignCore.Scene.headers.offsetDistance = this.getThroughDistance(this.selectedItem, point);
86
+ }
87
+ this.points = [point];
88
+ DesignCore.Scene.inputManager.actionCommand();
89
+ this.selectedItem = null;
90
+ }
91
+
92
+ DesignCore.Scene.inputManager.reset();
93
+ } catch (err) {
94
+ Logging.instance.error(`${this.type} - ${err}`);
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Preview the command during execution
100
+ */
101
+ preview() {
102
+ const offsetDistance = DesignCore.Scene.headers.offsetDistance;
103
+ if (this.selectedItem && offsetDistance > 0) {
104
+ const mousePoint = DesignCore.Mouse.pointOnScene();
105
+ const offsetPoints = this.getOffsetPoints(this.selectedItem, mousePoint, offsetDistance);
106
+
107
+ if (offsetPoints) {
108
+ const previewEntity = Utils.cloneObject(this.selectedItem);
109
+ previewEntity.fromPolylinePoints(offsetPoints);
110
+ DesignCore.Scene.tempEntities.add(previewEntity);
111
+ }
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Perform the command
117
+ */
118
+ action() {
119
+ const offsetDistance = DesignCore.Scene.headers.offsetDistance;
120
+ if (!this.selectedItem || offsetDistance <= 0) return;
121
+
122
+ const sidePoint = this.points[0];
123
+ const entity = this.selectedItem;
124
+ const offsetPoints = this.getOffsetPoints(entity, sidePoint, offsetDistance);
125
+
126
+ if (!offsetPoints) {
127
+ Logging.instance.warn(`${this.type}: ${entity.type} ${Strings.Message.CANNOTBEACTIONED}`);
128
+ return;
129
+ }
130
+
131
+ const offsetEntity = Utils.cloneObject(entity);
132
+ offsetEntity.fromPolylinePoints(offsetPoints);
133
+
134
+ const stateChange = new AddState(offsetEntity);
135
+ DesignCore.Scene.commit([stateChange]);
136
+ }
137
+
138
+ /**
139
+ * Get offset points for an entity in polyline point format
140
+ * @param {Object} entity
141
+ * @param {Point} sidePoint
142
+ * @param {number} distance
143
+ * @return {Array|null} offset polyline points or null if unsupported
144
+ */
145
+ getOffsetPoints(entity, sidePoint, distance) {
146
+ if (typeof entity.toPolylinePoints !== 'function') return null;
147
+
148
+ const polyPts = entity.toPolylinePoints();
149
+ if (!polyPts || polyPts.length < 2) return null;
150
+
151
+ const isClosed = polyPts.length >= 3 && polyPts[0].isSame(polyPts.at(-1));
152
+ const points = isClosed ? polyPts.slice(0, -1) : polyPts;
153
+
154
+ return this.getOffsetPolylinePoints(points, isClosed, sidePoint, distance);
155
+ }
156
+
157
+ /**
158
+ * Get offset points for polyline points
159
+ * @param {Array} points
160
+ * @param {boolean} isClosed
161
+ * @param {Point} sidePoint
162
+ * @param {number} distance
163
+ * @return {Array|null} offset points or null if unsupported
164
+ */
165
+ getOffsetPolylinePoints(points, isClosed, sidePoint, distance) {
166
+ const n = points.length;
167
+ if (n < 2) return null;
168
+
169
+ const segCount = isClosed ? n : n - 1;
170
+
171
+ // Determine offset sign from the closest segment to sidePoint.
172
+ // Use the actual distance to the segment (not the infinite-line perpendicular)
173
+ // so that sidePoints projecting beyond a segment endpoint pick the correct segment.
174
+ let sign = 1;
175
+ let minDist = Infinity;
176
+ for (let i = 0; i < segCount; i++) {
177
+ const A = points[i];
178
+ const B = points[(i + 1) % n];
179
+ if (A.bulge === 0) {
180
+ const closestPt = sidePoint.closestPointOnLine(A, B);
181
+ if (closestPt === null) continue;
182
+ const dist = sidePoint.distance(closestPt);
183
+ if (dist < minDist) {
184
+ minDist = dist;
185
+ const dir = B.subtract(A);
186
+ const cross = dir.cross(sidePoint.subtract(A));
187
+ sign = cross >= 0 ? 1 : -1;
188
+ }
189
+ } else {
190
+ const center = A.bulgeCentrePoint(B);
191
+ const currentRadius = center.distance(A);
192
+ const arcDir = A.bulge > 0 ? 1 : -1;
193
+ const closestPt = sidePoint.closestPointOnArc(A, B, center, arcDir);
194
+ if (closestPt === null) continue;
195
+ const dist = sidePoint.distance(closestPt);
196
+ if (dist < minDist) {
197
+ minDist = dist;
198
+ const distToCenter = center.distance(sidePoint);
199
+ // For CCW arc (arcDir>0): left of travel = toward center (smaller radius)
200
+ // For CW arc (arcDir<0): left of travel = away from center (larger radius)
201
+ sign = arcDir > 0 ?
202
+ (distToCenter < currentRadius ? 1 : -1) :
203
+ (distToCenter >= currentRadius ? 1 : -1);
204
+ }
205
+ }
206
+ }
207
+
208
+ // Compute the offset segment data for each segment
209
+ const offsetSegs = [];
210
+ for (let i = 0; i < segCount; i++) {
211
+ const A = points[i];
212
+ const B = points[(i + 1) % n];
213
+ if (A.bulge === 0) {
214
+ const dir = B.subtract(A);
215
+ const normal = new Point(-dir.y, dir.x).normalise();
216
+ const offset = normal.scale(distance * sign);
217
+ offsetSegs.push({
218
+ type: 'line',
219
+ A: A.add(offset),
220
+ B: B.add(offset),
221
+ bulge: 0,
222
+ });
223
+ } else {
224
+ const center = A.bulgeCentrePoint(B);
225
+ const currentRadius = center.distance(A);
226
+ const arcDir = A.bulge > 0 ? 1 : -1;
227
+ const newRadius = currentRadius - arcDir * distance * sign;
228
+ if (newRadius <= 0) return null;
229
+ const startAngle = Math.atan2(A.y - center.y, A.x - center.x);
230
+ const endAngle = Math.atan2(B.y - center.y, B.x - center.x);
231
+ offsetSegs.push({
232
+ type: 'arc',
233
+ A: new Point(center.x + newRadius * Math.cos(startAngle), center.y + newRadius * Math.sin(startAngle)),
234
+ B: new Point(center.x + newRadius * Math.cos(endAngle), center.y + newRadius * Math.sin(endAngle)),
235
+ bulge: A.bulge,
236
+ center,
237
+ radius: newRadius,
238
+ });
239
+ }
240
+ }
241
+
242
+ const newPoints = [];
243
+ if (!isClosed) {
244
+ newPoints.push(new Point(offsetSegs[0].A.x, offsetSegs[0].A.y, offsetSegs[0].bulge));
245
+ for (let i = 0; i < segCount - 1; i++) {
246
+ const junction = this.findJunction(offsetSegs[i], offsetSegs[i + 1]);
247
+ newPoints.push(new Point(junction.x, junction.y, offsetSegs[i + 1].bulge));
248
+ }
249
+ newPoints.push(new Point(offsetSegs[segCount - 1].B.x, offsetSegs[segCount - 1].B.y, 0));
250
+ } else {
251
+ for (let i = 0; i < segCount; i++) {
252
+ const nextSeg = offsetSegs[(i + 1) % segCount];
253
+ const junction = this.findJunction(offsetSegs[i], nextSeg);
254
+ newPoints.push(new Point(junction.x, junction.y, nextSeg.bulge));
255
+ }
256
+ }
257
+
258
+ return newPoints;
259
+ }
260
+
261
+ /**
262
+ * Find the junction point between two consecutive offset segments
263
+ * @param {Object} seg
264
+ * @param {Object} nextSeg
265
+ * @return {Point}
266
+ */
267
+ findJunction(seg, nextSeg) {
268
+ const midpoint = new Point((seg.B.x + nextSeg.A.x) / 2, (seg.B.y + nextSeg.A.y) / 2);
269
+
270
+ const segA = new Point(seg.A.x, seg.A.y, seg.bulge);
271
+ const segB = new Point(seg.B.x, seg.B.y);
272
+ const nextA = new Point(nextSeg.A.x, nextSeg.A.y, nextSeg.bulge);
273
+ const nextB = new Point(nextSeg.B.x, nextSeg.B.y);
274
+
275
+ const result = Intersection.intersectSegmentSegment(segA, segB, nextA, nextB, true, true);
276
+ const candidates = result.points;
277
+
278
+ if (candidates.length === 0) return midpoint;
279
+ if (candidates.length === 1) return candidates[0];
280
+
281
+ return candidates[0].distance(midpoint) <= candidates[1].distance(midpoint) ? candidates[0] : candidates[1];
282
+ }
283
+
284
+ /**
285
+ * Calculate through distance from entity to through point
286
+ * @param {Object} entity
287
+ * @param {Point} throughPoint
288
+ * @return {number} distance
289
+ */
290
+ getThroughDistance(entity, throughPoint) {
291
+ if (typeof entity.toPolylinePoints !== 'function') return 0;
292
+
293
+ const polyPts = entity.toPolylinePoints();
294
+ if (!polyPts || polyPts.length < 2) return 0;
295
+
296
+ const isClosed = polyPts.length >= 3 && polyPts[0].isSame(polyPts.at(-1));
297
+ const points = isClosed ? polyPts.slice(0, -1) : polyPts;
298
+ const n = points.length;
299
+ const segCount = isClosed ? n : n - 1;
300
+
301
+ let minDist = Infinity;
302
+
303
+ for (let i = 0; i < segCount; i++) {
304
+ const A = points[i];
305
+ const B = points[(i + 1) % n];
306
+
307
+ if (A.bulge === 0) {
308
+ const closest = throughPoint.perpendicular(A, B);
309
+ const dist = throughPoint.distance(closest);
310
+ if (dist < minDist) minDist = dist;
311
+ } else {
312
+ const center = A.bulgeCentrePoint(B);
313
+ const radius = center.distance(A);
314
+ const dist = Math.abs(center.distance(throughPoint) - radius);
315
+ if (dist < minDist) minDist = dist;
316
+ }
317
+ }
318
+
319
+ return minDist === Infinity ? 0 : minDist;
320
+ }
321
+ }
@@ -0,0 +1,54 @@
1
+ import { Tool } from './tool.js';
2
+ import { Input, PromptOptions } from '../lib/inputManager.js';
3
+ import { Logging } from '../lib/logging.js';
4
+ import { DesignCore } from '../designCore.js';
5
+
6
+ /**
7
+ * Pan Command Class
8
+ * @extends Tool
9
+ */
10
+ export class Pan extends Tool {
11
+ /** Create a Pan command */
12
+ constructor() {
13
+ super();
14
+ this.panning = false;
15
+ }
16
+
17
+ /**
18
+ * Register the command
19
+ * @return {Object}
20
+ */
21
+ static register() {
22
+ const command = { command: 'Pan', shortcut: 'P' };
23
+ return command;
24
+ }
25
+
26
+ /**
27
+ * Execute method
28
+ */
29
+ async execute() {
30
+ try {
31
+ while (DesignCore.Scene.inputManager.activeCommand) {
32
+ const down = await DesignCore.Scene.inputManager.requestInput(new PromptOptions('', [Input.Type.MOUSEDOWN], [], undefined, Input.Cursor.GRAB));
33
+ if (down === undefined) return;
34
+ this.panning = true;
35
+ const up = await DesignCore.Scene.inputManager.requestInput(new PromptOptions('', [Input.Type.MOUSEUP], [], undefined, Input.Cursor.GRABBING));
36
+ this.panning = false;
37
+ if (up === undefined) return;
38
+ }
39
+ } catch (err) {
40
+ Logging.instance.error(`${this.type} - ${err}`);
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Preview the command during execution
46
+ */
47
+ preview() {
48
+ if (this.panning) {
49
+ DesignCore.Canvas.pan();
50
+ }
51
+ }
52
+ }
53
+
54
+
@@ -0,0 +1,93 @@
1
+ import { Utils } from '../lib/utils.js';
2
+ import { Strings } from '../lib/strings.js';
3
+ import { Tool } from './tool.js';
4
+ import { Input, PromptOptions } from '../lib/inputManager.js';
5
+ import { Logging } from '../lib/logging.js';
6
+ import { Point } from '../entities/point.js';
7
+ import { AddState } from '../lib/stateManager.js';
8
+
9
+ import { DesignCore } from '../designCore.js';
10
+
11
+ /**
12
+ * Pasteclip Command Class
13
+ * @extends Tool
14
+ */
15
+ export class Pasteclip extends Tool {
16
+ /** Create a Pasteclip command */
17
+ constructor() {
18
+ super();
19
+ }
20
+
21
+ /**
22
+ * Register the command
23
+ * @return {Object}
24
+ * command = name of the command
25
+ * shortcut = shortcut for the command
26
+ * type = type to group command in toolbars (omitted if not shown)
27
+ */
28
+ static register() {
29
+ const command = { command: 'Pasteclip', shortcut: 'PASTECLIP' };
30
+ return command;
31
+ }
32
+
33
+ /**
34
+ * Execute method
35
+ * executes the workflow, requesting input required to perform the command
36
+ */
37
+ async execute() {
38
+ try {
39
+ if (!DesignCore.Clipboard.isValid) {
40
+ throw new Error(Strings.Error.INVALIDCLIPBOARD);
41
+ }
42
+
43
+ const op2 = new PromptOptions(Strings.Input.BASEPOINT, [Input.Type.POINT]);
44
+ const pt1 = await DesignCore.Scene.inputManager.requestInput(op2);
45
+ this.points.push(pt1);
46
+
47
+ DesignCore.Scene.inputManager.executeCommand();
48
+ } catch (err) {
49
+ Logging.instance.error(`${this.type} - ${err}`);
50
+ DesignCore.Scene.inputManager.reset();
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Preview the command during execution
56
+ */
57
+ preview() {
58
+ // get the mouse position
59
+ const mousePosition = DesignCore.Mouse.pointOnScene();
60
+ const basePoint = DesignCore.Clipboard.BasePoint;
61
+ const delta = mousePosition.subtract(basePoint);
62
+
63
+ for (const entity of DesignCore.Clipboard.Entities) {
64
+ const tempEntity = Utils.cloneObject(entity);
65
+ const offsetPoints = tempEntity.points.map((p) => new Point(p.x, p.y, p.bulge, p.sequence).add(delta));
66
+ tempEntity.setProperty('points', offsetPoints);
67
+ DesignCore.Scene.tempEntities.add(tempEntity);
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Perform the command
73
+ */
74
+ action() {
75
+ const stateChanges = [];
76
+
77
+ // get the mouse position
78
+ const mousePosition = this.points[0];
79
+ const basePoint = DesignCore.Clipboard.BasePoint;
80
+ const delta = mousePosition.subtract(basePoint);
81
+
82
+ for (const entity of DesignCore.Clipboard.Entities) {
83
+ const pastedEntity = Utils.cloneObject(entity);
84
+ const offsetPoints = pastedEntity.points.map((p) => new Point(p.x, p.y, p.bulge, p.sequence).add(delta));
85
+ pastedEntity.setProperty('points', offsetPoints);
86
+
87
+ const stateChange = new AddState(pastedEntity);
88
+ stateChanges.push(stateChange);
89
+ }
90
+
91
+ DesignCore.Scene.commit(stateChanges);
92
+ }
93
+ }
@@ -0,0 +1,90 @@
1
+ import { Strings } from '../lib/strings.js';
2
+ import { Tool } from './tool.js';
3
+ import { PromptOptions } from '../lib/inputManager.js';
4
+ import { Logging } from '../lib/logging.js';
5
+
6
+ import { DesignCore } from '../designCore.js';
7
+
8
+ /**
9
+ * Purge Command Class
10
+ * @extends Tool
11
+ */
12
+ export class Purge extends Tool {
13
+ /** Create a Purge command */
14
+ constructor() {
15
+ super();
16
+ this.option = '';
17
+ this.options = ['Blocks', 'Dimstyles', 'Layers', 'LTypes', 'All'];
18
+ }
19
+
20
+ /**
21
+ * Register the command
22
+ * @return {Object}
23
+ * command = name of the command
24
+ * shortcut = shortcut for the command
25
+ * type = type to group command in toolbars (omitted if not shown)
26
+ */
27
+ static register() {
28
+ const command = { command: 'Purge', shortcut: 'PU' };
29
+ return command;
30
+ }
31
+
32
+ /**
33
+ * Execute method
34
+ * executes the workflow, requesting input required to perform the command
35
+ */
36
+ async execute() {
37
+ try {
38
+ const op = new PromptOptions(Strings.Input.OPTION, [], this.options, this.options[3]);
39
+ this.option = await DesignCore.Scene.inputManager.requestInput(op);
40
+
41
+ DesignCore.Scene.inputManager.executeCommand();
42
+ } catch (err) {
43
+ Logging.instance.error(`${this.type} - ${err}`);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Preview the command during execution
49
+ */
50
+ preview() {
51
+ // No Preview
52
+ }
53
+
54
+ /**
55
+ * Perform the command
56
+ */
57
+ action() {
58
+ let purgedCount = 0;
59
+
60
+ if (this.option === 'Blocks' || this.option === 'All') {
61
+ const intialitemCount = DesignCore.Scene.blockManager.itemCount();
62
+ DesignCore.Scene.blockManager.purge();
63
+ const finalitemCount = DesignCore.Scene.blockManager.itemCount();
64
+ purgedCount += (intialitemCount - finalitemCount);
65
+ }
66
+
67
+ if (this.option === 'Dimstyles' || this.option === 'All') {
68
+ const intialitemCount = DesignCore.DimStyleManager.itemCount();
69
+ DesignCore.DimStyleManager.purge();
70
+ const finalitemCount = DesignCore.DimStyleManager.itemCount();
71
+ purgedCount += (intialitemCount - finalitemCount);
72
+ }
73
+
74
+ if (this.option === 'Layers' || this.option === 'All') {
75
+ const intialLayerCount = DesignCore.LayerManager.itemCount();
76
+ DesignCore.LayerManager.purge();
77
+ const finalLayerCount = DesignCore.LayerManager.itemCount();
78
+ purgedCount += (intialLayerCount - finalLayerCount);
79
+ }
80
+
81
+ if (this.option === 'LTypes' || this.option === 'All') {
82
+ const intialLTypeCount = DesignCore.LTypeManager.itemCount();
83
+ DesignCore.LTypeManager.purge();
84
+ const finalLTypeCount = DesignCore.LTypeManager.itemCount();
85
+ purgedCount += (intialLTypeCount - finalLTypeCount);
86
+ }
87
+
88
+ DesignCore.Core.notify(`${this.type} - ${this.option}: ${purgedCount} ${Strings.Strings.ITEMS} ${Strings.Strings.REMOVED}`);
89
+ }
90
+ }