@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.
- package/.eslintrc.json +14 -7
- package/.github/workflows/DesignCoreQA.yml +3 -1
- package/README.md +11 -4
- package/TODO.md +19 -0
- package/core/core/core.js +49 -42
- package/core/designCore.js +61 -2
- package/core/dimensions/alignedDimension.js +142 -0
- package/core/dimensions/angularDimension.js +550 -0
- package/core/dimensions/baseCircularDimension.js +244 -0
- package/core/dimensions/baseDimension.js +558 -0
- package/core/dimensions/baseLinearDimension.js +371 -0
- package/core/dimensions/diametricDimension.js +82 -0
- package/core/dimensions/dimension.js +298 -0
- package/core/dimensions/linearDimension.js +29 -0
- package/core/dimensions/radialDimension.js +78 -0
- package/core/dimensions/rotatedDimension.js +167 -0
- package/core/entities/arc.js +314 -60
- package/core/entities/arctext.js +642 -0
- package/core/entities/basePolyline.js +553 -94
- package/core/entities/circle.js +181 -54
- package/core/entities/entity.js +154 -74
- package/core/entities/hatch.js +807 -0
- package/core/entities/insert.js +200 -39
- package/core/entities/line.js +196 -134
- package/core/entities/lwpolyline.js +21 -44
- package/core/entities/point.js +194 -29
- package/core/entities/polyline.js +54 -7
- package/core/entities/rectangle.js +43 -13
- package/core/entities/solid.js +43 -6
- package/core/entities/text.js +324 -181
- package/core/lib/boundingBox.js +73 -13
- package/core/lib/canvas.js +256 -65
- package/core/lib/clipboard.js +198 -0
- package/core/lib/colour.js +144 -0
- package/core/lib/colours.js +367 -301
- package/core/lib/commandLine.js +16 -28
- package/core/lib/commandManager.js +115 -58
- package/core/lib/constants.js +23 -0
- package/core/lib/dxf/dxf.js +249 -34
- package/core/lib/dxf/dxfFile.js +23 -38
- package/core/lib/dxf/dxfIterator.js +17 -5
- package/core/lib/dxf/dxfRead.js +23 -7
- package/core/lib/dxf/dxfWrite.js +39 -129
- package/core/lib/dxf/handleManager.js +97 -0
- package/core/lib/dxf/sections/blocks.js +16 -2
- package/core/lib/dxf/sections/entities.js +17 -3
- package/core/lib/dxf/sections/header.js +10 -1
- package/core/lib/dxf/sections/objects.js +36 -0
- package/core/lib/dxf/sections/section.js +43 -5
- package/core/lib/dxf/sections/tables.js +17 -3
- package/core/lib/entityManager.js +178 -0
- package/core/lib/fileio.js +14 -4
- package/core/lib/headers.js +229 -0
- package/core/lib/input.js +46 -0
- package/core/lib/inputManager.js +199 -194
- package/core/lib/intersect.js +341 -468
- package/core/lib/logging.js +25 -1
- package/core/lib/matrix.js +6 -8
- package/core/lib/mouse.js +24 -79
- package/core/lib/patterns.js +690 -0
- package/core/lib/promptOptions.js +133 -0
- package/core/lib/scene.js +71 -174
- package/core/lib/selectionManager.js +74 -48
- package/core/lib/selectionWindow.js +24 -10
- package/core/lib/settings.js +18 -11
- package/core/lib/snapping.js +129 -21
- package/core/lib/stateManager.js +288 -0
- package/core/lib/strings.js +57 -5
- package/core/lib/utils.js +95 -11
- package/core/objects/dictionary.js +43 -0
- package/core/objects/dictionaryManager.js +80 -0
- package/core/properties/dimType.js +117 -0
- package/core/properties/flags.js +66 -0
- package/core/properties/property.js +26 -0
- package/core/properties/propertyManager.js +65 -19
- package/core/tables/appId.js +31 -0
- package/core/tables/appIdManager.js +44 -0
- package/core/tables/block.js +323 -0
- package/core/tables/blockManager.js +48 -0
- package/core/tables/blockRecord.js +29 -0
- package/core/tables/blockRecordManager.js +37 -0
- package/core/tables/dimStyle.js +627 -0
- package/core/tables/dimStyleManager.js +187 -0
- package/core/tables/endblk.js +28 -0
- package/core/tables/layer.js +219 -0
- package/core/tables/layerManager.js +47 -0
- package/core/tables/ltype.js +85 -0
- package/core/tables/ltypeManager.js +65 -0
- package/core/tables/style.js +145 -0
- package/core/tables/styleManager.js +55 -0
- package/core/tables/styleManagerBase.js +110 -0
- package/core/tables/tableManagerBase.js +354 -0
- package/core/tables/ucs.js +28 -0
- package/core/tables/ucsManager.js +44 -0
- package/core/tables/view.js +28 -0
- package/core/tables/viewManager.js +44 -0
- package/core/tables/vport.js +70 -0
- package/core/tables/vportManager.js +65 -0
- package/core/tools/chamfer.js +343 -0
- package/core/tools/chamferFilletBase.js +162 -0
- package/core/tools/copy.js +68 -40
- package/core/tools/copybase.js +65 -0
- package/core/tools/copyclip.js +59 -0
- package/core/tools/cornerEntity.js +138 -0
- package/core/tools/cutclip.js +72 -0
- package/core/tools/distance.js +37 -9
- package/core/tools/erase.js +43 -13
- package/core/tools/explode.js +117 -0
- package/core/tools/extend.js +71 -32
- package/core/tools/fillet.js +336 -0
- package/core/tools/identify.js +33 -6
- package/core/tools/matchProp.js +106 -0
- package/core/tools/mirror.js +141 -0
- package/core/tools/move.js +65 -32
- package/core/tools/offset.js +321 -0
- package/core/tools/pan.js +54 -0
- package/core/tools/pasteclip.js +93 -0
- package/core/tools/purge.js +90 -0
- package/core/tools/rotate.js +105 -70
- package/core/tools/scale.js +166 -0
- package/core/tools/tool.js +14 -4
- package/core/tools/trim.js +71 -32
- package/core/tools/zoom.js +152 -0
- package/package.json +3 -305
- package/test/dimensions/alignedDimension.test.js +211 -0
- package/test/dimensions/angularDimension.test.js +243 -0
- package/test/dimensions/baseDimension.test.js +239 -0
- package/test/dimensions/diametricDimension.test.js +203 -0
- package/test/dimensions/dimension.test.js +102 -0
- package/test/dimensions/radialDimension.test.js +203 -0
- package/test/dimensions/rotatedDimension.test.js +224 -0
- package/test/entities/arc.test.js +463 -41
- package/test/entities/arctext.test.js +329 -0
- package/test/entities/basePolyline.test.js +459 -10
- package/test/entities/circle.test.js +312 -7
- package/test/entities/entity.test.js +28 -9
- package/test/entities/hatch.test.js +606 -0
- package/test/entities/insert.test.js +90 -0
- package/test/entities/line.test.js +182 -6
- package/test/entities/point.test.js +375 -37
- package/test/entities/solid.test.js +156 -0
- package/test/entities/text.test.js +533 -7
- package/test/integration/exportIntegration.reference.dxf +1706 -0
- package/test/integration/exportIntegration.test.js +186 -0
- package/test/integration/importExportIntegration.test.js +126 -0
- package/test/integration/intersectionIntegration.test.js +880 -0
- package/test/integration/userInputIntegration.reference.dxf +1410 -0
- package/test/integration/userInputIntegration.test.js +269 -0
- package/test/lib/boundingBox.test.js +26 -2
- package/test/lib/canvas.test.js +613 -5
- package/test/lib/clipboard.test.js +70 -0
- package/test/lib/colour.test.js +114 -0
- package/test/lib/colours.test.js +63 -18
- package/test/lib/commandLine.test.js +159 -22
- package/test/lib/commandManager.test.js +4 -4
- package/test/lib/constants.test.js +9 -0
- package/test/lib/dxf/dxfFile.test.js +6 -2
- package/test/lib/dxf/dxfIterator.test.js +1 -1
- package/test/lib/dxf/dxfWrite.test.js +173 -0
- package/test/lib/dxf/handleManager.test.js +137 -0
- package/test/lib/dxf/sections/blocks.test.js +5 -5
- package/test/lib/dxf/sections/entities.test.js +4 -4
- package/test/lib/dxf/sections/header.test.js +18 -4
- package/test/lib/dxf/sections/objects.test.js +132 -0
- package/test/lib/dxf/sections/section.test.js +29 -29
- package/test/lib/dxf/sections/tables.test.js +3 -3
- package/test/lib/entityManager.test.js +163 -0
- package/test/lib/headers.test.js +233 -0
- package/test/lib/inputManager.test.js +1144 -5
- package/test/lib/intersect.test.js +454 -331
- package/test/lib/logging.test.js +1 -1
- package/test/lib/matrix.test.js +1 -1
- package/test/lib/mouse.test.js +327 -4
- package/test/lib/patterns.test.js +105 -0
- package/test/lib/promptOptions.test.js +179 -0
- package/test/lib/scene.test.js +16 -52
- package/test/lib/selectionManager.test.js +17 -5
- package/test/lib/settings.test.js +111 -5
- package/test/lib/snapping.test.js +142 -4
- package/test/lib/stateManager.test.js +155 -0
- package/test/lib/utils.test.js +81 -1
- package/test/objects/dictionary.test.js +81 -0
- package/test/objects/dictionaryManager.test.js +34 -0
- package/test/properties/dimType.test.js +62 -0
- package/test/properties/flags.test.js +164 -0
- package/test/properties/property.test.js +13 -0
- package/test/properties/propertyManager.test.js +10 -11
- package/test/tables/appId.test.js +46 -0
- package/test/tables/appIdManager.test.js +72 -0
- package/test/tables/block.test.js +157 -0
- package/test/tables/blockManager.test.js +52 -0
- package/test/tables/blockRecord.test.js +39 -0
- package/test/tables/blockRecordManager.test.js +60 -0
- package/test/tables/dimstyle.test.js +72 -0
- package/test/tables/endblk.test.js +30 -0
- package/test/tables/layer.test.js +95 -0
- package/test/tables/layerManager.test.js +172 -0
- package/test/{styles → tables}/ltype.test.js +7 -7
- package/test/{styles → tables}/ltypeManager.test.js +2 -2
- package/test/tables/style.test.js +44 -0
- package/test/tables/stylemanagerbase.test.js +220 -0
- package/test/tables/tableManagerBase.test.js +194 -0
- package/test/tables/ucs.test.js +37 -0
- package/test/tables/ucsManager.test.js +48 -0
- package/test/tables/view.test.js +37 -0
- package/test/tables/viewManager.test.js +48 -0
- package/test/tables/vport.test.js +117 -0
- package/test/tables/vportManager.test.js +54 -0
- package/test/test-helpers/test-helpers.js +66 -0
- package/test/tools/chamfer.test.js +970 -0
- package/test/tools/chamferFilletBase.test.js +446 -0
- package/test/tools/copy.test.js +22 -14
- package/test/tools/copybase.test.js +93 -0
- package/test/tools/copyclip.test.js +92 -0
- package/test/tools/cornerEntity.test.js +201 -0
- package/test/tools/cutclip.test.js +94 -0
- package/test/tools/distance.test.js +140 -18
- package/test/tools/erase.test.js +12 -12
- package/test/tools/explode.test.js +45 -0
- package/test/tools/extend.test.js +326 -44
- package/test/tools/fillet.test.js +831 -0
- package/test/tools/identify.test.js +115 -16
- package/test/tools/matchProp.test.js +84 -0
- package/test/tools/mirror.test.js +475 -0
- package/test/tools/move.test.js +75 -19
- package/test/tools/offset.test.js +748 -0
- package/test/tools/pan.test.js +72 -0
- package/test/tools/pasteclip.test.js +100 -0
- package/test/tools/purge.test.js +89 -0
- package/test/tools/rotate.test.js +89 -23
- package/test/tools/scale.test.js +529 -0
- package/test/tools/trim.test.js +419 -84
- package/test/tools/zoom.test.js +504 -0
- package/core/entities/alignedDimension.js +0 -279
- package/core/entities/angularDimension.js +0 -194
- package/core/entities/baseDimension.js +0 -227
- package/core/entities/block.js +0 -247
- package/core/entities/diametricDimension.js +0 -133
- package/core/entities/dimension.js +0 -202
- package/core/entities/radialDimension.js +0 -126
- package/core/styles/dimStyle.js +0 -719
- package/core/styles/dimStyleManager.js +0 -47
- package/core/styles/layer.js +0 -133
- package/core/styles/layerManager.js +0 -40
- package/core/styles/ltype.js +0 -86
- package/core/styles/ltypeManager.js +0 -50
- package/core/styles/style.js +0 -158
- package/core/styles/styleManager.js +0 -43
- package/core/styles/styleManagerBase.js +0 -299
- package/test/entities/block.test.js +0 -22
- package/test/styles/dimstyle.test.js +0 -19
- package/test/styles/layerManager.test.js +0 -150
- package/test/styles/style.test.js +0 -33
- package/test/styles/stylemanagerbase.test.js +0 -219
|
@@ -1,17 +1,25 @@
|
|
|
1
|
-
import {Strings} from '../lib/strings.js';
|
|
2
|
-
import {DesignCore} from '../designCore.js';
|
|
1
|
+
import { Strings } from '../lib/strings.js';
|
|
2
|
+
import { DesignCore } from '../designCore.js';
|
|
3
|
+
import { UpdateState } from '../lib/stateManager.js';
|
|
3
4
|
|
|
5
|
+
/** Property Manager Class */
|
|
4
6
|
export class PropertyManager {
|
|
7
|
+
/** Create Property Manager */
|
|
5
8
|
constructor() {
|
|
6
9
|
this.updateCallbackFunction; // set to external callback function
|
|
7
10
|
}
|
|
8
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Set the property callback function
|
|
14
|
+
* @param {Object} callback
|
|
15
|
+
*/
|
|
9
16
|
setPropertyCallbackFunction(callback) {
|
|
10
17
|
// set the call
|
|
11
18
|
this.updateCallbackFunction = callback;
|
|
12
19
|
}
|
|
13
20
|
|
|
14
21
|
|
|
22
|
+
/** Signal the selection set has changed */
|
|
15
23
|
selectionSetChanged() {
|
|
16
24
|
// If a callback is set - signal that a change has been made
|
|
17
25
|
if (this.updateCallbackFunction) {
|
|
@@ -19,29 +27,55 @@ export class PropertyManager {
|
|
|
19
27
|
}
|
|
20
28
|
}
|
|
21
29
|
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Set item properties
|
|
32
|
+
* @param {string} property
|
|
33
|
+
* @param {any} newPropertyValue
|
|
34
|
+
* @param {string} itemType
|
|
35
|
+
*/
|
|
36
|
+
setItemProperties(property, newPropertyValue, itemType='All') {
|
|
37
|
+
const stateChanges = [];
|
|
38
|
+
for (let i = 0; i < DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
|
|
39
|
+
const index = DesignCore.Scene.selectionManager.selectionSet.selectionSet[i];
|
|
40
|
+
|
|
41
|
+
const item = DesignCore.Scene.entities.get(index);
|
|
42
|
+
|
|
43
|
+
// check if the item is of the selected type
|
|
44
|
+
if (itemType !== 'All' && item.type !== itemType) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
24
48
|
// check if the item has the selected property
|
|
25
|
-
if (!
|
|
49
|
+
if (!item.hasOwnProperty(property)) {
|
|
26
50
|
continue;
|
|
27
51
|
}
|
|
28
52
|
|
|
29
|
-
if (typeof(
|
|
53
|
+
if (typeof (item[property]) !== typeof (newPropertyValue)) {
|
|
30
54
|
DesignCore.Core.notify(Strings.Error.INPUT);
|
|
31
55
|
} else {
|
|
32
|
-
|
|
33
|
-
|
|
56
|
+
// update the item property
|
|
57
|
+
const update = {};
|
|
58
|
+
update[property] = newPropertyValue;
|
|
59
|
+
const stateChange = new UpdateState(item, update);
|
|
60
|
+
stateChanges.push(stateChange);
|
|
34
61
|
}
|
|
35
62
|
}
|
|
63
|
+
DesignCore.Scene.commit(stateChanges);
|
|
64
|
+
DesignCore.Scene.selectionManager.reloadSelectedItems();
|
|
36
65
|
}
|
|
37
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Get the types of items selected
|
|
69
|
+
* @return {Array}
|
|
70
|
+
*/
|
|
38
71
|
getItemTypes() {
|
|
39
72
|
// Loop through the items and get a list of item types.
|
|
40
73
|
const itemTypes = [];
|
|
41
74
|
|
|
42
75
|
if (DesignCore.Scene.selectionManager.selectionSet.selectionSet.length > 0) {
|
|
43
|
-
for (let i = 0; i <DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
|
|
44
|
-
const
|
|
76
|
+
for (let i = 0; i < DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
|
|
77
|
+
const item = DesignCore.Scene.entities.get(DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]);
|
|
78
|
+
const itemType = item.type;
|
|
45
79
|
|
|
46
80
|
if (itemTypes.indexOf(itemType, 0) === -1) {
|
|
47
81
|
itemTypes.push(itemType);
|
|
@@ -57,11 +91,16 @@ export class PropertyManager {
|
|
|
57
91
|
return itemTypes;
|
|
58
92
|
}
|
|
59
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Get a list of common propertie
|
|
96
|
+
* @param {string} itemType
|
|
97
|
+
* @return {Array}
|
|
98
|
+
*/
|
|
60
99
|
getItemProperties(itemType) {
|
|
61
100
|
// Loop through the items and get a list of common properties.
|
|
62
101
|
|
|
63
102
|
// check for valid itemType and selectionSet
|
|
64
|
-
if (itemType === undefined || itemType === null ||DesignCore.Scene.selectionManager.selectionSet.selectionSet.length <= 0) {
|
|
103
|
+
if (itemType === undefined || itemType === null || DesignCore.Scene.selectionManager.selectionSet.selectionSet.length <= 0) {
|
|
65
104
|
return;
|
|
66
105
|
}
|
|
67
106
|
|
|
@@ -69,7 +108,7 @@ export class PropertyManager {
|
|
|
69
108
|
|
|
70
109
|
// create subset array of selectionSet
|
|
71
110
|
DesignCore.Scene.selectionManager.selectionSet.selectionSet.forEach((index) => {
|
|
72
|
-
subset.push(DesignCore.Scene.
|
|
111
|
+
subset.push(DesignCore.Scene.entities.get(index));
|
|
73
112
|
});
|
|
74
113
|
|
|
75
114
|
// get a subset of the selectionSet
|
|
@@ -81,11 +120,11 @@ export class PropertyManager {
|
|
|
81
120
|
|
|
82
121
|
subset.forEach((el) => {
|
|
83
122
|
// get list of keys
|
|
84
|
-
Object.keys(el).forEach(
|
|
123
|
+
Object.keys(el).forEach((key) => {
|
|
85
124
|
// check if the key is already in the propertiesList
|
|
86
125
|
if (propertiesList.includes(key) === false) {
|
|
87
|
-
|
|
88
|
-
if (subset.every((el) => el.hasOwnProperty(key))) {
|
|
126
|
+
// check if all subset items contain the key and the key is enumberable
|
|
127
|
+
if (subset.every((el) => el.hasOwnProperty(key) && Object.getOwnPropertyDescriptor(el, key).enumerable)) {
|
|
89
128
|
propertiesList.push(key);
|
|
90
129
|
}
|
|
91
130
|
}
|
|
@@ -96,19 +135,26 @@ export class PropertyManager {
|
|
|
96
135
|
}
|
|
97
136
|
|
|
98
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Get a list the property values
|
|
140
|
+
* @param {string} itemType
|
|
141
|
+
* @param {string} property
|
|
142
|
+
* @return {Array}
|
|
143
|
+
*/
|
|
99
144
|
getItemPropertyValue(itemType, property) {
|
|
100
145
|
// Loop through the items and get a list the property values
|
|
101
146
|
const propertiesValueList = [];
|
|
102
147
|
if (DesignCore.Scene.selectionManager.selectionSet.selectionSet.length > 0) {
|
|
103
|
-
for (let i = 0; i <DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
|
|
104
|
-
if (DesignCore.Scene.
|
|
105
|
-
const prop = DesignCore.Scene.
|
|
148
|
+
for (let i = 0; i < DesignCore.Scene.selectionManager.selectionSet.selectionSet.length; i++) {
|
|
149
|
+
if (DesignCore.Scene.entities.get(DesignCore.Scene.selectionManager.selectionSet.selectionSet[i]).type === itemType || itemType === 'All') {
|
|
150
|
+
const prop = DesignCore.Scene.entities.get(DesignCore.Scene.selectionManager.selectionSet.selectionSet[i])[property];
|
|
106
151
|
propertiesValueList.push(prop);
|
|
107
152
|
}
|
|
108
153
|
}
|
|
109
154
|
}
|
|
110
155
|
|
|
111
|
-
if
|
|
156
|
+
// Check if every item in the selection set has the same value for the property
|
|
157
|
+
if (propertiesValueList.every((prop) => {
|
|
112
158
|
return prop === propertiesValueList[0];
|
|
113
159
|
})) {
|
|
114
160
|
return propertiesValueList[0];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DXFFile } from '../lib/dxf/dxfFile.js';
|
|
2
|
+
import { Property } from '../properties/property.js';
|
|
3
|
+
|
|
4
|
+
/** AppID Class */
|
|
5
|
+
export class AppID {
|
|
6
|
+
/**
|
|
7
|
+
* Create an AppID
|
|
8
|
+
* @param {Object} data
|
|
9
|
+
*/
|
|
10
|
+
constructor(data) {
|
|
11
|
+
// DXF Groupcode 5 - Handle
|
|
12
|
+
this.handle = Property.loadValue([data?.handle, data?.[5]]);
|
|
13
|
+
// DXF Groupcode 2 - Name
|
|
14
|
+
this.name = Property.loadValue([data?.name, data?.[2]], '');
|
|
15
|
+
// DXF Groupcode 70 - Flags
|
|
16
|
+
this.flags = Property.loadValue([data?.flags, data?.[70]], 0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Write the item to file in the dxf format
|
|
21
|
+
* @param {DXFFile} file
|
|
22
|
+
*/
|
|
23
|
+
dxf(file) {
|
|
24
|
+
file.writeGroupCode('0', 'APPID', DXFFile.Version.R2000);
|
|
25
|
+
file.writeGroupCode('5', this.handle, DXFFile.Version.R2000);
|
|
26
|
+
file.writeGroupCode('100', 'AcDbSymbolTableRecord', DXFFile.Version.R2000);
|
|
27
|
+
file.writeGroupCode('100', 'AcDbRegAppTableRecord', DXFFile.Version.R2000);
|
|
28
|
+
file.writeGroupCode('2', this.name, DXFFile.Version.R2000);
|
|
29
|
+
file.writeGroupCode('70', this.flags.toString(), DXFFile.Version.R2000);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { DXFFile } from '../lib/dxf/dxfFile.js';
|
|
2
|
+
import { TableManagerBase } from './tableManagerBase.js';
|
|
3
|
+
import { AppID } from './appId.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* AppIDManager Class
|
|
7
|
+
* @extends TableManagerBase
|
|
8
|
+
*/
|
|
9
|
+
export class AppIDManager extends TableManagerBase {
|
|
10
|
+
/** Create an AppIDManager */
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
|
|
14
|
+
this.indelibleItems.push('ACAD');
|
|
15
|
+
this.itemProperty = 'appid';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Get the item class */
|
|
19
|
+
get itemClass() {
|
|
20
|
+
return AppID;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Add standard items */
|
|
24
|
+
addStandardItems() {
|
|
25
|
+
this.addItem({ 'name': 'ACAD' });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Write the table to file in the dxf format
|
|
30
|
+
* @param {DXFFile} file
|
|
31
|
+
*/
|
|
32
|
+
dxf(file) {
|
|
33
|
+
file.writeGroupCode('0', 'TABLE', DXFFile.Version.R2000);
|
|
34
|
+
file.writeGroupCode('2', 'APPID', DXFFile.Version.R2000);
|
|
35
|
+
file.writeGroupCode('5', this.handle, DXFFile.Version.R2000);
|
|
36
|
+
file.writeGroupCode('100', 'AcDbSymbolTable', DXFFile.Version.R2000);
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < this.itemCount(); i++) {
|
|
39
|
+
this.getItemByIndex(i).dxf(file);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
file.writeGroupCode('0', 'ENDTAB', DXFFile.Version.R2000);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { Point } from '../entities/point.js';
|
|
2
|
+
import { Entity } from '../entities/entity.js';
|
|
3
|
+
import { EndBlock } from './endblk.js';
|
|
4
|
+
import { DXFFile } from '../lib/dxf/dxfFile.js';
|
|
5
|
+
import { BoundingBox } from '../lib/boundingBox.js';
|
|
6
|
+
import { Strings } from '../lib/strings.js';
|
|
7
|
+
import { Input, PromptOptions } from '../lib/inputManager.js';
|
|
8
|
+
import { Flags } from '../properties/flags.js';
|
|
9
|
+
import { Property } from '../properties/property.js';
|
|
10
|
+
import { AddState, RemoveState } from '../lib/stateManager.js';
|
|
11
|
+
|
|
12
|
+
import { DesignCore } from '../designCore.js';
|
|
13
|
+
import { Utils } from '../lib/utils.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Block Entity Class
|
|
17
|
+
* @extends Entity
|
|
18
|
+
*/
|
|
19
|
+
export class Block extends Entity {
|
|
20
|
+
/**
|
|
21
|
+
* Create a Block Entity
|
|
22
|
+
* @param {Array} data
|
|
23
|
+
*/
|
|
24
|
+
constructor(data) {
|
|
25
|
+
super(data);
|
|
26
|
+
this.name = '';
|
|
27
|
+
this.points = [new Point()];
|
|
28
|
+
// Store the block record handle and endblk handle for use when writing to dxf file
|
|
29
|
+
this.blockRecordHandle = data?.blockRecordHandle;
|
|
30
|
+
this.endblkHandle = data?.endblkHandle;
|
|
31
|
+
|
|
32
|
+
Object.defineProperty(this, 'flags', {
|
|
33
|
+
value: new Flags(),
|
|
34
|
+
writable: true,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
Object.defineProperty(this, 'items', {
|
|
38
|
+
value: [],
|
|
39
|
+
writable: true,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (data) {
|
|
43
|
+
if (data.hasOwnProperty('name') || data.hasOwnProperty('2')) {
|
|
44
|
+
// DXF Groupcode 2 - Block Name
|
|
45
|
+
this.name = data.name || data[2];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (data.hasOwnProperty('items')) {
|
|
49
|
+
this.items = data.items;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (data.hasOwnProperty('flags') || data.hasOwnProperty('70')) {
|
|
53
|
+
// DXF Groupcode 70 - Block-type flags (bit-coded):
|
|
54
|
+
// 0 = Indicates none of the following flags apply
|
|
55
|
+
// 1 = This is an anonymous block generated by hatching, associative dimensioning, other internal operations, or an application
|
|
56
|
+
// 2 = This block has non-constant attribute definitions (this bit is not set if the block has any attribute definitions that are constant, or has no attribute definitions at all)
|
|
57
|
+
// 4 = This block is an external reference (xref)
|
|
58
|
+
// 8 = This block is an xref overlay
|
|
59
|
+
// 16 = This block is externally dependent
|
|
60
|
+
// 32 = This is a resolved external reference, or dependent of an external reference (ignored on input)
|
|
61
|
+
// 64 = This definition is a referenced external reference (ignored on input)
|
|
62
|
+
|
|
63
|
+
this.flags.setFlagValue(Property.loadValue([data.flags, data[70]], 0));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Register the command
|
|
70
|
+
* @return {Object}
|
|
71
|
+
* command = name of the command
|
|
72
|
+
* shortcut = shortcut for the command
|
|
73
|
+
* type = type to group command in toolbars (omitted if not shown)
|
|
74
|
+
*/
|
|
75
|
+
static register() {
|
|
76
|
+
const command = { command: 'Block', shortcut: 'B' };
|
|
77
|
+
return command;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Execute method
|
|
82
|
+
* executes the workflow, requesting input required to create an entity
|
|
83
|
+
*/
|
|
84
|
+
async execute() {
|
|
85
|
+
try {
|
|
86
|
+
// set a name
|
|
87
|
+
const defaultName = `Block-${DesignCore.Scene.blockManager.itemCount()}`;
|
|
88
|
+
const nameOp = new PromptOptions(Strings.Input.NAME, [Input.Type.STRING], [], defaultName);
|
|
89
|
+
const selectedName = await DesignCore.Scene.inputManager.requestInput(nameOp);
|
|
90
|
+
|
|
91
|
+
// get the insertion point
|
|
92
|
+
const op2 = new PromptOptions(Strings.Input.BASEPOINT, [
|
|
93
|
+
Input.Type.POINT,
|
|
94
|
+
]);
|
|
95
|
+
const insertPoint = await DesignCore.Scene.inputManager.requestInput(op2);
|
|
96
|
+
|
|
97
|
+
// get the block entities
|
|
98
|
+
const op = new PromptOptions(Strings.Input.SELECTIONSET, [
|
|
99
|
+
Input.Type.SELECTIONSET,
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
if (!DesignCore.Scene.selectionManager.selectionSet.selectionSet.length) {
|
|
103
|
+
await DesignCore.Scene.inputManager.requestInput(op);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// create block
|
|
107
|
+
const block = DesignCore.Scene.blockManager.addItem({ name: selectedName });
|
|
108
|
+
// get a copy of the selection set
|
|
109
|
+
const selections = DesignCore.Scene.selectionManager.selectionSet.selectionSet.slice();
|
|
110
|
+
// sort the selection in descending order
|
|
111
|
+
selections.sort((a, b) => b - a);
|
|
112
|
+
// array to hold state changes
|
|
113
|
+
const stateChanges = [];
|
|
114
|
+
|
|
115
|
+
// move selected items from scene to block
|
|
116
|
+
selections.forEach((index) => {
|
|
117
|
+
const item = DesignCore.Scene.entities.get(index);
|
|
118
|
+
// remove item from scene
|
|
119
|
+
const copyofitem = Utils.cloneObject(item);
|
|
120
|
+
// adjust the items points to reflect the insert point
|
|
121
|
+
const delta = new Point(-insertPoint.x, -insertPoint.y);
|
|
122
|
+
if (item.hasOwnProperty('points')) {
|
|
123
|
+
const points = copyofitem.points.map((p) => new Point(p.x, p.y, p.bulge, p.sequence).add(delta));
|
|
124
|
+
copyofitem.setProperty('points', points);
|
|
125
|
+
}
|
|
126
|
+
block.items.push(copyofitem);
|
|
127
|
+
const stateChangeRemove = new RemoveState(item);
|
|
128
|
+
stateChanges.push(stateChangeRemove);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// define insert data
|
|
132
|
+
const insertData = {
|
|
133
|
+
type: 'Insert',
|
|
134
|
+
points: [new Point(insertPoint.x, insertPoint.y)],
|
|
135
|
+
blockName: selectedName,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const insert = DesignCore.CommandManager.createNew(insertData.type, insertData);
|
|
139
|
+
const stateChangeAdd = new AddState(insert);
|
|
140
|
+
stateChanges.push(stateChangeAdd);
|
|
141
|
+
|
|
142
|
+
// commit the changes to the scene
|
|
143
|
+
DesignCore.Scene.commit(stateChanges);
|
|
144
|
+
|
|
145
|
+
DesignCore.Scene.inputManager.executeCommand();
|
|
146
|
+
} catch (err) {
|
|
147
|
+
Logging.instance.error(`${this.type} - ${err}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Preview the entity during creation
|
|
153
|
+
*/
|
|
154
|
+
preview() { }
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Write the entity to file in the dxf format
|
|
158
|
+
* @param {DXFFile} file
|
|
159
|
+
*/
|
|
160
|
+
dxf(file) {
|
|
161
|
+
file.writeGroupCode('0', 'BLOCK');
|
|
162
|
+
file.writeGroupCode('5', this.handle, DXFFile.Version.R2000); // Handle
|
|
163
|
+
file.writeGroupCode('100', 'AcDbEntity', DXFFile.Version.R2000);
|
|
164
|
+
file.writeGroupCode('8', this.layer);
|
|
165
|
+
file.writeGroupCode('100', 'AcDbBlockBegin', DXFFile.Version.R2000);
|
|
166
|
+
file.writeGroupCode('2', this.name);
|
|
167
|
+
file.writeGroupCode('70', this.flags.getFlagValue());
|
|
168
|
+
file.writeGroupCode('10', this.points[0].x);
|
|
169
|
+
file.writeGroupCode('20', this.points[0].y);
|
|
170
|
+
file.writeGroupCode('30', 0.0);
|
|
171
|
+
file.writeGroupCode('3', this.name); // Name again
|
|
172
|
+
file.writeGroupCode('1', '');
|
|
173
|
+
|
|
174
|
+
for (let i = 0; i < this.items.length; i++) {
|
|
175
|
+
this.items[i].dxf(file);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const endblk = new EndBlock({ handle: this.endblkHandle });
|
|
179
|
+
endblk.dxf(file);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Clear items from the block
|
|
184
|
+
*/
|
|
185
|
+
clearItems() {
|
|
186
|
+
this.items = [];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Add an item to the block
|
|
191
|
+
* @param {Object} item
|
|
192
|
+
*/
|
|
193
|
+
addItem(item) {
|
|
194
|
+
this.items.push(item);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Draw the entity
|
|
199
|
+
* @param {Object} ctx - context
|
|
200
|
+
* @param {number} scale
|
|
201
|
+
* @param {Object} insert - insert entity
|
|
202
|
+
*/
|
|
203
|
+
draw(ctx, scale, insert = undefined) {
|
|
204
|
+
if (!this.items.length) {
|
|
205
|
+
// nothing to draw
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
this.items.forEach((item) => {
|
|
210
|
+
ctx.save();
|
|
211
|
+
// Use the current item and block insert to set the context
|
|
212
|
+
// insert required for colour ByBlock
|
|
213
|
+
DesignCore.Canvas.setContext(item, ctx, insert);
|
|
214
|
+
|
|
215
|
+
item.draw(ctx, scale);
|
|
216
|
+
ctx.restore();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
/*
|
|
220
|
+
//////////////////////////////////////////
|
|
221
|
+
// draw test point for location
|
|
222
|
+
ctx.strokeStyle = Colours.rgbToString(colour);
|
|
223
|
+
ctx.lineWidth = 1 / scale;
|
|
224
|
+
ctx.beginPath()
|
|
225
|
+
ctx.moveTo(this.points[0].x, this.points[0].y);
|
|
226
|
+
ctx.arc(this.points[0].x, this.points[0].y, 5 / scale, radians2degrees(0), radians2degrees(360), false);
|
|
227
|
+
ctx.stroke();
|
|
228
|
+
//////////////////////////////////////////
|
|
229
|
+
*/
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get snap points
|
|
234
|
+
* @param {Point} mousePoint
|
|
235
|
+
* @param {number} delta
|
|
236
|
+
* @return {Array} - array of snap points
|
|
237
|
+
*/
|
|
238
|
+
snaps(mousePoint, delta) {
|
|
239
|
+
const snaps = [];
|
|
240
|
+
|
|
241
|
+
if (!this.items.length) {
|
|
242
|
+
// nothing to draw
|
|
243
|
+
return snaps;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
for (let item = 0; item < this.items.length; item++) {
|
|
247
|
+
// collect the child item snaps
|
|
248
|
+
const itemSnaps = this.items[item].snaps(mousePoint, delta);
|
|
249
|
+
snaps.push(...itemSnaps);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return snaps;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Get closest point on entity
|
|
257
|
+
* @param {Point} P
|
|
258
|
+
* @return {Array} - [Point, distance]
|
|
259
|
+
*/
|
|
260
|
+
closestPoint(P) {
|
|
261
|
+
let distance = Infinity;
|
|
262
|
+
let minPnt = P;
|
|
263
|
+
|
|
264
|
+
if (!this.items.length) {
|
|
265
|
+
// nothing to draw
|
|
266
|
+
return [minPnt, distance];
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
for (let idx = 0; idx < this.items.length; idx++) {
|
|
270
|
+
const itemClosestPoint = this.items[idx].closestPoint(P);
|
|
271
|
+
const itemPnt = itemClosestPoint[0];
|
|
272
|
+
const itemDist = itemClosestPoint[1];
|
|
273
|
+
|
|
274
|
+
if (itemDist < distance) {
|
|
275
|
+
distance = itemDist;
|
|
276
|
+
minPnt = itemPnt;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return [minPnt, distance];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Return boundingbox for entity
|
|
285
|
+
* @return {BoundingBox}
|
|
286
|
+
*/
|
|
287
|
+
boundingBox() {
|
|
288
|
+
let xmin = Infinity;
|
|
289
|
+
let xmax = -Infinity;
|
|
290
|
+
let ymin = Infinity;
|
|
291
|
+
let ymax = -Infinity;
|
|
292
|
+
|
|
293
|
+
for (let idx = 0; idx < this.items.length; idx++) {
|
|
294
|
+
const itemBoundingBox = this.items[idx].boundingBox();
|
|
295
|
+
|
|
296
|
+
xmin = Math.min(xmin, itemBoundingBox.xMin);
|
|
297
|
+
xmax = Math.max(xmax, itemBoundingBox.xMax);
|
|
298
|
+
ymin = Math.min(ymin, itemBoundingBox.yMin);
|
|
299
|
+
ymax = Math.max(ymax, itemBoundingBox.yMax);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const topLeft = new Point(xmin, ymax);
|
|
303
|
+
const bottomRight = new Point(xmax, ymin);
|
|
304
|
+
|
|
305
|
+
return new BoundingBox(topLeft, bottomRight);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Determine if the entity is touch the selection window
|
|
310
|
+
* @param {Object} selection - {min: Point, max: Point}
|
|
311
|
+
* @return {boolean} true if touched
|
|
312
|
+
*/
|
|
313
|
+
touched(selection) {
|
|
314
|
+
for (let idx = 0; idx < this.items.length; idx++) {
|
|
315
|
+
const touched = this.items[idx].touched(selection);
|
|
316
|
+
if (touched) {
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// import {DesignCore} from '../designCore.js';
|
|
2
|
+
// import {Strings} from '../lib/strings.js';
|
|
3
|
+
import { TableManagerBase } from './tableManagerBase.js';
|
|
4
|
+
import { Block } from './block.js';
|
|
5
|
+
import { DesignCore } from '../designCore.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* BlockManager Class
|
|
9
|
+
* @extends TableManagerBase
|
|
10
|
+
*/
|
|
11
|
+
export class BlockManager extends TableManagerBase {
|
|
12
|
+
/** Create a BlockManager */
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
this.itemProperty = 'block';
|
|
16
|
+
this.indelibleItems.push('*Model_Space', '*Paper_Space');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Get the item class */
|
|
20
|
+
get itemClass() {
|
|
21
|
+
return Block;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Add standard blocks
|
|
26
|
+
*/
|
|
27
|
+
addStandardItems() {
|
|
28
|
+
this.addItem({ 'name': '*Model_Space' });
|
|
29
|
+
this.addItem({ 'name': '*Paper_Space' });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Add a block to the list of items and assign a block record handle
|
|
34
|
+
* @param {Object} item
|
|
35
|
+
* @param {boolean} overwrite
|
|
36
|
+
* @return {Object}
|
|
37
|
+
*/
|
|
38
|
+
addItem(item, overwrite = false) {
|
|
39
|
+
const newItem = super.addItem(item, overwrite);
|
|
40
|
+
if (newItem.blockRecordHandle === undefined) {
|
|
41
|
+
newItem.blockRecordHandle = DesignCore.HandleManager.next();
|
|
42
|
+
}
|
|
43
|
+
if (newItem.endblkHandle === undefined) {
|
|
44
|
+
newItem.endblkHandle = DesignCore.HandleManager.next();
|
|
45
|
+
}
|
|
46
|
+
return newItem;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DXFFile } from '../lib/dxf/dxfFile.js';
|
|
2
|
+
import { Property } from '../properties/property.js';
|
|
3
|
+
|
|
4
|
+
/** BlockRecord Class */
|
|
5
|
+
export class BlockRecord {
|
|
6
|
+
/**
|
|
7
|
+
* Create a BlockRecord
|
|
8
|
+
* @param {Object} data
|
|
9
|
+
*/
|
|
10
|
+
constructor(data) {
|
|
11
|
+
// DXF Groupcode 5 - Handle
|
|
12
|
+
this.handle = Property.loadValue([data?.handle, data?.[5]]);
|
|
13
|
+
// DXF Groupcode 2 - Name
|
|
14
|
+
this.name = Property.loadValue([data?.name, data?.[2]], '');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Write the item to file in the dxf format
|
|
19
|
+
* @param {DXFFile} file
|
|
20
|
+
*/
|
|
21
|
+
dxf(file) {
|
|
22
|
+
file.writeGroupCode('0', 'BLOCK_RECORD', DXFFile.Version.R2000);
|
|
23
|
+
file.writeGroupCode('5', this.handle, DXFFile.Version.R2000);
|
|
24
|
+
file.writeGroupCode('100', 'AcDbSymbolTableRecord', DXFFile.Version.R2000);
|
|
25
|
+
file.writeGroupCode('100', 'AcDbBlockTableRecord', DXFFile.Version.R2000);
|
|
26
|
+
file.writeGroupCode('2', this.name, DXFFile.Version.R2000);
|
|
27
|
+
file.writeGroupCode('340', '0', DXFFile.Version.R2000);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { DXFFile } from '../lib/dxf/dxfFile.js';
|
|
2
|
+
import { BlockRecord } from './blockRecord.js';
|
|
3
|
+
|
|
4
|
+
import { DesignCore } from '../designCore.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* BlockRecordManager Class
|
|
8
|
+
* Writes BLOCK_RECORD table entries based on the scene's block manager
|
|
9
|
+
*/
|
|
10
|
+
export class BlockRecordManager {
|
|
11
|
+
/** Create a BlockRecordManager */
|
|
12
|
+
constructor() {
|
|
13
|
+
this.handle = DesignCore.HandleManager.next();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Write the table to file in the dxf format
|
|
18
|
+
* @param {DXFFile} file
|
|
19
|
+
*/
|
|
20
|
+
dxf(file) {
|
|
21
|
+
const blocks = DesignCore.Scene.blockManager.items;
|
|
22
|
+
|
|
23
|
+
file.writeGroupCode('0', 'TABLE', DXFFile.Version.R2000);
|
|
24
|
+
file.writeGroupCode('2', 'BLOCK_RECORD', DXFFile.Version.R2000);
|
|
25
|
+
file.writeGroupCode('5', this.handle, DXFFile.Version.R2000);
|
|
26
|
+
file.writeGroupCode('100', 'AcDbSymbolTable', DXFFile.Version.R2000);
|
|
27
|
+
file.writeGroupCode('70', blocks.length.toString(), DXFFile.Version.R2000);
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
30
|
+
// Temp hack for block record handle
|
|
31
|
+
const record = new BlockRecord({ name: blocks[i].name, handle: blocks[i].blockRecordHandle });
|
|
32
|
+
record.dxf(file);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
file.writeGroupCode('0', 'ENDTAB', DXFFile.Version.R2000);
|
|
36
|
+
}
|
|
37
|
+
}
|