Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dxf calculations #62

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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