Skip to content

Commit 483ed02

Browse files
committed
dxf-calculations
1 parent 151b7de commit 483ed02

File tree

3 files changed

+204
-10
lines changed

3 files changed

+204
-10
lines changed

src/BatchingKey.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ export class BatchingKey {
1010
* @param lineType {?number} Line type ID, null for non-lines. Zero is default type (solid
1111
* line).
1212
*/
13-
constructor(layerName, blockName, geometryType, color, lineType) {
13+
constructor(layerName, blockName, geometryType, color, lineType, vertices) {
1414
this.layerName = layerName ?? null
1515
this.blockName = blockName ?? null
1616
this.geometryType = geometryType ?? null
1717
this.color = color
1818
this.lineType = lineType ?? null
19+
this.vertices = vertices
1920
}
2021

2122
/** Comparator function. Fields lexical order corresponds to the constructor arguments order.

src/DxfScene.js

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export class DxfScene {
9595
this.pointShapeBlock = null
9696
this.numBlocksFlattened = 0
9797
this.numEntitiesFiltered = 0
98+
this.entityVertices = []
9899
}
99100

100101
/** Build the scene from the provided parsed DXF.
@@ -277,8 +278,16 @@ export class DxfScene {
277278
}
278279
}
279280
}
281+
282+
checkTangentLayer (layer) {
283+
const bendKeywords = ['tangent', 'bend_extent'];
284+
return bendKeywords.some(substr=>layer.toLowerCase().indexOf(substr) >= 0);
285+
}
280286

281287
_ProcessDxfEntity(entity, blockCtx = null) {
288+
if (this.checkTangentLayer(entity.layer)) {
289+
return;
290+
}
282291
let renderEntities
283292
switch (entity.type) {
284293
case "LINE":
@@ -341,6 +350,7 @@ export class DxfScene {
341350
* @param blockCtx {?BlockContext}
342351
*/
343352
_ProcessEntity(entity, blockCtx = null) {
353+
this.entityVertices.push(entity);
344354
switch (entity.type) {
345355
case Entity.Type.POINTS:
346356
this._ProcessPoints(entity, blockCtx)
@@ -617,7 +627,7 @@ export class DxfScene {
617627
if (isShaped) {
618628
/* Shaped mark should be instanced. */
619629
const key = new BatchingKey(layer, POINT_SHAPE_BLOCK_NAME,
620-
BatchingKey.GeometryType.POINT_INSTANCE, color, 0)
630+
BatchingKey.GeometryType.POINT_INSTANCE, color, 0, entity?.vertices ? entity?.vertices : [])
621631
const batch = this._GetBatch(key)
622632
batch.PushVertex(this._TransformVertex(entity.position))
623633
this._CreatePointShapeBlock()
@@ -1452,7 +1462,7 @@ export class DxfScene {
14521462
}
14531463
} else {
14541464
const key = new BatchingKey(layer, entity.name, BatchingKey.GeometryType.BLOCK_INSTANCE,
1455-
color, lineType)
1465+
color, lineType, entity?.vertices ? entity?.vertices : [])
14561466
const batch = this._GetBatch(key)
14571467
batch.PushInstanceTransform(transform)
14581468
}
@@ -1470,7 +1480,7 @@ export class DxfScene {
14701480
color = blockBatch.key.color
14711481
}
14721482
//XXX line type
1473-
const key = new BatchingKey(layerName, null, blockBatch.key.geometryType, color, lineType)
1483+
const key = new BatchingKey(layerName, null, blockBatch.key.geometryType, color, lineType, [])
14741484
const batch = this._GetBatch(key)
14751485
batch.Merge(blockBatch, transform)
14761486
}
@@ -1852,7 +1862,7 @@ export class DxfScene {
18521862
*/
18531863
_ProcessPoints(entity, blockCtx = null) {
18541864
const key = new BatchingKey(entity.layer, blockCtx?.name,
1855-
BatchingKey.GeometryType.POINTS, entity.color, 0)
1865+
BatchingKey.GeometryType.POINTS, entity.color, 0, entity?.vertices ? entity?.vertices : [])
18561866
const batch = this._GetBatch(key)
18571867
for (const v of entity.vertices) {
18581868
batch.PushVertex(this._TransformVertex(v, blockCtx))
@@ -1868,7 +1878,7 @@ export class DxfScene {
18681878
throw Error("Even number of vertices expected")
18691879
}
18701880
const key = new BatchingKey(entity.layer, blockCtx?.name,
1871-
BatchingKey.GeometryType.LINES, entity.color, entity.lineType)
1881+
BatchingKey.GeometryType.LINES, entity.color, entity.lineType, entity?.vertices ? entity?.vertices : [])
18721882
const batch = this._GetBatch(key)
18731883
for (const v of entity.vertices) {
18741884
batch.PushVertex(this._TransformVertex(v, blockCtx))
@@ -1890,7 +1900,7 @@ export class DxfScene {
18901900
if (verticesCount <= 3) {
18911901
const key = new BatchingKey(entity.layer, blockCtx?.name,
18921902
BatchingKey.GeometryType.LINES, entity.color,
1893-
entity.lineType)
1903+
entity.lineType, entity?.vertices ? entity?.vertices : [])
18941904
const batch = this._GetBatch(key)
18951905
let prev = null
18961906
for (const v of entity.vertices) {
@@ -1909,7 +1919,7 @@ export class DxfScene {
19091919

19101920
const key = new BatchingKey(entity.layer, blockCtx?.name,
19111921
BatchingKey.GeometryType.INDEXED_LINES,
1912-
entity.color, entity.lineType)
1922+
entity.color, entity.lineType, entity?.vertices ? entity?.vertices : [])
19131923
const batch = this._GetBatch(key)
19141924
/* Line may be split if exceeds chunk limit. */
19151925
for (const lineChunk of entity._IterateLineChunks()) {
@@ -1938,7 +1948,7 @@ export class DxfScene {
19381948
}
19391949
const key = new BatchingKey(entity.layer, blockCtx?.name,
19401950
BatchingKey.GeometryType.INDEXED_TRIANGLES,
1941-
entity.color, 0)
1951+
entity.color, 0, entity?.vertices ? entity?.vertices : [])
19421952
const batch = this._GetBatch(key)
19431953
//XXX splitting into chunks is not yet implemented. Currently used only for text glyphs so
19441954
// should fit into one chunk
@@ -2087,7 +2097,8 @@ export class DxfScene {
20872097
layers: [],
20882098
origin: this.origin,
20892099
bounds: this.bounds,
2090-
hasMissingChars: this.hasMissingChars
2100+
hasMissingChars: this.hasMissingChars,
2101+
entityVertices: this.entityVertices
20912102
}
20922103

20932104
const buffers = {

src/DxfViewer.js

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ export class DxfViewer {
2121
* @param options Some options can be overridden if specified. See DxfViewer.DefaultOptions.
2222
*/
2323
constructor(domContainer, options = null) {
24+
this.dimensions = {dxfWidth: 0, dxfHeight: 0};
25+
this.totalCuts = 0;
26+
this.cutsLength = 0;
27+
this.area = 0;
28+
this.shapes = [];
29+
this.bends = [];
30+
2431
this.domContainer = domContainer
2532
this.options = Object.create(DxfViewer.DefaultOptions)
2633
if (options) {
@@ -119,6 +126,15 @@ export class DxfViewer {
119126
return this.parsedDxf
120127
}
121128

129+
GetFileDetails() {
130+
return {
131+
dimensions: this.dimensions,
132+
totalCuts: this.totalCuts,
133+
cutsLength: this.cutsLength,
134+
area: this.area,
135+
}
136+
}
137+
122138
SetSize(width, height) {
123139
this._EnsureRenderer()
124140

@@ -172,12 +188,17 @@ export class DxfViewer {
172188

173189
this.worker = new DxfWorker(workerFactory ? workerFactory() : null)
174190
const {scene, dxf} = await this.worker.Load(url, fonts, this.options, progressCbk)
191+
this.SetFileDetails(scene?.entityVertices);
175192
await this.worker.Destroy()
176193
this.worker = null
177194
this.parsedDxf = dxf
178195

179196
this.origin = scene.origin
180197
this.bounds = scene.bounds
198+
this.dimensions = {
199+
dxfWidth: scene.bounds.maxY - scene.bounds.minY,
200+
dxfHeight: scene.bounds.maxX - scene.bounds.minX
201+
};
181202
this.hasMissingChars = scene.hasMissingChars
182203

183204
for (const layer of scene.layers) {
@@ -234,6 +255,167 @@ export class DxfViewer {
234255
this._EnsureRenderer()
235256
this.renderer.render(this.scene, this.camera)
236257
}
258+
259+
checkTangentLayer (layer) {
260+
const bendKeywords = ['tangent', 'bend_extent'];
261+
return bendKeywords.some(substr=>layer.toLowerCase().indexOf(substr) >= 0);
262+
}
263+
264+
checkBendLayer (layer) {
265+
const bendKeywords = ['bend', 'reference'];
266+
return bendKeywords.some(substr=>layer.toLowerCase().indexOf(substr) >= 0);
267+
}
268+
269+
_TransformVertex(vs=[]) {
270+
return vs.map(v=>{return { x: v.x - this.origin.x, y: v.y - this.origin.y }})
271+
}
272+
273+
getAllLastPoints(entities) {
274+
let points = [];
275+
for (let i = 0; i < entities.length; i++) {
276+
const entity = entities[i];
277+
if(!this.checkBendLayer(entity.layer) && !entity.lineType && !this.checkTangentLayer(entity.layer)){
278+
points.push({
279+
startPointx : entity.vertices[0].x,
280+
startPointy : entity.vertices[0].y,
281+
endPointx : entity.vertices[entity.vertices.length - 1].x,
282+
endPointy : entity.vertices[entity.vertices.length - 1].y,
283+
visited: false,
284+
entity,
285+
points: entity.vertices,
286+
});
287+
}
288+
}
289+
return points;
290+
}
291+
292+
SetFileDetails(entityVertices) {
293+
let lastPoints = this.getAllLastPoints(entityVertices);
294+
let cuts = [];
295+
var maxArea = 0;
296+
let cutLength = 0;
297+
298+
function round3(value){
299+
return Math.round(value*1000)/1000;
300+
}
301+
302+
function markPointVisited ({startPointx, startPointy, endPointx, endPointy}) {
303+
const index = lastPoints.findIndex(el=> el.startPointx===startPointx && el.startPointy===startPointy && el.endPointx===endPointx && el.endPointy===endPointy);
304+
if(index >= 0) {
305+
lastPoints[index].visited = true;
306+
}
307+
}
308+
309+
function visitAllPoints({startPointx, startPointy, endPointx, endPointy}, entity, points) {
310+
markPointVisited({startPointx, startPointy, endPointx, endPointy});
311+
let allPoints = [...points];
312+
let ended = false;
313+
let connectedPoints = [entity];
314+
while(!ended) {
315+
const index = lastPoints.findIndex(
316+
el =>
317+
(round3(el.startPointx)===round3(endPointx) && round3(el.startPointy)===round3(endPointy) && !el.visited) ||
318+
(round3(el.endPointx)===round3(startPointx) && round3(el.endPointy)===round3(startPointy) && !el.visited) ||
319+
(round3(el.endPointx)===round3(endPointx) && round3(el.endPointy)===round3(endPointy) && !el.visited) ||
320+
(round3(el.startPointx)===round3(startPointx) && round3(el.startPointy)===round3(startPointy) && !el.visited)
321+
);
322+
if (index < 0) {
323+
ended = true;
324+
cuts.push(connectedPoints);
325+
} else {
326+
327+
if(round3(lastPoints[index].startPointx)===round3(endPointx) && round3(lastPoints[index].startPointy)===round3(endPointy)){
328+
allPoints = [...allPoints, ...lastPoints[index].points];
329+
}
330+
else if(round3(lastPoints[index].endPointx)===round3(startPointx) && round3(lastPoints[index].endPointy)===round3(startPointy)){
331+
allPoints = [...lastPoints[index].points, ...allPoints];
332+
}
333+
else if(round3(lastPoints[index].endPointx)===round3(endPointx) && round3(lastPoints[index].endPointy)===round3(endPointy)){
334+
allPoints = [ ...allPoints, ...lastPoints[index].points.reverse()];
335+
}
336+
else if(round3(lastPoints[index].startPointx)===round3(startPointx) && round3(lastPoints[index].startPointy)===round3(startPointy)){
337+
allPoints = [...lastPoints[index].points.reverse(), ...allPoints];
338+
}
339+
340+
startPointx = allPoints[0].x;
341+
startPointy = allPoints[0].y;
342+
endPointx = allPoints[allPoints.length - 1].x;
343+
endPointy = allPoints[allPoints.length - 1].y;
344+
entity = lastPoints[index].entity;
345+
lastPoints[index].visited = true;
346+
connectedPoints.push(lastPoints[index].entity);
347+
}
348+
}
349+
return allPoints.map(el=>new three.Vector2(el.x, el.y));
350+
}
351+
352+
function isPointVisited({startPointx, startPointy, endPointx, endPointy}) {
353+
const found = lastPoints.find(el=> el.startPointx===startPointx && el.startPointy===startPointy && el.endPointx===endPointx && el.endPointy===endPointy);
354+
if(found) {
355+
return found.visited;
356+
}
357+
else {
358+
return true;
359+
}
360+
}
361+
362+
for (let i = 0; i < entityVertices.length; i++) {
363+
const entity = entityVertices[i];
364+
if(!this.checkBendLayer(entity.layer) && !entity.lineType && !this.checkTangentLayer(entity.layer) && !isPointVisited({
365+
startPointx : entity.vertices[0].x,
366+
startPointy : entity.vertices[0].y,
367+
endPointx : entity.vertices[entity.vertices.length - 1].x,
368+
endPointy : entity.vertices[entity.vertices.length - 1].y,
369+
})) {
370+
const points = visitAllPoints({
371+
startPointx : entity.vertices[0].x,
372+
startPointy : entity.vertices[0].y,
373+
endPointx : entity.vertices[entity.vertices.length - 1].x,
374+
endPointy : entity.vertices[entity.vertices.length - 1].y,
375+
}, entity, entity.vertices);
376+
this.shapes.push(points);
377+
cutLength += this.getVectorDistance(points);
378+
const area = this.calcPolygonArea(points);
379+
if (area > maxArea){
380+
maxArea = area;
381+
}
382+
} else if(this.checkBendLayer(entity.layer)) {
383+
this.bends.push(entity.vertices.map(el=>new three.Vector2(el.x, el.y)));
384+
}
385+
}
386+
387+
console.log("TOTAL LENGTH : " + cutLength.toFixed(3));
388+
console.log("TOTAL CUTS : " + cuts.length);
389+
console.log("TOTAL AREA : " + maxArea.toFixed(3));
390+
391+
this.totalCuts = cuts.length;
392+
this.cutsLength = cutLength;
393+
this.area = maxArea;
394+
}
395+
396+
getVectorDistance(vectors) {
397+
let sum=0;
398+
for(let i=0;i<vectors.length;i++){
399+
sum+=vectors[i].distanceTo(vectors[i === vectors.length - 1 ? 0 : i + 1]);
400+
}
401+
return sum;
402+
}
403+
404+
calcPolygonArea(vertices) {
405+
var total = 0;
406+
407+
for (var i = 0, l = vertices.length; i < l; i++) {
408+
var addX = vertices[i].x;
409+
var addY = vertices[i === vertices.length - 1 ? 0 : i + 1].y;
410+
var subX = vertices[i === vertices.length - 1 ? 0 : i + 1].x;
411+
var subY = vertices[i].y;
412+
413+
total += (addX * addY * 0.5);
414+
total -= (subX * subY * 0.5);
415+
}
416+
417+
return Math.abs(total);
418+
}
237419

238420
/** @return {Iterable<{name:String, color:number}>} List of layer names. */
239421
GetLayers() {

0 commit comments

Comments
 (0)