Skip to content

Commit d84b23f

Browse files
Early line-merge code
1 parent 834d4ce commit d84b23f

File tree

4 files changed

+254
-8
lines changed

4 files changed

+254
-8
lines changed

index.html

+6
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,10 @@ <h6>Calculating Toolpaths...</h6>
691691
<script type="text/javascript" src="js/advanced-cam-drill.js"></script>
692692
<script type="text/javascript" src="js/advanced-cam-booleans.js"></script>
693693

694+
<script type="text/javascript" src="js/basic-cad-tool-merge-lines.js"></script>
695+
696+
697+
694698
<!-- DXF Library -->
695699
<script type="text/javascript" src="lib/dxf/dxf-parser.js"></script>
696700
<script type="text/javascript" src="lib/dxf/three-dxf.js"></script>
@@ -724,6 +728,8 @@ <h6>Calculating Toolpaths...</h6>
724728
<script src="workers/toolpath/toolpath.js"></script>
725729
<script src="workers/toolpath/worker/toolpathworker.js"></script>
726730

731+
732+
727733
<!-- OpenJSCAD -->
728734
<!-- <script src="lib/openjscad/src/csg.js"></script>
729735
<script src="lib/openjscad/src/threecsg.js"></script>

js/advanced-cam-doctree.js

+3-7
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function treeClick(checkbox, node) {
2929
var object = objectsInScene[object]
3030
object.traverse(function(child) {
3131
if (child.type == "Line") {
32-
if (child.userData.layer.label == layer) {
32+
if (child.userData.layer && child.userData.layer.label == layer) {
3333
child.userData.selected = true;
3434
}
3535
}
@@ -38,7 +38,7 @@ function treeClick(checkbox, node) {
3838
var object = objectsInScene[object]
3939
object.traverse(function(child) {
4040
if (child.type == "Line") {
41-
if (child.userData.layer.label == layer) {
41+
if (child.userData.layer && child.userData.layer.label == layer) {
4242
child.userData.selected = false;
4343
}
4444
}
@@ -123,11 +123,7 @@ function filldoctree() {
123123
// Add Vectors to Layers
124124
for (j = 0; j < objectsInScene[i].children.length; j++) {
125125

126-
if (objectsInScene[i].children[j].closed) {
127-
var template = ` <li><input id="checkbox_` + i + `_` + j + `" type="checkbox" data-role="checkbox" data-caption="<span class='fas fa-vector-square'></span> ` + objectsInScene[i].children[j].name + `" data-type="vector" data-object="` + i + `" data-child="` + j + `" data-layer="` + layersinthisdoc[j] + `"></li>`
128-
} else {
129-
var template = ` <li><input id="checkbox_` + i + `_` + j + `" type="checkbox" data-role="checkbox" data-caption="<span class='fas fa-slash'></span> ` + objectsInScene[i].children[j].name + ` (open vector)" data-type="vector" data-object="` + i + `" data-child="` + j + `" data-layer="` + layersinthisdoc[j] + `"></li>`
130-
}
126+
var template = ` <li><input id="checkbox_` + i + `_` + j + `" type="checkbox" data-role="checkbox" data-caption="<span class='fas fa-vector-square'></span> ` + objectsInScene[i].children[j].name + `" data-type="vector" data-object="` + i + `" data-child="` + j + `" data-layer="` + layersinthisdoc[j] + `"></li>`
131127

132128
objectsInScene[i].children[j].userData.link = "link" + i + "_" + j;
133129
if (objectsInScene[i].children[j].userData.layer) {

js/basic-cad-tool-merge-lines.js

+241
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
// Note to self. Select "line" items in Doc tree > run addMergedLines
2+
// No tolerance yet
3+
// operator has to select lines that belong to the same "shape"
4+
// manually - sorted needs to learn to find all that has matching start/end - then reprocess remainders again creating multiple polylines as it goes so you
5+
// can even use Select All, it should filter for 2-point vectors (lines), etc
6+
7+
function addMergedLines() {
8+
9+
// var lines = []
10+
var toolpath = new THREE.Group();
11+
12+
13+
for (i = 0; i < objectsInScene.length; i++) {
14+
var obj = objectsInScene[i];
15+
obj.traverse(function(child) {
16+
if (child.userData.selected) {
17+
var copy = child.clone()
18+
//console.log("copy:", copy)
19+
if (copy.geometry.vertices.length < 3) {
20+
copy.userData.closed = false
21+
} else if (copy.geometry.vertices.length > 2) {
22+
var d = distanceFormula(copy.geometry.vertices[0].x, copy.geometry.vertices[copy.geometry.vertices.length - 1].x, copy.geometry.vertices[0].y, copy.geometry.vertices[copy.geometry.vertices.length - 1].y)
23+
console.log(d)
24+
if (d < 0.1) {
25+
copy.userData.closed = true
26+
} else {
27+
copy.userData.closed = false
28+
}
29+
}
30+
copy.position.copy(obj.position);
31+
toolpath.add(copy);
32+
// lines.push(copy)
33+
}
34+
});
35+
};
36+
37+
38+
// get it as Clipper paths
39+
var newClipperPaths = getClipperPaths(toolpath);
40+
console.log(JSON.stringify(newClipperPaths))
41+
var sortedPaths = sortClipperPath(newClipperPaths)
42+
console.log(JSON.stringify(sortedPaths))
43+
44+
var fileObject = new THREE.Group();
45+
// Create a new geometry
46+
var mergedGeometry = new THREE.Geometry();
47+
48+
sortedPaths.forEach(function(coord) {
49+
mergedGeometry.vertices.push(new THREE.Vector3(coord.X, coord.Y, 0));
50+
});
51+
// add geometry
52+
53+
54+
var material = new THREE.MeshBasicMaterial({
55+
color: 0xffff00,
56+
side: THREE.DoubleSide
57+
});
58+
var mergedPath = new THREE.Line(mergedGeometry, material);
59+
mergedPath.name = "Merged Lines"
60+
fileObject.add(mergedPath);
61+
fileObject.name = "Merged Lines" + Math.random()
62+
63+
objectsInScene.push(fileObject)
64+
setTimeout(function() {
65+
fillTree();
66+
changePositionToGeoTranslate();
67+
resetView();
68+
}, 250);
69+
}
70+
71+
// function sortClipperPath(clipperPath) {
72+
// // Create a map to store the starting and ending points of each segment
73+
// const startPoints = new Map();
74+
// const endPoints = new Map();
75+
//
76+
// // Iterate through each segment and store their start and end points
77+
// clipperPath.forEach(segment => {
78+
// console.log(segment)
79+
// const startPoint = segment[0];
80+
// const endPoint = segment[1];
81+
//
82+
// const startPointKey = `${startPoint.X},${startPoint.Y}`;
83+
// const endPointKey = `${endPoint.X},${endPoint.Y}`;
84+
//
85+
// // Store start and end points in respective maps
86+
// if (!startPoints.has(startPointKey)) {
87+
// startPoints.set(startPointKey, segment);
88+
// }
89+
// if (!endPoints.has(endPointKey)) {
90+
// endPoints.set(endPointKey, segment);
91+
// }
92+
// });
93+
//
94+
// // Reorder the segments to form a continuous path
95+
// const sortedPath = [];
96+
// let currentSegment = clipperPath[0];
97+
// sortedPath.push(currentSegment);
98+
// clipperPath.splice(0, 1); // Remove the first segment from the original array
99+
//
100+
// while (clipperPath.length > 0) {
101+
// const endPoint = currentSegment[1];
102+
// const endPointKey = `${endPoint.X},${endPoint.Y}`;
103+
//
104+
// // Find the next segment whose start point matches the current segment's end point
105+
// const nextSegment = startPoints.get(endPointKey);
106+
//
107+
// // If next segment is found, add it to the sorted path and remove it from the original array
108+
// if (nextSegment) {
109+
// sortedPath.push(nextSegment);
110+
// clipperPath.splice(clipperPath.indexOf(nextSegment), 1);
111+
// currentSegment = nextSegment;
112+
// } else {
113+
// // If no next segment is found, break the loop
114+
// break;
115+
// }
116+
// }
117+
//
118+
// // Flatten the sorted path into a single array
119+
// const flattenedPath = sortedPath.reduce((acc, segment) => {
120+
// acc.push(segment[0], segment[1]);
121+
// return acc;
122+
// }, []);
123+
//
124+
// return flattenedPath;
125+
// }
126+
127+
function sortClipperPath(clipperPath, threshold = 0.1) {
128+
// Create a map to store the starting and ending points of each segment
129+
const startPoints = new Map();
130+
const endPoints = new Map();
131+
132+
// Helper function to check if two points are approximately equal within the threshold
133+
const arePointsApproximatelyEqual = (point1, point2) => {
134+
return Math.abs(point1.X - point2.X) < threshold && Math.abs(point1.Y - point2.Y) < threshold;
135+
};
136+
137+
// Iterate through each segment and store their start and end points
138+
clipperPath.forEach(segment => {
139+
const startPoint = segment[0];
140+
const endPoint = segment[1];
141+
142+
const startPointKey = `${startPoint.X},${startPoint.Y}`;
143+
const endPointKey = `${endPoint.X},${endPoint.Y}`;
144+
145+
// Store start and end points in respective maps
146+
if (!startPoints.has(startPointKey)) {
147+
startPoints.set(startPointKey, segment);
148+
}
149+
if (!endPoints.has(endPointKey)) {
150+
endPoints.set(endPointKey, segment);
151+
}
152+
});
153+
154+
// Reorder the segments to form a continuous path
155+
const sortedPath = [];
156+
let currentSegment = clipperPath[0];
157+
sortedPath.push(currentSegment);
158+
clipperPath.splice(0, 1); // Remove the first segment from the original array
159+
160+
while (clipperPath.length > 0) {
161+
const endPoint = currentSegment[1];
162+
const endPointKey = `${endPoint.X},${endPoint.Y}`;
163+
164+
// Find the next segment whose start point approximately matches the current segment's end point
165+
let nextSegment = null;
166+
for (const [key, segment] of startPoints) {
167+
const startPoint = segment[0];
168+
if (arePointsApproximatelyEqual(startPoint, endPoint)) {
169+
nextSegment = segment;
170+
break;
171+
}
172+
}
173+
174+
// If next segment is found, add it to the sorted path and remove it from the original array
175+
if (nextSegment) {
176+
sortedPath.push(nextSegment);
177+
clipperPath.splice(clipperPath.indexOf(nextSegment), 1);
178+
currentSegment = nextSegment;
179+
} else {
180+
// If no next segment is found, break the loop
181+
break;
182+
}
183+
}
184+
185+
// Flatten the sorted path into a single array
186+
const flattenedPath = sortedPath.reduce((acc, segment) => {
187+
acc.push(segment[0], segment[1]);
188+
return acc;
189+
}, []);
190+
191+
return flattenedPath;
192+
}
193+
194+
195+
function tryFixGeometry(object) {
196+
getClipperPaths(object)
197+
console.log("Clipper Path", JSON.stringify(clipperPaths));
198+
var sortedPaths = sortClipperPath(clipperPaths)
199+
console.log("Clipper Path", JSON.stringify(sortedPaths));
200+
return sortedPaths
201+
}
202+
203+
function getClipperPaths(object) {
204+
object.updateMatrix();
205+
var grp = object;
206+
var clipperPaths = [];
207+
grp.traverse(function(child) {
208+
// console.log('Traverse: ', child)
209+
if (child.name == "inflatedGroup") {
210+
console.log("this is the inflated path from a previous run. ignore.");
211+
return;
212+
} else if (child.type == "Line") {
213+
// let's inflate the path for this line. it may not be closed
214+
// so we need to check that.
215+
var clipperArr = [];
216+
// Fix world Coordinates
217+
for (j = 0; j < child.geometry.vertices.length; j++) {
218+
var localPt = child.geometry.vertices[j];
219+
var worldPt = child.localToWorld(localPt.clone());
220+
var xpos = worldPt.x; // + (sizexmax /2);
221+
var ypos = worldPt.y; // + (sizeymax /2);
222+
223+
var xpos_offset = (parseFloat(child.position.x.toFixed(3)));
224+
var ypos_offset = (parseFloat(child.position.y.toFixed(3)));
225+
226+
if (child.geometry.type == "CircleGeometry") {
227+
xpos = (xpos + xpos_offset);
228+
ypos = (ypos + ypos_offset);
229+
}
230+
clipperArr.push({
231+
X: xpos,
232+
Y: ypos
233+
});
234+
}
235+
clipperPaths.push(clipperArr);
236+
} else {
237+
// console.log("type of ", child.type, " being skipped");
238+
}
239+
});
240+
return clipperPaths
241+
}

workers/toolpath/worker/toolpathworker.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ if (typeof window == "undefined") { // Only run as worker
2525
self.postMessage(data);
2626
}, false);
2727

28+
29+
2830
function getToolpaths(toolpath, jobindex, performanceLimit) {
2931
// Process Them
3032
// console.log(toolpath)
@@ -186,7 +188,7 @@ if (typeof window == "undefined") { // Only run as worker
186188
var inflateGrpZ = new THREE.Group();
187189
var prettyGrp = new THREE.Group();
188190
var clipperPaths = workerGetClipperPaths(config.toolpath)
189-
191+
// clipperPaths = tryFixGeometry(clipperPaths)
190192
// console.log('Original Toolpath: ', JSON.stringify(clipperPaths))
191193
if (config.union == "Yes") {
192194
// simplify this set of paths which is a very powerful Clipper call that figures out holes and path orientations
@@ -339,6 +341,7 @@ if (typeof window == "undefined") { // Only run as worker
339341

340342

341343
function workerGetInflatePath(paths, delta, joinType) {
344+
console.log(JSON.stringify(paths));
342345
var scale = 10000;
343346
ClipperLib.JS.Clean(paths, 2);
344347
ClipperLib.JS.ScaleUpPaths(paths, scale);

0 commit comments

Comments
 (0)