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
+ }
0 commit comments