dxf-json 0.0.1
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/.github/FUNDING.yml +1 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/.github/ISSUE_TEMPLATE/custom.md +10 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/pull_request_template.md +23 -0
- package/.github/workflows/npm-publish.yml +55 -0
- package/.swcrc +8 -0
- package/LICENSE +674 -0
- package/README.md +567 -0
- package/jest.config.js +20 -0
- package/package.json +56 -0
- package/src/consts/block.ts +22 -0
- package/src/consts/color.ts +6 -0
- package/src/consts/config.ts +2 -0
- package/src/consts/dimension.ts +69 -0
- package/src/consts/hatch.ts +52 -0
- package/src/consts/header.ts +10 -0
- package/src/consts/index.ts +9 -0
- package/src/consts/lineweight.ts +5 -0
- package/src/consts/measurement.ts +4 -0
- package/src/consts/obscuredLineTypes.ts +21 -0
- package/src/consts/scene.ts +2 -0
- package/src/consts/viewport.ts +62 -0
- package/src/index.ts +6 -0
- package/src/parser/AutoCadColorIndex.ts +265 -0
- package/src/parser/DxfArrayScanner.ts +161 -0
- package/src/parser/DxfParser.ts +108 -0
- package/src/parser/ParseHelpers.ts +124 -0
- package/src/parser/blocks/blocks.test.ts +97 -0
- package/src/parser/blocks/index.ts +88 -0
- package/src/parser/blocks/types.ts +15 -0
- package/src/parser/entities/arc/index.ts +2 -0
- package/src/parser/entities/arc/parser.ts +67 -0
- package/src/parser/entities/arc/types.ts +13 -0
- package/src/parser/entities/attdef/consts.ts +12 -0
- package/src/parser/entities/attdef/index.ts +3 -0
- package/src/parser/entities/attdef/parser.ts +119 -0
- package/src/parser/entities/attdef/types.ts +19 -0
- package/src/parser/entities/attribute/consts.ts +6 -0
- package/src/parser/entities/attribute/index.ts +3 -0
- package/src/parser/entities/attribute/parser.ts +198 -0
- package/src/parser/entities/attribute/types.ts +31 -0
- package/src/parser/entities/circle/index.ts +2 -0
- package/src/parser/entities/circle/parser.ts +58 -0
- package/src/parser/entities/circle/types.ts +11 -0
- package/src/parser/entities/dimension/common.ts +98 -0
- package/src/parser/entities/dimension/index.ts +24 -0
- package/src/parser/entities/dimension/types.ts +65 -0
- package/src/parser/entities/ellipse/index.ts +2 -0
- package/src/parser/entities/ellipse/parser.ts +66 -0
- package/src/parser/entities/ellipse/types.ts +13 -0
- package/src/parser/entities/entities.test.ts +86 -0
- package/src/parser/entities/hatch/boundaryPathData/edge.ts +190 -0
- package/src/parser/entities/hatch/boundaryPathData/index.ts +27 -0
- package/src/parser/entities/hatch/boundaryPathData/polyline.ts +43 -0
- package/src/parser/entities/hatch/boundaryPathData/shared.ts +16 -0
- package/src/parser/entities/hatch/index.ts +189 -0
- package/src/parser/entities/hatch/patternData.ts +57 -0
- package/src/parser/entities/hatch/types/boundaryPath.ts +72 -0
- package/src/parser/entities/hatch/types/definitionLine.ts +14 -0
- package/src/parser/entities/hatch/types/hatch.ts +47 -0
- package/src/parser/entities/hatch/types/index.ts +3 -0
- package/src/parser/entities/index.ts +87 -0
- package/src/parser/entities/insert/index.ts +2 -0
- package/src/parser/entities/insert/parser.ts +106 -0
- package/src/parser/entities/insert/types.ts +19 -0
- package/src/parser/entities/leader/consts.ts +6 -0
- package/src/parser/entities/leader/index.ts +3 -0
- package/src/parser/entities/leader/parser.ts +119 -0
- package/src/parser/entities/leader/types.ts +24 -0
- package/src/parser/entities/line/index.ts +2 -0
- package/src/parser/entities/line/parser.ts +55 -0
- package/src/parser/entities/line/types.ts +11 -0
- package/src/parser/entities/lwpolyline/consts.ts +4 -0
- package/src/parser/entities/lwpolyline/index.ts +3 -0
- package/src/parser/entities/lwpolyline/parser.ts +122 -0
- package/src/parser/entities/lwpolyline/types.ts +21 -0
- package/src/parser/entities/mtext/consts.ts +5 -0
- package/src/parser/entities/mtext/index.ts +3 -0
- package/src/parser/entities/mtext/parser.ts +195 -0
- package/src/parser/entities/mtext/types.ts +34 -0
- package/src/parser/entities/point/index.ts +2 -0
- package/src/parser/entities/point/parser.ts +60 -0
- package/src/parser/entities/point/types.ts +10 -0
- package/src/parser/entities/polyline/consts.ts +17 -0
- package/src/parser/entities/polyline/index.ts +3 -0
- package/src/parser/entities/polyline/parser.ts +126 -0
- package/src/parser/entities/polyline/types.ts +20 -0
- package/src/parser/entities/section/index.ts +2 -0
- package/src/parser/entities/section/parser.ts +104 -0
- package/src/parser/entities/section/types.ts +20 -0
- package/src/parser/entities/shared.ts +166 -0
- package/src/parser/entities/solid/index.ts +2 -0
- package/src/parser/entities/solid/parser.ts +56 -0
- package/src/parser/entities/solid/types.ts +10 -0
- package/src/parser/entities/spline/consts.ts +8 -0
- package/src/parser/entities/spline/index.ts +3 -0
- package/src/parser/entities/spline/parser.ts +121 -0
- package/src/parser/entities/spline/types.ts +22 -0
- package/src/parser/entities/text/consts.ts +21 -0
- package/src/parser/entities/text/index.ts +3 -0
- package/src/parser/entities/text/parser.ts +117 -0
- package/src/parser/entities/text/types.ts +21 -0
- package/src/parser/entities/vertex/consts.ts +10 -0
- package/src/parser/entities/vertex/index.ts +3 -0
- package/src/parser/entities/vertex/parser.ts +90 -0
- package/src/parser/entities/vertex/types.ts +17 -0
- package/src/parser/entities/viewport/index.ts +178 -0
- package/src/parser/entities/viewport/types.ts +58 -0
- package/src/parser/filterDummyBlocks.ts +49 -0
- package/src/parser/header/index.ts +30 -0
- package/src/parser/objects/common.ts +55 -0
- package/src/parser/objects/dictionary.ts +61 -0
- package/src/parser/objects/index.ts +45 -0
- package/src/parser/objects/layout.ts +136 -0
- package/src/parser/objects/plotSettings.ts +231 -0
- package/src/parser/objects/treefy.ts +53 -0
- package/src/parser/objects/types.ts +17 -0
- package/src/parser/shared/index.ts +21 -0
- package/src/parser/shared/parsePoint.ts +37 -0
- package/src/parser/shared/parserGenerator.test.ts +164 -0
- package/src/parser/shared/parserGenerator.ts +180 -0
- package/src/parser/shared/xdata/index.ts +3 -0
- package/src/parser/shared/xdata/interpreter.test.ts +85 -0
- package/src/parser/shared/xdata/interpreter.ts +65 -0
- package/src/parser/shared/xdata/parser.test.ts +66 -0
- package/src/parser/shared/xdata/parser.ts +140 -0
- package/src/parser/shared/xdata/types.ts +22 -0
- package/src/parser/tables/blockRecord/index.ts +2 -0
- package/src/parser/tables/blockRecord/parser.ts +49 -0
- package/src/parser/tables/blockRecord/types.ts +11 -0
- package/src/parser/tables/dimStyle/consts.ts +428 -0
- package/src/parser/tables/dimStyle/index.ts +3 -0
- package/src/parser/tables/dimStyle/parser.ts +37 -0
- package/src/parser/tables/dimStyle/types.ts +164 -0
- package/src/parser/tables/index.ts +2 -0
- package/src/parser/tables/layer/index.ts +2 -0
- package/src/parser/tables/layer/parser.ts +58 -0
- package/src/parser/tables/layer/types.ts +14 -0
- package/src/parser/tables/ltype/consts.ts +6 -0
- package/src/parser/tables/ltype/index.ts +3 -0
- package/src/parser/tables/ltype/parser.ts +110 -0
- package/src/parser/tables/ltype/types.ts +23 -0
- package/src/parser/tables/parser.ts +100 -0
- package/src/parser/tables/shared.ts +32 -0
- package/src/parser/tables/style/index.ts +2 -0
- package/src/parser/tables/style/parser.ts +70 -0
- package/src/parser/tables/style/types.ts +15 -0
- package/src/parser/tables/types.ts +15 -0
- package/src/parser/tables/vport/index.ts +2 -0
- package/src/parser/tables/vport/parser.ts +205 -0
- package/src/parser/tables/vport/types.ts +48 -0
- package/src/parser/types.ts +30 -0
- package/src/types/color.ts +5 -0
- package/src/types/dxfHeader.ts +21 -0
- package/src/types/entity.ts +7 -0
- package/src/types/index.ts +30 -0
- package/src/utils/binarySearch.ts +20 -0
- package/src/utils/disjointSet.ts +52 -0
- package/src/utils/flooding.ts +37 -0
- package/src/utils/functional.ts +124 -0
- package/src/utils/graph.ts +53 -0
- package/src/utils/index.ts +102 -0
- package/src/utils/queue.ts +77 -0
- package/src/utils/triangle.ts +28 -0
- package/tsconfig.json +34 -0
- package/webpack.config.js +46 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import DxfArrayScanner from './DxfArrayScanner';
|
|
2
|
+
import { parseHeader } from './header';
|
|
3
|
+
import { parseTables } from './tables';
|
|
4
|
+
import { parseBlocks } from './blocks';
|
|
5
|
+
import { parseEntities } from './entities';
|
|
6
|
+
import { parseObjects } from './objects';
|
|
7
|
+
import { isMatched } from './shared';
|
|
8
|
+
import { filterDummyBlocks } from './filterDummyBlocks';
|
|
9
|
+
import type { ParsedDxf } from './types';
|
|
10
|
+
import { Readable } from 'readable-stream';
|
|
11
|
+
export default class DxfParser {
|
|
12
|
+
parseSync(dxfString: string) {
|
|
13
|
+
const dxfLinesArray = dxfString.split(/\r\n|\r|\n/g);
|
|
14
|
+
const scanner = new DxfArrayScanner(dxfLinesArray);
|
|
15
|
+
if (!scanner.hasNext()) {
|
|
16
|
+
throw Error('Empty file');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return this.parseAll(scanner);
|
|
20
|
+
}
|
|
21
|
+
parseStream(stream: Readable) {
|
|
22
|
+
let dxfString = "";
|
|
23
|
+
const self = this;
|
|
24
|
+
return new Promise<ParsedDxf>((res, rej) => {
|
|
25
|
+
stream.on('data', (chunk) => {
|
|
26
|
+
dxfString += chunk;
|
|
27
|
+
});
|
|
28
|
+
stream.on('end', () => {
|
|
29
|
+
try {
|
|
30
|
+
const dxfLinesArray = dxfString.split(/\r\n|\r|\n/g);
|
|
31
|
+
const scanner = new DxfArrayScanner(dxfLinesArray);
|
|
32
|
+
if (!scanner.hasNext()) {
|
|
33
|
+
throw Error('Empty file');
|
|
34
|
+
}
|
|
35
|
+
res(self.parseAll(scanner));
|
|
36
|
+
} catch (err) {
|
|
37
|
+
rej(err);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
stream.on('error', (err) => {
|
|
41
|
+
rej(err);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async parseFromUrl(url: string, encoding = "utf-8", init?: RequestInit | undefined) {
|
|
47
|
+
const response = await fetch(url, init)
|
|
48
|
+
|
|
49
|
+
if (!response.body) return null;
|
|
50
|
+
|
|
51
|
+
const reader = response.body.getReader()
|
|
52
|
+
let buffer = ""
|
|
53
|
+
let decoder = new TextDecoder(encoding)
|
|
54
|
+
|
|
55
|
+
while (true) {
|
|
56
|
+
const { done, value } = await reader.read()
|
|
57
|
+
if (done) {
|
|
58
|
+
buffer += decoder.decode(new ArrayBuffer(0), { stream: false })
|
|
59
|
+
break
|
|
60
|
+
}
|
|
61
|
+
buffer += decoder.decode(value, { stream: true })
|
|
62
|
+
}
|
|
63
|
+
return this.parseSync(buffer)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
parseAll(scanner: DxfArrayScanner) {
|
|
68
|
+
const dxf: ParsedDxf = {
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
header: {},
|
|
71
|
+
blocks: {},
|
|
72
|
+
entities: [],
|
|
73
|
+
tables: {},
|
|
74
|
+
objects: {
|
|
75
|
+
byName: {},
|
|
76
|
+
byTree: undefined,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
let curr = scanner.next();
|
|
80
|
+
|
|
81
|
+
while (!isMatched(curr, 0, 'EOF')) {
|
|
82
|
+
if (isMatched(curr, 0, 'SECTION')) {
|
|
83
|
+
curr = scanner.next();
|
|
84
|
+
|
|
85
|
+
if (isMatched(curr, 2, 'HEADER')) {
|
|
86
|
+
curr = scanner.next();
|
|
87
|
+
dxf.header = parseHeader(curr, scanner);
|
|
88
|
+
} else if (isMatched(curr, 2, 'BLOCKS')) {
|
|
89
|
+
curr = scanner.next();
|
|
90
|
+
dxf.blocks = parseBlocks(curr, scanner);
|
|
91
|
+
}
|
|
92
|
+
else if (isMatched(curr, 2, 'ENTITIES')) {
|
|
93
|
+
curr = scanner.next();
|
|
94
|
+
dxf.entities = parseEntities(curr, scanner);
|
|
95
|
+
}
|
|
96
|
+
else if (isMatched(curr, 2, 'TABLES')) {
|
|
97
|
+
curr = scanner.next();
|
|
98
|
+
dxf.tables = parseTables(curr, scanner);
|
|
99
|
+
} else if (isMatched(curr, 2, 'OBJECTS')) {
|
|
100
|
+
curr = scanner.next();
|
|
101
|
+
dxf.objects = parseObjects(curr, scanner);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
curr = scanner.next();
|
|
105
|
+
}
|
|
106
|
+
return filterDummyBlocks(dxf);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import AUTO_CAD_COLOR_INDEX from './AutoCadColorIndex';
|
|
2
|
+
import DxfArrayScanner, { ScannerGroup } from './DxfArrayScanner';
|
|
3
|
+
import { CommonDxfEntity, skipApplicationGroups } from './entities/shared';
|
|
4
|
+
import { ViewportEntity } from './entities/viewport/types';
|
|
5
|
+
import { isMatched } from './shared';
|
|
6
|
+
import { parseXData } from './shared/xdata';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns the truecolor value of the given AutoCad color index value
|
|
10
|
+
* @param {import('../types').ColorIndex} index
|
|
11
|
+
* @return {import('../types').ColorInstance} truecolor value as a number
|
|
12
|
+
*/
|
|
13
|
+
export function getAcadColor(index: number) {
|
|
14
|
+
return AUTO_CAD_COLOR_INDEX[index];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Some entities may contain embedded object which is started by group 101. All the rest data until
|
|
18
|
+
* end of entity should not be interpreted as entity attributes. There is no documentation for this
|
|
19
|
+
* feature.
|
|
20
|
+
* @param scanner
|
|
21
|
+
*/
|
|
22
|
+
export function skipEmbeddedObject(scanner: DxfArrayScanner) {
|
|
23
|
+
/* Ensure proper start group. */
|
|
24
|
+
scanner.rewind();
|
|
25
|
+
let curr = scanner.next();
|
|
26
|
+
if (curr.code !== 101) {
|
|
27
|
+
throw new Error('Bad call for skipEmbeddedObject()');
|
|
28
|
+
}
|
|
29
|
+
do {
|
|
30
|
+
curr = scanner.next();
|
|
31
|
+
} while (curr.code !== 0);
|
|
32
|
+
scanner.rewind();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Attempts to parse codes common to all entities. Returns true if the group
|
|
37
|
+
* was handled by this function.
|
|
38
|
+
* @param {*} entity - the entity currently being parsed
|
|
39
|
+
* @param {*} curr - the current group being parsed
|
|
40
|
+
*/
|
|
41
|
+
export function checkCommonEntityProperties(entity: CommonDxfEntity, curr: ScannerGroup, scanner: DxfArrayScanner) {
|
|
42
|
+
if (isMatched(curr, 102)) {
|
|
43
|
+
skipApplicationGroups(curr, scanner);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
switch (curr.code) {
|
|
48
|
+
case 0:
|
|
49
|
+
entity.type = curr.value as string;
|
|
50
|
+
break;
|
|
51
|
+
case 5:
|
|
52
|
+
entity.handle = curr.value as string;
|
|
53
|
+
break;
|
|
54
|
+
case 330:
|
|
55
|
+
if (!entity.ownerDictionarySoftId) {
|
|
56
|
+
entity.ownerDictionarySoftId = curr.value;
|
|
57
|
+
} else {
|
|
58
|
+
entity.ownerBlockRecordSoftId = curr.value;
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case 360:
|
|
62
|
+
entity.ownerdictionaryHardId = curr.value;
|
|
63
|
+
break;
|
|
64
|
+
case 67:
|
|
65
|
+
entity.isInPaperSpace = !!curr.value;
|
|
66
|
+
break;
|
|
67
|
+
case 8:
|
|
68
|
+
entity.layer = curr.value;
|
|
69
|
+
break;
|
|
70
|
+
// Code 6 of an entity indicates inheritance of properties (eg. color).
|
|
71
|
+
// BYBLOCK means inherits from block
|
|
72
|
+
// BYLAYER (default) mean inherits from layer
|
|
73
|
+
case 6:
|
|
74
|
+
entity.lineType = curr.value;
|
|
75
|
+
break;
|
|
76
|
+
case 347:
|
|
77
|
+
entity.materialObjectHardId = curr.value;
|
|
78
|
+
break;
|
|
79
|
+
case 62: // Acad Index Color. 0 inherits ByBlock. 256 inherits ByLayer. Default is bylayer
|
|
80
|
+
entity.colorIndex = curr.value;
|
|
81
|
+
entity.color = getAcadColor(Math.abs(curr.value));
|
|
82
|
+
break;
|
|
83
|
+
case 370:
|
|
84
|
+
//From https://www.woutware.com/Forum/Topic/955/lineweight?returnUrl=%2FForum%2FUserPosts%3FuserId%3D478262319
|
|
85
|
+
// An integer representing 100th of mm, must be one of the following values:
|
|
86
|
+
// 0, 5, 9, 13, 15, 18, 20, 25, 30, 35, 40, 50, 53, 60, 70, 80, 90, 100, 106, 120, 140, 158, 200, 211.
|
|
87
|
+
// -3 = STANDARD, -2 = BYLAYER, -1 = BYBLOCK
|
|
88
|
+
entity.lineweight = curr.value;
|
|
89
|
+
break;
|
|
90
|
+
case 48:
|
|
91
|
+
entity.lineTypeScale = curr.value;
|
|
92
|
+
break;
|
|
93
|
+
case 60:
|
|
94
|
+
entity.isVisible = !!curr.value;
|
|
95
|
+
break;
|
|
96
|
+
case 92:
|
|
97
|
+
entity.proxyByte = curr.value;
|
|
98
|
+
break;
|
|
99
|
+
case 310:
|
|
100
|
+
entity.proxyEntity = curr.value;
|
|
101
|
+
break;
|
|
102
|
+
case 100:
|
|
103
|
+
// general한 목적으로는 현 구조로 여기서 처리 불가
|
|
104
|
+
break;
|
|
105
|
+
case 420:
|
|
106
|
+
entity.color = curr.value;
|
|
107
|
+
break;
|
|
108
|
+
case 430:
|
|
109
|
+
entity.transparency = curr.value;
|
|
110
|
+
break;
|
|
111
|
+
case 390:
|
|
112
|
+
entity.plotStyleHardId = curr.value;
|
|
113
|
+
break;
|
|
114
|
+
case 284:
|
|
115
|
+
entity.shadowMode = curr.value;
|
|
116
|
+
break;
|
|
117
|
+
case 1001:
|
|
118
|
+
entity.xdata = parseXData(curr, scanner);
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import DxfArrayScanner from '../DxfArrayScanner';
|
|
2
|
+
import { parseBlock, parseBlocks } from '.';
|
|
3
|
+
import { isMatched } from '../shared';
|
|
4
|
+
|
|
5
|
+
const content = ` 0
|
|
6
|
+
BLOCK
|
|
7
|
+
2
|
|
8
|
+
block-0
|
|
9
|
+
100
|
|
10
|
+
AcDbEntity
|
|
11
|
+
0
|
|
12
|
+
ENDBLK
|
|
13
|
+
5
|
|
14
|
+
endblk-0
|
|
15
|
+
100
|
|
16
|
+
AcDbEntity
|
|
17
|
+
100
|
|
18
|
+
AcDbBlockEnd
|
|
19
|
+
0
|
|
20
|
+
BLOCK
|
|
21
|
+
2
|
|
22
|
+
block-1
|
|
23
|
+
100
|
|
24
|
+
AcDbEntity
|
|
25
|
+
0
|
|
26
|
+
ENDBLK
|
|
27
|
+
5
|
|
28
|
+
endblk-1
|
|
29
|
+
100
|
|
30
|
+
AcDbEntity
|
|
31
|
+
100
|
|
32
|
+
AcDbBlockEnd
|
|
33
|
+
0
|
|
34
|
+
ENDSEC
|
|
35
|
+
0
|
|
36
|
+
SECTION
|
|
37
|
+
0
|
|
38
|
+
EOF
|
|
39
|
+
`.split('\n');
|
|
40
|
+
|
|
41
|
+
describe('BLOCK section', () => {
|
|
42
|
+
describe('parseBlock', () => {
|
|
43
|
+
it('parseBlock 한 번 실행하고 나면 scanner.next()가 다음 BLOCK의 <0, BLOCK>를 반환한다.', () => {
|
|
44
|
+
const scanner = new DxfArrayScanner(content);
|
|
45
|
+
let curr = scanner.next();
|
|
46
|
+
|
|
47
|
+
curr = scanner.next(); // 집어넣을 때 이미 <0, BLOCK>을 소모한 상태여야 함
|
|
48
|
+
parseBlock(curr, scanner);
|
|
49
|
+
|
|
50
|
+
curr = scanner.next();
|
|
51
|
+
|
|
52
|
+
expect(curr.code).toBe(0);
|
|
53
|
+
expect(curr.value).toBe('BLOCK');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('parseBlock은 모든 BLOCK을 소모하여야 한다.', () => {
|
|
57
|
+
const scanner = new DxfArrayScanner(content);
|
|
58
|
+
let curr = scanner.next();
|
|
59
|
+
|
|
60
|
+
curr = scanner.next();
|
|
61
|
+
const block0 = parseBlock(curr, scanner);
|
|
62
|
+
|
|
63
|
+
curr = scanner.next();
|
|
64
|
+
expect(isMatched(curr, 0, 'BLOCK')).toBeTruthy();
|
|
65
|
+
|
|
66
|
+
curr = scanner.next();
|
|
67
|
+
const block1 = parseBlock(curr, scanner);
|
|
68
|
+
|
|
69
|
+
expect(block0.name).toBe('block-0');
|
|
70
|
+
expect(block1.name).toBe('block-1');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('parseBlocks', () => {
|
|
75
|
+
it('parseBlocks 한 번 실행하고 나면 scanner.next()가 다음 SECTION의 <0, SECTION>을 반환한다.', () => {
|
|
76
|
+
const scanner = new DxfArrayScanner(content);
|
|
77
|
+
let curr = scanner.next();
|
|
78
|
+
|
|
79
|
+
parseBlocks(curr, scanner);
|
|
80
|
+
|
|
81
|
+
curr = scanner.next();
|
|
82
|
+
|
|
83
|
+
expect(curr.code).toBe(0);
|
|
84
|
+
expect(curr.value).toBe('SECTION');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('parseBlocks는 모든 BLOCK을 반환해야 한다.', () => {
|
|
88
|
+
const scanner = new DxfArrayScanner(content);
|
|
89
|
+
let curr = scanner.next();
|
|
90
|
+
|
|
91
|
+
const blocks = parseBlocks(curr, scanner);
|
|
92
|
+
|
|
93
|
+
expect(blocks['block-0']).toMatchObject({ name: 'block-0' });
|
|
94
|
+
expect(blocks['block-1']).toMatchObject({ name: 'block-1' });
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type DxfArrayScanner from '../DxfArrayScanner';
|
|
2
|
+
import type { ScannerGroup } from '../DxfArrayScanner';
|
|
3
|
+
import { parseEntities } from '../entities';
|
|
4
|
+
import { parsePoint } from '../shared/parsePoint';
|
|
5
|
+
import { ensureHandle, isMatched } from '../shared';
|
|
6
|
+
|
|
7
|
+
export function parseBlocks(curr: ScannerGroup, scanner: DxfArrayScanner) {
|
|
8
|
+
let blocks: any = {};
|
|
9
|
+
|
|
10
|
+
while (!isMatched(curr, 0, 'EOF')) {
|
|
11
|
+
if (isMatched(curr, 0, 'ENDSEC')) {
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (isMatched(curr, 0, 'BLOCK')) {
|
|
16
|
+
curr = scanner.next();
|
|
17
|
+
const block = parseBlock(curr, scanner);
|
|
18
|
+
|
|
19
|
+
ensureHandle(block);
|
|
20
|
+
if (block.name) {
|
|
21
|
+
blocks[block.name] = block;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
curr = scanner.next();
|
|
26
|
+
}
|
|
27
|
+
return blocks;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function parseBlock(curr: ScannerGroup, scanner: DxfArrayScanner) {
|
|
31
|
+
let block: any = {};
|
|
32
|
+
|
|
33
|
+
while (!isMatched(curr, 0, 'EOF')) {
|
|
34
|
+
if (isMatched(curr, 0, 'ENDBLK')) {
|
|
35
|
+
// 당장 ENDBLK 파싱이 없어서 임시로 대충 소비함
|
|
36
|
+
// 소비 안하면 ENTITY에 딸려들어가서 문제 생김
|
|
37
|
+
curr = scanner.next();
|
|
38
|
+
while (!isMatched(curr, 0, 'EOF')) {
|
|
39
|
+
if (isMatched(curr, 100, 'AcDbBlockEnd')) {
|
|
40
|
+
return block;
|
|
41
|
+
}
|
|
42
|
+
curr = scanner.next();
|
|
43
|
+
}
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
switch (curr.code) {
|
|
48
|
+
case 1:
|
|
49
|
+
block.xrefPath = curr.value;
|
|
50
|
+
break;
|
|
51
|
+
case 2:
|
|
52
|
+
block.name = curr.value;
|
|
53
|
+
break;
|
|
54
|
+
case 3:
|
|
55
|
+
block.name2 = curr.value;
|
|
56
|
+
break;
|
|
57
|
+
case 5:
|
|
58
|
+
block.handle = curr.value;
|
|
59
|
+
break;
|
|
60
|
+
case 8:
|
|
61
|
+
block.layer = curr.value;
|
|
62
|
+
break;
|
|
63
|
+
case 10:
|
|
64
|
+
block.position = parsePoint(scanner);
|
|
65
|
+
break;
|
|
66
|
+
case 67:
|
|
67
|
+
block.paperSpace = curr.value && curr.value == 1 ? true : false;
|
|
68
|
+
break;
|
|
69
|
+
case 70:
|
|
70
|
+
if (curr.value !== 0) {
|
|
71
|
+
block.type = curr.value;
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
case 100:
|
|
75
|
+
// ignore class markers
|
|
76
|
+
break;
|
|
77
|
+
case 330:
|
|
78
|
+
block.ownerHandle = curr.value;
|
|
79
|
+
break;
|
|
80
|
+
case 0:
|
|
81
|
+
block.entities = parseEntities(curr, scanner);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
curr = scanner.next();
|
|
86
|
+
}
|
|
87
|
+
return block;
|
|
88
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Point3D } from '../../types';
|
|
2
|
+
import type { CommonDxfEntity } from '../entities/shared';
|
|
3
|
+
|
|
4
|
+
export interface DxfBlock {
|
|
5
|
+
type: number; // bit flag of BlockTypeFlag
|
|
6
|
+
name: string;
|
|
7
|
+
name2: string;
|
|
8
|
+
handle: string;
|
|
9
|
+
ownerHandle: string;
|
|
10
|
+
layer: string;
|
|
11
|
+
position: Point3D;
|
|
12
|
+
paperSpace: boolean;
|
|
13
|
+
xrefPath: string;
|
|
14
|
+
entities?: CommonDxfEntity[];
|
|
15
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type DxfArrayScanner from '../../DxfArrayScanner';
|
|
2
|
+
import type { ScannerGroup } from '../../DxfArrayScanner';
|
|
3
|
+
import {
|
|
4
|
+
createParser,
|
|
5
|
+
DXFParserSnippet,
|
|
6
|
+
Identity,
|
|
7
|
+
PointParser,
|
|
8
|
+
} from '../../shared/parserGenerator';
|
|
9
|
+
import { CommonEntitySnippets } from '../shared';
|
|
10
|
+
|
|
11
|
+
const DefaultArcEntity = {
|
|
12
|
+
extrusionDirection: { x: 0, y: 0, z: 1 },
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const ArcEntityParserSnippets: DXFParserSnippet[] = [
|
|
16
|
+
{
|
|
17
|
+
code: 210,
|
|
18
|
+
name: 'extrusionDirection',
|
|
19
|
+
parser: PointParser,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
code: 51,
|
|
23
|
+
name: 'endAngle',
|
|
24
|
+
parser: Identity,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
code: 50,
|
|
28
|
+
name: 'startAngle',
|
|
29
|
+
parser: Identity,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
code: 100,
|
|
33
|
+
name: 'subclassMarker',
|
|
34
|
+
parser: Identity,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
code: 40,
|
|
38
|
+
name: 'radius',
|
|
39
|
+
parser: Identity,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
code: 10,
|
|
43
|
+
name: 'center',
|
|
44
|
+
parser: PointParser,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
code: 39,
|
|
48
|
+
name: 'thickness',
|
|
49
|
+
parser: Identity,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
// skip for AcDbCircle
|
|
53
|
+
code: 100,
|
|
54
|
+
},
|
|
55
|
+
...CommonEntitySnippets,
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
export class ArcEntityParser {
|
|
59
|
+
static ForEntityName = 'ARC';
|
|
60
|
+
private parser = createParser(ArcEntityParserSnippets, DefaultArcEntity);
|
|
61
|
+
|
|
62
|
+
parseEntity(scanner: DxfArrayScanner, curr: ScannerGroup) {
|
|
63
|
+
const entity = {} as any;
|
|
64
|
+
this.parser(curr, scanner, entity);
|
|
65
|
+
return entity;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Point3D } from '../../../types';
|
|
2
|
+
import type { CommonDxfEntity } from '../shared';
|
|
3
|
+
|
|
4
|
+
export interface ArcEntity extends CommonDxfEntity {
|
|
5
|
+
type: 'ARC';
|
|
6
|
+
subclassMarker: 'AcDbArc';
|
|
7
|
+
thickness: number;
|
|
8
|
+
center: Point3D;
|
|
9
|
+
radius: number;
|
|
10
|
+
startAngle: number;
|
|
11
|
+
endAngle: number;
|
|
12
|
+
extrusionDirection: Point3D;
|
|
13
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type DxfArrayScanner from '../../DxfArrayScanner';
|
|
2
|
+
import type { ScannerGroup } from '../../DxfArrayScanner';
|
|
3
|
+
import {
|
|
4
|
+
createParser,
|
|
5
|
+
DXFParserSnippet,
|
|
6
|
+
Identity,
|
|
7
|
+
PointParser,
|
|
8
|
+
ToBoolean,
|
|
9
|
+
} from '../../shared/parserGenerator';
|
|
10
|
+
import { DefaultTextEntity, TextEntityParserSnippets } from '../text';
|
|
11
|
+
import type { AttdefEntity } from './types';
|
|
12
|
+
|
|
13
|
+
const DefaultAttDefEntity = {
|
|
14
|
+
...DefaultTextEntity,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const AttDefEntityParserSnippets: DXFParserSnippet[] = [
|
|
18
|
+
{
|
|
19
|
+
code: 2, // tag. 왜 다시 나오는지 모르겠음
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
code: 40,
|
|
23
|
+
name: 'annotationScale',
|
|
24
|
+
parser: Identity,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
code: 10,
|
|
28
|
+
name: 'alignmentPoint',
|
|
29
|
+
parser: PointParser,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
code: 340,
|
|
33
|
+
name: 'secondaryAttributesHardIds',
|
|
34
|
+
isMultiple: true,
|
|
35
|
+
parser: Identity,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
code: 70,
|
|
39
|
+
name: 'numberOfSecondaryAttributes',
|
|
40
|
+
parser: Identity,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
code: 70,
|
|
44
|
+
name: 'isReallyLocked',
|
|
45
|
+
parser: ToBoolean,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
code: 70,
|
|
49
|
+
name: 'mtextFlag',
|
|
50
|
+
parser: Identity,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
code: 280,
|
|
54
|
+
name: 'isDuplicatedRecord',
|
|
55
|
+
parser: ToBoolean,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
code: 100, // AcDbXrecord, skip
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
code: 280,
|
|
62
|
+
name: 'isLocked',
|
|
63
|
+
parser: ToBoolean,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
code: 74,
|
|
67
|
+
name: 'valign',
|
|
68
|
+
parser: Identity,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
code: 73, // field length, useless
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
code: 70,
|
|
75
|
+
name: 'attributeFlag',
|
|
76
|
+
parser: Identity,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
code: 2,
|
|
80
|
+
name: 'tag',
|
|
81
|
+
parser: Identity,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
code: 3,
|
|
85
|
+
name: 'prompt',
|
|
86
|
+
parser: Identity,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
code: 280, // version number, always 0, useless
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
code: 100,
|
|
93
|
+
name: 'subclassMarker',
|
|
94
|
+
parser: Identity,
|
|
95
|
+
},
|
|
96
|
+
...TextEntityParserSnippets.slice(2),
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
export class AttDefEntityParser {
|
|
100
|
+
static ForEntityName = 'ATTDEF';
|
|
101
|
+
private parser = createParser(
|
|
102
|
+
AttDefEntityParserSnippets,
|
|
103
|
+
DefaultAttDefEntity,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
parseEntity(scanner: DxfArrayScanner, curr: ScannerGroup) {
|
|
107
|
+
const entity = {} as any;
|
|
108
|
+
this.parser(curr, scanner, entity);
|
|
109
|
+
return entity as AttdefEntity;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// entity.invisible = !!(curr.value & 0x01);
|
|
114
|
+
// entity.constant = !!(curr.value & 0x02);
|
|
115
|
+
// entity.verificationRequired = !!(curr.value & 0x04);
|
|
116
|
+
// entity.preset = !!(curr.value & 0x08);
|
|
117
|
+
|
|
118
|
+
// entity.backwards = !!(curr.value & 0x02);
|
|
119
|
+
// entity.mirrored = !!(curr.value & 0x04);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Point3D } from '../../../types';
|
|
2
|
+
import type { TextEntity } from '../text';
|
|
3
|
+
|
|
4
|
+
export interface AttdefEntity
|
|
5
|
+
extends Omit<TextEntity, 'type' | 'subclassMarker'> {
|
|
6
|
+
type: 'ATTDEF';
|
|
7
|
+
subclassMarker: 'AcDbAttributeDefinition';
|
|
8
|
+
prompt: string;
|
|
9
|
+
tag: string;
|
|
10
|
+
attributeFlag: number;
|
|
11
|
+
isLocked: boolean;
|
|
12
|
+
isDuplicatedRecord: boolean;
|
|
13
|
+
mtextFlag: number;
|
|
14
|
+
isReallyLocked: boolean;
|
|
15
|
+
numberOfSecondaryAttributes: number;
|
|
16
|
+
secondaryAttributesHardIds: string[];
|
|
17
|
+
alignmentPoint: Point3D;
|
|
18
|
+
annotationScale: number;
|
|
19
|
+
}
|