@@ -6,17 +6,20 @@ module MakerJs.model {
6
6
* @private
7
7
*/
8
8
function getNonZeroSegments ( pathToSegment : IPath , breakPoint : IPoint ) : IPath [ ] {
9
+ var segmentType = pathToSegment . type ;
9
10
var segment1 = cloneObject < IPath > ( pathToSegment ) ;
10
11
var segment2 = path . breakAtPoint ( segment1 , breakPoint ) ;
11
12
12
13
if ( segment2 ) {
13
14
var segments : IPath [ ] = [ segment1 , segment2 ] ;
14
15
for ( var i = 2 ; i -- ; ) {
15
- if ( round ( measure . pathLength ( segments [ i ] ) , .00001 ) == 0 ) {
16
+ if ( round ( measure . pathLength ( segments [ i ] ) , .0001 ) == 0 ) {
16
17
return null ;
17
18
}
18
19
}
19
20
return segments ;
21
+ } else if ( segmentType == pathType . Circle ) {
22
+ return [ segment1 ] ;
20
23
}
21
24
return null ;
22
25
}
@@ -26,7 +29,7 @@ module MakerJs.model {
26
29
*/
27
30
function breakAlongForeignPath ( segments : ICrossedPathSegment [ ] , overlappedSegments : ICrossedPathSegment [ ] , foreignPath : IPath ) {
28
31
29
- if ( path . areEqual ( segments [ 0 ] . path , foreignPath ) ) {
32
+ if ( path . areEqual ( segments [ 0 ] . path , foreignPath , .0001 ) ) {
30
33
segments [ 0 ] . overlapped = true ;
31
34
segments [ 0 ] . duplicate = true ;
32
35
@@ -70,13 +73,20 @@ module MakerJs.model {
70
73
if ( subSegments ) {
71
74
segments [ i ] . path = subSegments [ 0 ] ;
72
75
73
- var newSegment = { path : subSegments [ 1 ] , overlapped : segments [ i ] . overlapped , uniqueForeignIntersectionPoints : [ ] } ;
76
+ if ( subSegments [ 1 ] ) {
77
+ var newSegment : ICrossedPathSegment = {
78
+ path : subSegments [ 1 ] ,
79
+ pathId : segments [ 0 ] . pathId ,
80
+ overlapped : segments [ i ] . overlapped ,
81
+ uniqueForeignIntersectionPoints : [ ]
82
+ } ;
74
83
75
- if ( segments [ i ] . overlapped ) {
76
- overlappedSegments . push ( newSegment ) ;
77
- }
84
+ if ( segments [ i ] . overlapped ) {
85
+ overlappedSegments . push ( newSegment ) ;
86
+ }
78
87
79
- segments . push ( newSegment ) ;
88
+ segments . push ( newSegment ) ;
89
+ }
80
90
81
91
//re-check this segment for another deep intersection
82
92
i -- ;
@@ -94,7 +104,7 @@ module MakerJs.model {
94
104
95
105
function addUniquePoint ( pointToAdd : IPoint ) {
96
106
for ( var i = 0 ; i < pointArray . length ; i ++ ) {
97
- if ( point . areEqualRounded ( pointArray [ i ] , pointToAdd ) ) {
107
+ if ( point . areEqual ( pointArray [ i ] , pointToAdd , .000000001 ) ) {
98
108
return ;
99
109
}
100
110
}
@@ -112,7 +122,7 @@ module MakerJs.model {
112
122
/**
113
123
* @private
114
124
*/
115
- function checkInsideForeignPath ( segment : IPathInside , foreignPath : IPath , farPoint : IPoint = [ 7654321 , 1234567 ] ) {
125
+ function checkIntersectsForeignPath ( segment : IPathInside , foreignPath : IPath , foreignPathId : string , farPoint : IPoint = [ 7654321 , 1234567 ] ) {
116
126
var origin = point . middle ( segment . path ) ;
117
127
var lineToFarPoint = new paths . Line ( origin , farPoint ) ;
118
128
var farInt = path . intersection ( lineToFarPoint , foreignPath ) ;
@@ -133,7 +143,7 @@ module MakerJs.model {
133
143
function checkInsideForeignModel ( segment : IPathInside , modelToIntersect : IModel , farPoint ?: IPoint ) {
134
144
walkPaths ( modelToIntersect , function ( mx : IModel , pathId2 : string , path2 : IPath ) {
135
145
if ( path2 ) {
136
- checkInsideForeignPath ( segment , path2 , farPoint ) ;
146
+ checkIntersectsForeignPath ( segment , path2 , pathId2 , farPoint ) ;
137
147
}
138
148
} ) ;
139
149
}
@@ -171,16 +181,15 @@ module MakerJs.model {
171
181
* @private
172
182
*/
173
183
interface ICrossedPathSegment extends IPathInside {
184
+ pathId : string ;
174
185
overlapped : boolean ;
175
186
duplicate ?: boolean ;
176
187
}
177
188
178
189
/**
179
190
* @private
180
191
*/
181
- interface ICrossedPath {
182
- modelContext : IModel ;
183
- pathId : string ;
192
+ interface ICrossedPath extends IRefPathIdInModel {
184
193
segments : ICrossedPathSegment [ ] ;
185
194
}
186
195
@@ -192,10 +201,20 @@ module MakerJs.model {
192
201
overlappedSegments : ICrossedPathSegment [ ] ;
193
202
}
194
203
204
+ /**
205
+ * Break a model's paths everywhere they intersect with another path.
206
+ *
207
+ * @param modelToBreak The model containing paths to be broken.
208
+ * @param modelToIntersect Optional model containing paths to look for intersection, or else the modelToBreak will be used.
209
+ */
210
+ export function breakPathsAtIntersections ( modelToBreak : IModel , modelToIntersect ?: IModel ) {
211
+ breakAllPathsAtIntersections ( modelToBreak , modelToIntersect || modelToBreak , false ) ;
212
+ }
213
+
195
214
/**
196
215
* @private
197
216
*/
198
- function breakAllPathsAtIntersections ( modelToBreak : IModel , modelToIntersect : IModel , farPoint : IPoint ) : ICombinedModel {
217
+ function breakAllPathsAtIntersections ( modelToBreak : IModel , modelToIntersect : IModel , checkIsInside : boolean , farPoint ? : IPoint ) : ICombinedModel {
199
218
200
219
var crossedPaths : ICrossedPath [ ] = [ ] ;
201
220
var overlappedSegments : ICrossedPathSegment [ ] = [ ] ;
@@ -207,6 +226,7 @@ module MakerJs.model {
207
226
//clone this path and make it the first segment
208
227
var segment : ICrossedPathSegment = {
209
228
path : cloneObject < IPath > ( path1 ) ,
229
+ pathId : pathId1 ,
210
230
overlapped : false ,
211
231
uniqueForeignIntersectionPoints : [ ]
212
232
} ;
@@ -219,14 +239,16 @@ module MakerJs.model {
219
239
220
240
//keep breaking the segments anywhere they intersect with paths of the other model
221
241
walkPaths ( modelToIntersect , function ( mx : IModel , pathId2 : string , path2 : IPath ) {
222
- if ( path2 ) {
242
+ if ( path2 && path1 !== path2 ) {
223
243
breakAlongForeignPath ( thisPath . segments , overlappedSegments , path2 ) ;
224
244
}
225
245
} ) ;
226
246
227
- //check each segment whether it is inside or outside
228
- for ( var i = 0 ; i < thisPath . segments . length ; i ++ ) {
229
- checkInsideForeignModel ( thisPath . segments [ i ] , modelToIntersect ) ;
247
+ if ( checkIsInside ) {
248
+ //check each segment whether it is inside or outside
249
+ for ( var i = 0 ; i < thisPath . segments . length ; i ++ ) {
250
+ checkInsideForeignModel ( thisPath . segments [ i ] , modelToIntersect , farPoint ) ;
251
+ }
230
252
}
231
253
232
254
crossedPaths . push ( thisPath ) ;
@@ -238,10 +260,10 @@ module MakerJs.model {
238
260
/**
239
261
* @private
240
262
*/
241
- function checkForEqualOverlaps ( crossedPathsA : ICrossedPathSegment [ ] , crossedPathsB : ICrossedPathSegment [ ] ) {
263
+ function checkForEqualOverlaps ( crossedPathsA : ICrossedPathSegment [ ] , crossedPathsB : ICrossedPathSegment [ ] , pointMatchingDistance : number ) {
242
264
243
265
function compareSegments ( segment1 : ICrossedPathSegment , segment2 : ICrossedPathSegment ) {
244
- if ( path . areEqual ( segment1 . path , segment2 . path ) ) {
266
+ if ( path . areEqual ( segment1 . path , segment2 . path , pointMatchingDistance ) ) {
245
267
segment1 . duplicate = segment2 . duplicate = true ;
246
268
}
247
269
}
@@ -261,16 +283,16 @@ module MakerJs.model {
261
283
/**
262
284
* @private
263
285
*/
264
- function addOrDeleteSegments ( crossedPath : ICrossedPath , includeInside : boolean , includeOutside : boolean , keepDuplicates ? : boolean ) {
286
+ function addOrDeleteSegments ( crossedPath : ICrossedPath , includeInside : boolean , includeOutside : boolean , keepDuplicates : boolean ) {
265
287
266
- function addSegment ( model : IModel , pathIdBase : string , segment : ICrossedPathSegment ) {
267
- var id = getSimilarPathId ( model , pathIdBase ) ;
268
- model . paths [ id ] = segment . path ;
288
+ function addSegment ( modelContext : IModel , pathIdBase : string , segment : ICrossedPathSegment ) {
289
+ var id = getSimilarPathId ( modelContext , pathIdBase ) ;
290
+ modelContext . paths [ id ] = segment . path ;
269
291
}
270
292
271
- function checkAddSegment ( model : IModel , pathIdBase : string , segment : ICrossedPathSegment ) {
293
+ function checkAddSegment ( modelContext : IModel , pathIdBase : string , segment : ICrossedPathSegment ) {
272
294
if ( segment . isInside && includeInside || ! segment . isInside && includeOutside ) {
273
- addSegment ( model , pathIdBase , segment ) ;
295
+ addSegment ( modelContext , pathIdBase , segment ) ;
274
296
}
275
297
}
276
298
@@ -289,7 +311,7 @@ module MakerJs.model {
289
311
}
290
312
291
313
/**
292
- * Combine 2 models. The models should be originated.
314
+ * Combine 2 models. The models should be originated, and every path within each model should be part of a loop .
293
315
*
294
316
* @param modelA First model to combine.
295
317
* @param modelB Second model to combine.
@@ -300,19 +322,29 @@ module MakerJs.model {
300
322
* @param keepDuplicates Flag to include paths which are duplicate in both models.
301
323
* @param farPoint Optional point of reference which is outside the bounds of both models.
302
324
*/
303
- export function combine ( modelA : IModel , modelB : IModel , includeAInsideB : boolean = false , includeAOutsideB : boolean = true , includeBInsideA : boolean = false , includeBOutsideA : boolean = true , keepDuplicates : boolean = true , farPoint ?: IPoint ) {
325
+ export function combine ( modelA : IModel , modelB : IModel , includeAInsideB : boolean = false , includeAOutsideB : boolean = true , includeBInsideA : boolean = false , includeBOutsideA : boolean = true , options ?: ICombineOptions ) {
304
326
305
- var pathsA = breakAllPathsAtIntersections ( modelA , modelB , farPoint ) ;
306
- var pathsB = breakAllPathsAtIntersections ( modelB , modelA , farPoint ) ;
327
+ var opts : ICombineOptions = {
328
+ trimDeadEnds : true ,
329
+ pointMatchingDistance : .005
330
+ } ;
331
+ extendObject ( opts , options ) ;
307
332
308
- checkForEqualOverlaps ( pathsA . overlappedSegments , pathsB . overlappedSegments ) ;
333
+ var pathsA = breakAllPathsAtIntersections ( modelA , modelB , true , opts . farPoint ) ;
334
+ var pathsB = breakAllPathsAtIntersections ( modelB , modelA , true , opts . farPoint ) ;
335
+
336
+ checkForEqualOverlaps ( pathsA . overlappedSegments , pathsB . overlappedSegments , opts . pointMatchingDistance ) ;
309
337
310
338
for ( var i = 0 ; i < pathsA . crossedPaths . length ; i ++ ) {
311
- addOrDeleteSegments ( pathsA . crossedPaths [ i ] , includeAInsideB , includeAOutsideB , keepDuplicates ) ;
339
+ addOrDeleteSegments ( pathsA . crossedPaths [ i ] , includeAInsideB , includeAOutsideB , true ) ;
312
340
}
313
341
314
342
for ( var i = 0 ; i < pathsB . crossedPaths . length ; i ++ ) {
315
- addOrDeleteSegments ( pathsB . crossedPaths [ i ] , includeBInsideA , includeBOutsideA ) ;
343
+ addOrDeleteSegments ( pathsB . crossedPaths [ i ] , includeBInsideA , includeBOutsideA , false ) ;
344
+ }
345
+
346
+ if ( opts . trimDeadEnds ) {
347
+ removeDeadEnds ( < IModel > { models : { modelA : modelA , modelB : modelB } } ) ;
316
348
}
317
349
}
318
350
0 commit comments