Skip to content

Commit

Permalink
dxf-calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
usamamasood01 committed May 13, 2023
1 parent 151b7de commit 483ed02
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 10 deletions.
3 changes: 2 additions & 1 deletion src/BatchingKey.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ export class BatchingKey {
* @param lineType {?number} Line type ID, null for non-lines. Zero is default type (solid
* line).
*/
constructor(layerName, blockName, geometryType, color, lineType) {
constructor(layerName, blockName, geometryType, color, lineType, vertices) {
this.layerName = layerName ?? null
this.blockName = blockName ?? null
this.geometryType = geometryType ?? null
this.color = color
this.lineType = lineType ?? null
this.vertices = vertices
}

/** Comparator function. Fields lexical order corresponds to the constructor arguments order.
Expand Down
29 changes: 20 additions & 9 deletions src/DxfScene.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export class DxfScene {
this.pointShapeBlock = null
this.numBlocksFlattened = 0
this.numEntitiesFiltered = 0
this.entityVertices = []
}

/** Build the scene from the provided parsed DXF.
Expand Down Expand Up @@ -277,8 +278,16 @@ export class DxfScene {
}
}
}

checkTangentLayer (layer) {
const bendKeywords = ['tangent', 'bend_extent'];
return bendKeywords.some(substr=>layer.toLowerCase().indexOf(substr) >= 0);
}

_ProcessDxfEntity(entity, blockCtx = null) {
if (this.checkTangentLayer(entity.layer)) {
return;
}
let renderEntities
switch (entity.type) {
case "LINE":
Expand Down Expand Up @@ -341,6 +350,7 @@ export class DxfScene {
* @param blockCtx {?BlockContext}
*/
_ProcessEntity(entity, blockCtx = null) {
this.entityVertices.push(entity);
switch (entity.type) {
case Entity.Type.POINTS:
this._ProcessPoints(entity, blockCtx)
Expand Down Expand Up @@ -617,7 +627,7 @@ export class DxfScene {
if (isShaped) {
/* Shaped mark should be instanced. */
const key = new BatchingKey(layer, POINT_SHAPE_BLOCK_NAME,
BatchingKey.GeometryType.POINT_INSTANCE, color, 0)
BatchingKey.GeometryType.POINT_INSTANCE, color, 0, entity?.vertices ? entity?.vertices : [])
const batch = this._GetBatch(key)
batch.PushVertex(this._TransformVertex(entity.position))
this._CreatePointShapeBlock()
Expand Down Expand Up @@ -1452,7 +1462,7 @@ export class DxfScene {
}
} else {
const key = new BatchingKey(layer, entity.name, BatchingKey.GeometryType.BLOCK_INSTANCE,
color, lineType)
color, lineType, entity?.vertices ? entity?.vertices : [])
const batch = this._GetBatch(key)
batch.PushInstanceTransform(transform)
}
Expand All @@ -1470,7 +1480,7 @@ export class DxfScene {
color = blockBatch.key.color
}
//XXX line type
const key = new BatchingKey(layerName, null, blockBatch.key.geometryType, color, lineType)
const key = new BatchingKey(layerName, null, blockBatch.key.geometryType, color, lineType, [])
const batch = this._GetBatch(key)
batch.Merge(blockBatch, transform)
}
Expand Down Expand Up @@ -1852,7 +1862,7 @@ export class DxfScene {
*/
_ProcessPoints(entity, blockCtx = null) {
const key = new BatchingKey(entity.layer, blockCtx?.name,
BatchingKey.GeometryType.POINTS, entity.color, 0)
BatchingKey.GeometryType.POINTS, entity.color, 0, entity?.vertices ? entity?.vertices : [])
const batch = this._GetBatch(key)
for (const v of entity.vertices) {
batch.PushVertex(this._TransformVertex(v, blockCtx))
Expand All @@ -1868,7 +1878,7 @@ export class DxfScene {
throw Error("Even number of vertices expected")
}
const key = new BatchingKey(entity.layer, blockCtx?.name,
BatchingKey.GeometryType.LINES, entity.color, entity.lineType)
BatchingKey.GeometryType.LINES, entity.color, entity.lineType, entity?.vertices ? entity?.vertices : [])
const batch = this._GetBatch(key)
for (const v of entity.vertices) {
batch.PushVertex(this._TransformVertex(v, blockCtx))
Expand All @@ -1890,7 +1900,7 @@ export class DxfScene {
if (verticesCount <= 3) {
const key = new BatchingKey(entity.layer, blockCtx?.name,
BatchingKey.GeometryType.LINES, entity.color,
entity.lineType)
entity.lineType, entity?.vertices ? entity?.vertices : [])
const batch = this._GetBatch(key)
let prev = null
for (const v of entity.vertices) {
Expand All @@ -1909,7 +1919,7 @@ export class DxfScene {

const key = new BatchingKey(entity.layer, blockCtx?.name,
BatchingKey.GeometryType.INDEXED_LINES,
entity.color, entity.lineType)
entity.color, entity.lineType, entity?.vertices ? entity?.vertices : [])
const batch = this._GetBatch(key)
/* Line may be split if exceeds chunk limit. */
for (const lineChunk of entity._IterateLineChunks()) {
Expand Down Expand Up @@ -1938,7 +1948,7 @@ export class DxfScene {
}
const key = new BatchingKey(entity.layer, blockCtx?.name,
BatchingKey.GeometryType.INDEXED_TRIANGLES,
entity.color, 0)
entity.color, 0, entity?.vertices ? entity?.vertices : [])
const batch = this._GetBatch(key)
//XXX splitting into chunks is not yet implemented. Currently used only for text glyphs so
// should fit into one chunk
Expand Down Expand Up @@ -2087,7 +2097,8 @@ export class DxfScene {
layers: [],
origin: this.origin,
bounds: this.bounds,
hasMissingChars: this.hasMissingChars
hasMissingChars: this.hasMissingChars,
entityVertices: this.entityVertices
}

const buffers = {
Expand Down
182 changes: 182 additions & 0 deletions src/DxfViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ export class DxfViewer {
* @param options Some options can be overridden if specified. See DxfViewer.DefaultOptions.
*/
constructor(domContainer, options = null) {
this.dimensions = {dxfWidth: 0, dxfHeight: 0};
this.totalCuts = 0;
this.cutsLength = 0;
this.area = 0;
this.shapes = [];
this.bends = [];

this.domContainer = domContainer
this.options = Object.create(DxfViewer.DefaultOptions)
if (options) {
Expand Down Expand Up @@ -119,6 +126,15 @@ export class DxfViewer {
return this.parsedDxf
}

GetFileDetails() {
return {
dimensions: this.dimensions,
totalCuts: this.totalCuts,
cutsLength: this.cutsLength,
area: this.area,
}
}

SetSize(width, height) {
this._EnsureRenderer()

Expand Down Expand Up @@ -172,12 +188,17 @@ export class DxfViewer {

this.worker = new DxfWorker(workerFactory ? workerFactory() : null)
const {scene, dxf} = await this.worker.Load(url, fonts, this.options, progressCbk)
this.SetFileDetails(scene?.entityVertices);
await this.worker.Destroy()
this.worker = null
this.parsedDxf = dxf

this.origin = scene.origin
this.bounds = scene.bounds
this.dimensions = {
dxfWidth: scene.bounds.maxY - scene.bounds.minY,
dxfHeight: scene.bounds.maxX - scene.bounds.minX
};
this.hasMissingChars = scene.hasMissingChars

for (const layer of scene.layers) {
Expand Down Expand Up @@ -234,6 +255,167 @@ export class DxfViewer {
this._EnsureRenderer()
this.renderer.render(this.scene, this.camera)
}

checkTangentLayer (layer) {
const bendKeywords = ['tangent', 'bend_extent'];
return bendKeywords.some(substr=>layer.toLowerCase().indexOf(substr) >= 0);
}

checkBendLayer (layer) {
const bendKeywords = ['bend', 'reference'];
return bendKeywords.some(substr=>layer.toLowerCase().indexOf(substr) >= 0);
}

_TransformVertex(vs=[]) {
return vs.map(v=>{return { x: v.x - this.origin.x, y: v.y - this.origin.y }})
}

getAllLastPoints(entities) {
let points = [];
for (let i = 0; i < entities.length; i++) {
const entity = entities[i];
if(!this.checkBendLayer(entity.layer) && !entity.lineType && !this.checkTangentLayer(entity.layer)){
points.push({
startPointx : entity.vertices[0].x,
startPointy : entity.vertices[0].y,
endPointx : entity.vertices[entity.vertices.length - 1].x,
endPointy : entity.vertices[entity.vertices.length - 1].y,
visited: false,
entity,
points: entity.vertices,
});
}
}
return points;
}

SetFileDetails(entityVertices) {
let lastPoints = this.getAllLastPoints(entityVertices);
let cuts = [];
var maxArea = 0;
let cutLength = 0;

function round3(value){
return Math.round(value*1000)/1000;
}

function markPointVisited ({startPointx, startPointy, endPointx, endPointy}) {
const index = lastPoints.findIndex(el=> el.startPointx===startPointx && el.startPointy===startPointy && el.endPointx===endPointx && el.endPointy===endPointy);
if(index >= 0) {
lastPoints[index].visited = true;
}
}

function visitAllPoints({startPointx, startPointy, endPointx, endPointy}, entity, points) {
markPointVisited({startPointx, startPointy, endPointx, endPointy});
let allPoints = [...points];
let ended = false;
let connectedPoints = [entity];
while(!ended) {
const index = lastPoints.findIndex(
el =>
(round3(el.startPointx)===round3(endPointx) && round3(el.startPointy)===round3(endPointy) && !el.visited) ||
(round3(el.endPointx)===round3(startPointx) && round3(el.endPointy)===round3(startPointy) && !el.visited) ||
(round3(el.endPointx)===round3(endPointx) && round3(el.endPointy)===round3(endPointy) && !el.visited) ||
(round3(el.startPointx)===round3(startPointx) && round3(el.startPointy)===round3(startPointy) && !el.visited)
);
if (index < 0) {
ended = true;
cuts.push(connectedPoints);
} else {

if(round3(lastPoints[index].startPointx)===round3(endPointx) && round3(lastPoints[index].startPointy)===round3(endPointy)){
allPoints = [...allPoints, ...lastPoints[index].points];
}
else if(round3(lastPoints[index].endPointx)===round3(startPointx) && round3(lastPoints[index].endPointy)===round3(startPointy)){
allPoints = [...lastPoints[index].points, ...allPoints];
}
else if(round3(lastPoints[index].endPointx)===round3(endPointx) && round3(lastPoints[index].endPointy)===round3(endPointy)){
allPoints = [ ...allPoints, ...lastPoints[index].points.reverse()];
}
else if(round3(lastPoints[index].startPointx)===round3(startPointx) && round3(lastPoints[index].startPointy)===round3(startPointy)){
allPoints = [...lastPoints[index].points.reverse(), ...allPoints];
}

startPointx = allPoints[0].x;
startPointy = allPoints[0].y;
endPointx = allPoints[allPoints.length - 1].x;
endPointy = allPoints[allPoints.length - 1].y;
entity = lastPoints[index].entity;
lastPoints[index].visited = true;
connectedPoints.push(lastPoints[index].entity);
}
}
return allPoints.map(el=>new three.Vector2(el.x, el.y));
}

function isPointVisited({startPointx, startPointy, endPointx, endPointy}) {
const found = lastPoints.find(el=> el.startPointx===startPointx && el.startPointy===startPointy && el.endPointx===endPointx && el.endPointy===endPointy);
if(found) {
return found.visited;
}
else {
return true;
}
}

for (let i = 0; i < entityVertices.length; i++) {
const entity = entityVertices[i];
if(!this.checkBendLayer(entity.layer) && !entity.lineType && !this.checkTangentLayer(entity.layer) && !isPointVisited({
startPointx : entity.vertices[0].x,
startPointy : entity.vertices[0].y,
endPointx : entity.vertices[entity.vertices.length - 1].x,
endPointy : entity.vertices[entity.vertices.length - 1].y,
})) {
const points = visitAllPoints({
startPointx : entity.vertices[0].x,
startPointy : entity.vertices[0].y,
endPointx : entity.vertices[entity.vertices.length - 1].x,
endPointy : entity.vertices[entity.vertices.length - 1].y,
}, entity, entity.vertices);
this.shapes.push(points);
cutLength += this.getVectorDistance(points);
const area = this.calcPolygonArea(points);
if (area > maxArea){
maxArea = area;
}
} else if(this.checkBendLayer(entity.layer)) {
this.bends.push(entity.vertices.map(el=>new three.Vector2(el.x, el.y)));
}
}

console.log("TOTAL LENGTH : " + cutLength.toFixed(3));
console.log("TOTAL CUTS : " + cuts.length);
console.log("TOTAL AREA : " + maxArea.toFixed(3));

this.totalCuts = cuts.length;
this.cutsLength = cutLength;
this.area = maxArea;
}

getVectorDistance(vectors) {
let sum=0;
for(let i=0;i<vectors.length;i++){
sum+=vectors[i].distanceTo(vectors[i === vectors.length - 1 ? 0 : i + 1]);
}
return sum;
}

calcPolygonArea(vertices) {
var total = 0;

for (var i = 0, l = vertices.length; i < l; i++) {
var addX = vertices[i].x;
var addY = vertices[i === vertices.length - 1 ? 0 : i + 1].y;
var subX = vertices[i === vertices.length - 1 ? 0 : i + 1].x;
var subY = vertices[i].y;

total += (addX * addY * 0.5);
total -= (subX * subY * 0.5);
}

return Math.abs(total);
}

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

0 comments on commit 483ed02

Please sign in to comment.