@vitrosoftware/common-ui-ts 1.1.122 → 1.1.124

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 (124) hide show
  1. package/css/std/controls/checkbox/checkbox.css +4 -0
  2. package/css/std/controls/checkbox/img/checkbox-indeterminate.svg +4 -0
  3. package/css/std/controls/date-picker/date-picker.css +1 -25
  4. package/css/std/controls/dxf-viewer/annotation.css +85 -0
  5. package/css/std/controls/dxf-viewer/common.css +24 -0
  6. package/css/std/controls/dxf-viewer/dxf-viewer-index.css +14081 -0
  7. package/css/std/controls/dxf-viewer/dxf-viewer.css +194 -0
  8. package/css/std/controls/dxf-viewer/img/cancel-dark-grey.svg +5 -0
  9. package/css/std/controls/dxf-viewer/img/collapse-bottom.svg +5 -0
  10. package/css/std/controls/dxf-viewer/img/collapse-up-blue.svg +5 -0
  11. package/css/std/controls/dxf-viewer/img/delete-active.svg +11 -0
  12. package/css/std/controls/dxf-viewer/img/delete.svg +11 -0
  13. package/css/std/controls/dxf-viewer/img/draw-annotation.svg +3 -0
  14. package/css/std/controls/dxf-viewer/img/invisible-eye.svg +4 -0
  15. package/css/std/controls/dxf-viewer/img/show-annotation.svg +3 -0
  16. package/css/std/controls/dxf-viewer/img/sidebar-layers-toggle.svg +6 -0
  17. package/css/std/controls/dxf-viewer/img/sidebar-notes-toggle.svg +5 -0
  18. package/css/std/controls/dxf-viewer/img/sidebar-resizer.svg +6 -0
  19. package/css/std/controls/dxf-viewer/img/sidebar-toggle.svg +7 -0
  20. package/css/std/controls/dxf-viewer/img/visible-eye.svg +4 -0
  21. package/css/std/controls/dxf-viewer/img/zoom-in.svg +6 -0
  22. package/css/std/controls/dxf-viewer/img/zoom-out.svg +5 -0
  23. package/css/std/controls/dxf-viewer/layer-list.css +104 -0
  24. package/css/std/controls/dxf-viewer/panel.css +34 -0
  25. package/css/std/controls/dxf-viewer/prop-inspector.css +102 -0
  26. package/css/std/controls/dxf-viewer/select.css +111 -0
  27. package/css/std/controls/dxf-viewer/sidebar.css +190 -0
  28. package/css/std/controls/dxf-viewer/thumbnail-list.css +65 -0
  29. package/css/std/controls/dxf-viewer/toolbar.css +117 -0
  30. package/css/std/controls/dxf-viewer/treeview.css +3 -0
  31. package/css/std/controls/dxf-viewer/treeview.panel.css +108 -0
  32. package/css/std/controls/error-message/error-message.css +22 -0
  33. package/css/std/controls/image-picker/image-picker.css +0 -26
  34. package/css/std/controls/input/input.css +1 -24
  35. package/css/std/controls/issue-tile/issue-tile-header.css +1 -0
  36. package/css/std/controls/login/ntlm-authentication-form.css +9 -12
  37. package/css/std/controls/lookup-picker/lookup-picker-value-list.css +38 -2
  38. package/css/std/controls/lookup-picker/lookup-picker.css +1 -25
  39. package/css/std/controls/table-view/treegrid-context-menu.css +44 -18
  40. package/css/std/controls/table-view/treegrid-message.css +4 -4
  41. package/css/std/controls/time-picker/time-picker.css +1 -25
  42. package/dist/index.css +81 -143
  43. package/dist/index.js +15137 -489
  44. package/dist/index.js.map +1 -1
  45. package/dist/src/controls/Checkbox/Checkbox.d.ts +1 -0
  46. package/dist/src/controls/DxfViewer/DxfViewer.d.ts +6 -0
  47. package/dist/src/controls/DxfViewer/DxfViewerContext.d.ts +31 -0
  48. package/dist/src/controls/DxfViewer/Layer.d.ts +9 -0
  49. package/dist/src/controls/DxfViewer/LayerList.d.ts +11 -0
  50. package/dist/src/controls/DxfViewer/Thumbnail.d.ts +7 -0
  51. package/dist/src/controls/DxfViewer/ThumbnailList.d.ts +6 -0
  52. package/dist/src/controls/DxfViewer/Viewer.d.ts +6 -0
  53. package/dist/src/controls/ErrorMessage/ErrorMessage.d.ts +6 -0
  54. package/dist/src/controls/Login/FormRef.d.ts +3 -0
  55. package/dist/src/controls/Login/LoginConstants.d.ts +2 -1
  56. package/dist/src/controls/Login/LoginFormRef.d.ts +2 -2
  57. package/dist/src/controls/Login/NTLMAuthenticationForm.d.ts +5 -2
  58. package/dist/src/controls/LookupPicker/LookupPicker.d.ts +2 -0
  59. package/dist/src/controls/LookupPicker/ValueList.d.ts +2 -0
  60. package/dist/src/controls/TableView/TableViewConstants.d.ts +11 -0
  61. package/dist/src/controls/TableView/TreeGridTableViewContextImpl.d.ts +1 -0
  62. package/dist/src/controls/TreeView/TreeView.d.ts +4 -0
  63. package/dist/src/controls/TreeView/TreeViewConfig.d.ts +3 -0
  64. package/dist/src/controls/TreeView/TreeViewConstants.d.ts +2 -1
  65. package/dist/src/index.d.ts +7 -1
  66. package/lib/dxf-viewer/BatchingKey.js +91 -0
  67. package/lib/dxf-viewer/DxfFetcher.js +39 -0
  68. package/lib/dxf-viewer/DxfScene.js +2695 -0
  69. package/lib/dxf-viewer/DxfViewer.js +1056 -0
  70. package/lib/dxf-viewer/DxfWorker.js +229 -0
  71. package/lib/dxf-viewer/DynamicBuffer.js +100 -0
  72. package/lib/dxf-viewer/HatchCalculator.js +345 -0
  73. package/lib/dxf-viewer/LinearDimension.js +323 -0
  74. package/lib/dxf-viewer/MTextFormatParser.js +211 -0
  75. package/lib/dxf-viewer/MaterialKey.js +37 -0
  76. package/lib/dxf-viewer/OrbitControls.js +1253 -0
  77. package/lib/dxf-viewer/Pattern.js +94 -0
  78. package/lib/dxf-viewer/RBTree.js +471 -0
  79. package/lib/dxf-viewer/TextRenderer.js +1038 -0
  80. package/lib/dxf-viewer/index.js +42 -0
  81. package/lib/dxf-viewer/math/Matrix2.js +77 -0
  82. package/lib/dxf-viewer/math/utils.js +59 -0
  83. package/lib/dxf-viewer/parser/AutoCadColorIndex.js +265 -0
  84. package/lib/dxf-viewer/parser/DimStyleCodes.js +33 -0
  85. package/lib/dxf-viewer/parser/DxfArrayScanner.js +143 -0
  86. package/lib/dxf-viewer/parser/DxfParser.js +980 -0
  87. package/lib/dxf-viewer/parser/ExtendedDataParse-My.js +91 -0
  88. package/lib/dxf-viewer/parser/ExtendedDataParser.js +123 -0
  89. package/lib/dxf-viewer/parser/ParseHelpers.js +142 -0
  90. package/lib/dxf-viewer/parser/entities/3dface.js +83 -0
  91. package/lib/dxf-viewer/parser/entities/arc.js +38 -0
  92. package/lib/dxf-viewer/parser/entities/attdef.js +89 -0
  93. package/lib/dxf-viewer/parser/entities/attrib.js +34 -0
  94. package/lib/dxf-viewer/parser/entities/attribute.js +109 -0
  95. package/lib/dxf-viewer/parser/entities/circle.js +43 -0
  96. package/lib/dxf-viewer/parser/entities/dimension.js +72 -0
  97. package/lib/dxf-viewer/parser/entities/ellipse.js +46 -0
  98. package/lib/dxf-viewer/parser/entities/hatch.js +343 -0
  99. package/lib/dxf-viewer/parser/entities/insert.js +62 -0
  100. package/lib/dxf-viewer/parser/entities/leader.js +84 -0
  101. package/lib/dxf-viewer/parser/entities/line.js +34 -0
  102. package/lib/dxf-viewer/parser/entities/lwpolyline.js +100 -0
  103. package/lib/dxf-viewer/parser/entities/mtext.js +54 -0
  104. package/lib/dxf-viewer/parser/entities/point.js +35 -0
  105. package/lib/dxf-viewer/parser/entities/polyline.js +92 -0
  106. package/lib/dxf-viewer/parser/entities/solid.js +40 -0
  107. package/lib/dxf-viewer/parser/entities/spline.js +70 -0
  108. package/lib/dxf-viewer/parser/entities/text.js +47 -0
  109. package/lib/dxf-viewer/parser/entities/vertex.js +62 -0
  110. package/lib/dxf-viewer/parser/entities/viewport.js +56 -0
  111. package/lib/dxf-viewer/parser/objects/dictionary.js +29 -0
  112. package/lib/dxf-viewer/parser/objects/layout.js +35 -0
  113. package/lib/dxf-viewer/parser/objects/xrecord.js +29 -0
  114. package/lib/opentype/opentype.module.js +14571 -0
  115. package/lib/three/CSS2DRenderer.js +235 -0
  116. package/lib/three/three.module.js +49912 -0
  117. package/package.json +12 -10
  118. package/src/controls/BimViewer/js/bim-viewer.js +2 -2
  119. package/src/controls/DxfViewer/js/dxf-viewer.js +3580 -0
  120. package/src/controls/PdfViewer/js/pdf-viewer.js +1 -1
  121. package/css/std/controls/input/img/error-message.svg +0 -6
  122. package/css/std/controls/lookup-picker/img/error-message.svg +0 -6
  123. package/css/std/controls/time-picker/img/error-message.svg +0 -6
  124. /package/css/std/controls/{date-picker → error-message}/img/error-message.svg +0 -0
@@ -0,0 +1,323 @@
1
+ import { Matrix3, Vector2 } from "/resource/dxfViewer/js/three/three.module.js"
2
+ import { ParseSpecialChars } from "./TextRenderer.js"
3
+
4
+ /**
5
+ * @property {{color: ?number, start: Vector2, end: Vector2}[]} lines
6
+ * @property {{color: ?number, vertices: Vector2[]}[], indices: number[]} triangles On or more
7
+ * triangles in each item.
8
+ * @property {{text: string, size: number, angle: number, color: number, position: Vector2}[]} texts
9
+ * Each item position is specified as middle point of the rendered text.
10
+ */
11
+ export class DimensionLayout {
12
+ constructor() {
13
+ this.lines = []
14
+ this.triangles = []
15
+ this.texts = []
16
+ }
17
+
18
+ AddLine(start, end, color = null) {
19
+ this.lines.push({ start, end, color })
20
+ }
21
+
22
+ /** Add one or more triangles. */
23
+ AddTriangles(vertices, indices, color = null) {
24
+ this.triangles.push({ vertices, indices, color })
25
+ }
26
+
27
+ AddText(text, size, angle, color, position) {
28
+ this.texts.push({ text, size, angle, color, position })
29
+ }
30
+ }
31
+
32
+ const arrowHeadShape = {
33
+ vertices: [
34
+ new Vector2(0, 0),
35
+ new Vector2(1, -0.25),
36
+ new Vector2(1, 0.25)
37
+ ],
38
+ indices: [0, 1, 2]
39
+ }
40
+
41
+ /** Encapsulates all calculations about linear dimensions layout. */
42
+ export class LinearDimension {
43
+
44
+ /**
45
+ * @typedef LinearDimensionParams
46
+ * @property {Vector2} p1 First definition point.
47
+ * @property {Vector2} p2 Second definition point.
48
+ * @property {Vector2} anchor Anchor point defines dimension line location.
49
+ * @property {?number} angle Rotation angle for rotated dimension, deg.
50
+ * @property {boolean} isAligned Dimension line is parallel to base line for aligned dimension.
51
+ * @property {?string} text Dimension text pattern.
52
+ * @property {?Vector2} textAnchor Text location (middle point) override.
53
+ * @property {?number} textRotation Rotation angle of the dimension text away from its default
54
+ * orientation (the direction of the dimension line)
55
+ */
56
+
57
+ /**
58
+ * @param {LinearDimensionParams} params
59
+ * @param {Function<any(string)>} styleResolver Provides value for a requested style parameter.
60
+ * @param {Function<number(string, number)>} textWidthCalculator Get text width in model space
61
+ * units for a given text and font size (height).
62
+ */
63
+ constructor(params, styleResolver, textWidthCalculator) {
64
+ this.params = params
65
+ this.styleResolver = styleResolver
66
+ this.textWidthCalculator = textWidthCalculator
67
+ /* Can be set to indicate some invalid geometric solution. */
68
+ this.isValid = true
69
+ this._CalculateGeometry()
70
+ }
71
+
72
+ IsValid() {
73
+ return this.isValid
74
+ }
75
+
76
+ GetTexts() {
77
+ return [this._GetText()]
78
+ }
79
+
80
+ /**
81
+ * @return {DimensionLayout}
82
+ */
83
+ GenerateLayout() {
84
+ /* See https://ezdxf.readthedocs.io/en/stable/tables/dimstyle_table_entry.html */
85
+ const result = new DimensionLayout()
86
+
87
+ /* Dimension line(s). */
88
+ const dimSize = this.d1.distanceTo(this.d2)
89
+ const dimColor = this.styleResolver("DIMCLRD")
90
+ let dimScale = this.styleResolver("DIMSCALE") ?? 1
91
+ if (dimScale == 0) {
92
+ /* No any auto calculation implemented, since no support for paper space. */
93
+ dimScale = 1
94
+ }
95
+
96
+ const text = this._GetText()
97
+ const fontSize = (this.styleResolver("DIMTXT") ?? 1) * dimScale
98
+ const textWidth = this.textWidthCalculator(text, fontSize)
99
+ const textColor = this.styleResolver("DIMCLRT")
100
+ const arrowSize = (this.styleResolver("DIMASZ") ?? 1) * dimScale
101
+ const tickSize = (this.styleResolver("DIMTSZ") ?? 0) * dimScale
102
+
103
+ let textAnchor = this.params.textAnchor
104
+ let flipArrows = false
105
+
106
+ const start = this.d1.clone()
107
+ const dimExt = (this.styleResolver("DIMDLE") ?? 0) * dimScale
108
+ if (dimExt != 0) {
109
+ start.add(this.vDim.clone().multiplyScalar(-dimExt))
110
+ }
111
+ const end = this.d2.clone()
112
+ if (dimExt != 0) {
113
+ end.add(this.vDim.clone().multiplyScalar(dimExt))
114
+ }
115
+ result.AddLine(start, end, dimColor)
116
+
117
+ if (dimSize < arrowSize * 2) {
118
+ flipArrows = true
119
+ }
120
+
121
+ if (!textAnchor) {
122
+ //XXX for now just always draw the text above dimension line with fixed gap
123
+ textAnchor = this.vDim.clone().multiplyScalar(this.d1.distanceTo(this.d2) / 2)
124
+ .add(this.d1).add(this.vDimNorm.clone().multiplyScalar(fontSize * 0.75))
125
+ }
126
+ const angle = this.vDimNorm.angle() * 180 / Math.PI - 90 +
127
+ (this.params.textRotation ?? 0)
128
+ result.AddText(text, fontSize, angle, textColor, textAnchor)
129
+
130
+
131
+ /* Extension lines. */
132
+ const extColor = this.styleResolver("DIMCLRE")
133
+ const extOffset = (this.styleResolver("DIMEXO") ?? 0) * dimScale
134
+ const extExt = (this.styleResolver("DIMEXE") ?? 0) * dimScale
135
+
136
+ const DrawExtLine = (basePt, dimPt) => {
137
+ const vExt = dimPt.clone().sub(basePt)
138
+ const dist = vExt.length()
139
+ if (dist == 0) {
140
+ return
141
+ }
142
+ vExt.normalize()
143
+ const start = basePt.clone()
144
+ if (extOffset != 0) {
145
+ start.add(vExt.clone().multiplyScalar(extOffset))
146
+ }
147
+ const end = dimPt.clone()
148
+ if (extExt != 0) {
149
+ end.add(vExt.clone().multiplyScalar(extExt))
150
+ }
151
+ result.AddLine(start, end, extColor)
152
+ }
153
+
154
+ if (!(this.styleResolver("DIMSE1") ?? 0)) {
155
+ DrawExtLine(this.params.p1, this.d1)
156
+ }
157
+ if (!(this.styleResolver("DIMSE2") ?? 0)) {
158
+ DrawExtLine(this.params.p2, this.d2)
159
+ }
160
+
161
+ /* Draw arrows (or anything defined as dimension shape). Assuming shape is defined
162
+ * horizontally for left side with the origin in the dimension point, scale corresponding to
163
+ * size 1. Calculate appropriate transform for the shape.
164
+ */
165
+ //XXX check suppression by DIMSOXD, DIMSD1, DIMSD2
166
+ for (let i = 0; i < 2; i++) {
167
+ const dimPt = i == 0 ? this.d1 : this.d2
168
+ let flip = i == 1
169
+ if (flipArrows) {
170
+ flip = !flip
171
+ }
172
+
173
+ let transform = new Matrix3().identity()
174
+ if (tickSize > 0) {
175
+ transform.scale(tickSize, tickSize)
176
+ } else {
177
+ transform.scale(arrowSize, arrowSize)
178
+ /* Tick is not flipped. */
179
+ if (flip) {
180
+ transform.scale(-1, 1)
181
+ }
182
+ }
183
+
184
+ const angle = -this.vDim.angle()
185
+ transform.rotate(angle)
186
+
187
+ transform.translate(dimPt.x, dimPt.y)
188
+
189
+ if (tickSize > 0) {
190
+ this._CreateTick(result, transform, dimColor)
191
+ } else {
192
+ this._CreateArrowShape(result, transform, dimColor)
193
+ }
194
+ }
195
+
196
+ return result
197
+ }
198
+
199
+ _CreateArrowShape(layout, transform, color) {
200
+ const vertices = []
201
+ for (const v of arrowHeadShape.vertices) {
202
+ vertices.push(v.clone().applyMatrix3(transform))
203
+ }
204
+ layout.AddTriangles(vertices, arrowHeadShape.indices, color)
205
+ }
206
+
207
+ _CreateTick(layout, transform, color) {
208
+ layout.AddLine(new Vector2(0.5, 0.5).applyMatrix3(transform),
209
+ new Vector2(-0.5, -0.5).applyMatrix3(transform),
210
+ color)
211
+ }
212
+
213
+ /** Calculate and set basic geometric parameters (some points and vectors which define the
214
+ * dimension layout).
215
+ */
216
+ _CalculateGeometry() {
217
+ /* Base vector. */
218
+ this.vBase = this.params.p2.clone().sub(this.params.p1).normalize()
219
+
220
+ /* Dimension vector. */
221
+ if (this.params.isAligned) {
222
+ this.vDim = this.vBase
223
+ } else {
224
+ /* Angle is defined as angle between X axis and dimension line (CCW is positive). */
225
+ const angle = (this.params.angle ?? 0) * Math.PI / 180
226
+ this.vDim = new Vector2(Math.cos(angle), Math.sin(angle))
227
+ }
228
+
229
+ /* Dimension points. Calculate them by projecting base points to dimension line. */
230
+ this.d1 = this.vDim.clone().multiplyScalar(
231
+ /* Projected signed length. */
232
+ this.params.p1.clone().sub(this.params.anchor).dot(this.vDim))
233
+ .add(this.params.anchor)
234
+ this.d2 = this.vDim.clone().multiplyScalar(
235
+ /* Projected signed length. */
236
+ this.params.p2.clone().sub(this.params.anchor).dot(this.vDim))
237
+ .add(this.params.anchor)
238
+
239
+ if (this.d1.distanceTo(this.d2) == 0) {
240
+ this.isValid = false
241
+ }
242
+
243
+ /* Ensure dimension vector still points from d1 to d2 after rotation. */
244
+ this.vDim.copy(this.d2).sub(this.d1).normalize()
245
+
246
+ /* Dimension normal vector is perpendicular to dimension line and is either above or on its
247
+ * left side.
248
+ * 90deg rotated vector is either [y; -x] or [-y; x]. Select most suitable from them
249
+ * (y > x).
250
+ */
251
+ if (this.vDim.y < -this.vDim.x) {
252
+ this.vDimNorm = new Vector2(this.vDim.y, -this.vDim.x)
253
+ } else {
254
+ this.vDimNorm = new Vector2(-this.vDim.y, this.vDim.x)
255
+ }
256
+ }
257
+
258
+ _GetText() {
259
+ if (this.params.text == " ") {
260
+ /* Space indicates empty text. */
261
+ return ""
262
+ }
263
+ if ((this.params.text ?? "") != "" && this.params.text.indexOf("<>") == -1) {
264
+ /* No value placeholder, just return the text. */
265
+ return ParseSpecialChars(this.params.text)
266
+ }
267
+
268
+ let measurement = this.d2.distanceTo(this.d1)
269
+ measurement *= this.styleResolver("DIMLFAC") ?? 1
270
+
271
+ const rnd = this.styleResolver("DIMRND") ?? 0
272
+ if (rnd > 0) {
273
+ const n = Math.round(measurement / rnd)
274
+ measurement = rnd * n
275
+ }
276
+
277
+ const zeroSupp = this.styleResolver("DIMZIN") ?? 0
278
+ const leadZeroSupp = (zeroSupp & 4) != 0
279
+ const trailingZeroSupp = (zeroSupp & 8) != 0
280
+
281
+ let measText = measurement.toFixed(this.styleResolver("DIMDEC") ?? 2)
282
+
283
+ if (trailingZeroSupp) {
284
+ measText = measText.replace(/.0+$/, "")
285
+ }
286
+
287
+ if (leadZeroSupp) {
288
+ measText = measText.replace(/^0+/, "")
289
+ }
290
+
291
+ if (measText.startsWith(".")) {
292
+ measText = "0" + measText
293
+ } else if (measText == "") {
294
+ measText = "0"
295
+ }
296
+ if (measText.endsWith(".")) {
297
+ measText = measText.substring(0, measText.length - 1)
298
+ }
299
+
300
+ let decSep = this.styleResolver("DIMDSEP") ?? "."
301
+ if (!isNaN(decSep)) {
302
+ decSep = String.fromCharCode(decSep)
303
+ }
304
+ if (decSep != ".") {
305
+ measText = measText.replace(".", decSep)
306
+ }
307
+
308
+ const suffix = this.styleResolver("DIMPOST") ?? ""
309
+ if (suffix != "") {
310
+ if (suffix.indexOf("<>") != -1) {
311
+ measText = suffix.replaceAll("<>", measText)
312
+ } else {
313
+ measText += suffix
314
+ }
315
+ }
316
+
317
+ if ((this.params.text ?? "") != "") {
318
+ measText = this.params.text.replaceAll("<>", measText)
319
+ }
320
+
321
+ return ParseSpecialChars(measText)
322
+ }
323
+ }
@@ -0,0 +1,211 @@
1
+ /** Parses MTEXT formatted text into more convenient intermediate representation. The MTEXT
2
+ * formatting is not well documented, the only source I found:
3
+ * https://adndevblog.typepad.com/autocad/2017/09/dissecting-mtext-format-codes.html
4
+ */
5
+
6
+ const State = Object.freeze({
7
+ TEXT: 0,
8
+ ESCAPE: 1,
9
+ /* Skip currently unsupported format codes till ';' */
10
+ SKIP_FORMAT: 2,
11
+ /* For \pxq* paragraph formatting. Not found documentation yet, so temporal naming for now. */
12
+ PARAGRAPH1: 3,
13
+ PARAGRAPH2: 4,
14
+ PARAGRAPH3: 5
15
+ })
16
+
17
+ const EntityType = Object.freeze({
18
+ TEXT: 0,
19
+ SCOPE: 1,
20
+ PARAGRAPH: 2,
21
+ NON_BREAKING_SPACE: 3,
22
+ /** "alignment" property is either "r", "c", "l", "j", "d" for right, center, left, justify
23
+ * (seems to be the same as left), distribute (justify) alignment.
24
+ */
25
+ PARAGRAPH_ALIGNMENT: 4
26
+
27
+ /* Many others are not yet implemented. */
28
+ })
29
+
30
+ /** Single letter format codes which are not terminated by ";". */
31
+ const shortFormats = new Set([
32
+ "L", "l", "O", "o", "K", "k", "P", "X", "~"
33
+ ])
34
+
35
+ const longFormats = new Set([
36
+ "f", "F", "p", "Q", "H", "W", "S", "A", "C", "T"
37
+ ])
38
+
39
+ const validEscapes = new Set([
40
+ "\\", "{", "}"
41
+ ])
42
+
43
+ export class MTextFormatParser {
44
+
45
+ constructor() {
46
+ this.entities = []
47
+ }
48
+
49
+ Parse(text) {
50
+ const n = text.length
51
+ let textStart = 0
52
+ let state = State.TEXT
53
+ let scopeStack = []
54
+ let curEntities = this.entities
55
+ let curPos = 0
56
+ const _this = this
57
+
58
+ function EmitText() {
59
+ if (state !== State.TEXT || textStart === curPos) {
60
+ return
61
+ }
62
+ curEntities.push({
63
+ type: EntityType.TEXT,
64
+ content: text.slice(textStart, curPos)
65
+ })
66
+ textStart = curPos
67
+ }
68
+
69
+ function EmitEntity(type) {
70
+ curEntities.push({type: type})
71
+ }
72
+
73
+ function PushScope() {
74
+ const scope = {
75
+ type: EntityType.SCOPE,
76
+ content: []
77
+ }
78
+ curEntities.push(scope)
79
+ curEntities = scope.content
80
+ scopeStack.push(scope)
81
+ }
82
+
83
+ function PopScope() {
84
+ if (scopeStack.length === 0) {
85
+ /* Stack underflow, just ignore now. */
86
+ return
87
+ }
88
+ scopeStack.pop()
89
+ if (scopeStack.length === 0) {
90
+ curEntities = _this.entities
91
+ } else {
92
+ curEntities = scopeStack[scopeStack.length - 1].content
93
+ }
94
+ }
95
+
96
+ for ( ;curPos < n; curPos++) {
97
+ const c = text.charAt(curPos)
98
+
99
+ switch (state) {
100
+
101
+ case State.TEXT:
102
+ if (c === "{") {
103
+ EmitText()
104
+ PushScope()
105
+ textStart = curPos + 1
106
+ continue
107
+ }
108
+ if (c === "}") {
109
+ EmitText()
110
+ PopScope()
111
+ textStart = curPos + 1
112
+ continue
113
+ }
114
+ if (c === "\\") {
115
+ EmitText()
116
+ state = State.ESCAPE
117
+ continue
118
+ }
119
+ continue
120
+
121
+ case State.ESCAPE:
122
+ if (shortFormats.has(c)) {
123
+ switch (c) {
124
+ case "P":
125
+ EmitEntity(EntityType.PARAGRAPH)
126
+ break
127
+ case "~":
128
+ EmitEntity(EntityType.NON_BREAKING_SPACE)
129
+ break
130
+ }
131
+ state = State.TEXT
132
+ textStart = curPos + 1
133
+ continue
134
+ }
135
+ if (longFormats.has(c)) {
136
+ switch (c) {
137
+ case "p":
138
+ state = State.PARAGRAPH1
139
+ continue
140
+ }
141
+ state = State.SKIP_FORMAT
142
+ continue
143
+ }
144
+ /* Include current character into a next text chunk. Backslash is also included if
145
+ * character is not among allowed ones (that is how Autodesk viewer behaves).
146
+ */
147
+ if (validEscapes.has(c)) {
148
+ textStart = curPos
149
+ } else {
150
+ textStart = curPos - 1
151
+ }
152
+ state = State.TEXT
153
+ continue
154
+
155
+ case State.PARAGRAPH1:
156
+ state = c === "x" ? State.PARAGRAPH2 : State.SKIP_FORMAT
157
+ continue
158
+
159
+ case State.PARAGRAPH2:
160
+ state = c === "q" ? State.PARAGRAPH3 : State.SKIP_FORMAT
161
+ continue
162
+
163
+ case State.PARAGRAPH3:
164
+ curEntities.push({type: EntityType.PARAGRAPH_ALIGNMENT, alignment: c})
165
+ state = State.SKIP_FORMAT
166
+ continue
167
+
168
+ case State.SKIP_FORMAT:
169
+ if (c === ";") {
170
+ textStart = curPos + 1
171
+ state = State.TEXT
172
+ }
173
+ continue
174
+
175
+ default:
176
+ throw new Error("Unhandled state")
177
+ }
178
+ }
179
+
180
+ EmitText()
181
+ }
182
+
183
+ /** @typedef MTextFormatEntity
184
+ * @property type One of EntityType
185
+ *
186
+ * @return {MTextFormatEntity[]} List of format chunks. Each chunk is either a text chunk with
187
+ * TEXT type or some format entity. Entity with type SCOPE represents format scope which has
188
+ * nested list of entities in "content" property.
189
+ */
190
+ GetContent() {
191
+ return this.entities
192
+ }
193
+
194
+ /** Return only text chunks in a flattened sequence of strings. */
195
+ *GetText() {
196
+
197
+ function *TraverseItems(items) {
198
+ for (const item of items) {
199
+ if (item.type === EntityType.TEXT) {
200
+ yield item.content
201
+ } else if (item.type === EntityType.SCOPE) {
202
+ yield *TraverseItems(item.content)
203
+ }
204
+ }
205
+ }
206
+
207
+ yield *TraverseItems(this.GetContent())
208
+ }
209
+ }
210
+
211
+ MTextFormatParser.EntityType = EntityType
@@ -0,0 +1,37 @@
1
+ /** Key for materials. */
2
+ import {BatchingKey, CompareValues} from "./BatchingKey.js";
3
+
4
+ export class MaterialKey {
5
+ /**
6
+ * @param instanceType {Number} One of InstanceType values.
7
+ * @param geometryType {?number} One of BatchingKey.GeometryType.
8
+ * @param color {number} Color ARGB value.
9
+ * @param lineType {?number} Line type ID, null for non-lines. Zero is default type (solid
10
+ * line).
11
+ */
12
+ constructor(instanceType, geometryType, color, lineType) {
13
+ this.instanceType = instanceType
14
+ this.geometryType = geometryType ?? null
15
+ this.color = color
16
+ this.lineType = lineType ?? null
17
+ }
18
+
19
+ /** Comparator function. Fields lexical order corresponds to the constructor arguments order.
20
+ * Null values are always first.
21
+ */
22
+ Compare(other) {
23
+ let c = CompareValues(this.instanceType, other.instanceType)
24
+ if (c !== 0) {
25
+ return c
26
+ }
27
+ c = CompareValues(this.geometryType, other.geometryType)
28
+ if (c !== 0) {
29
+ return c
30
+ }
31
+ c = CompareValues(this.color, other.color)
32
+ if (c !== 0) {
33
+ return c
34
+ }
35
+ return CompareValues(this.lineType, other.lineType)
36
+ }
37
+ }