@@ -89,7 +89,6 @@ impl LayerSnapper {
89
89
90
90
pub fn free_snap_paths ( & mut self , snap_data : & mut SnapData , point : & SnapCandidatePoint , snap_results : & mut SnapResults , config : SnapTypeConfiguration ) {
91
91
self . collect_paths ( snap_data, !config. use_existing_candidates ) ;
92
-
93
92
let document = snap_data. document ;
94
93
let normals = document. snapping_state . target_enabled ( SnapTarget :: Path ( PathSnapTarget :: NormalToPath ) ) ;
95
94
let tangents = document. snapping_state . target_enabled ( SnapTarget :: Path ( PathSnapTarget :: TangentToPath ) ) ;
@@ -121,8 +120,9 @@ impl LayerSnapper {
121
120
..Default :: default ( )
122
121
} ,
123
122
} ) ;
124
- normals_and_tangents ( path, normals, tangents , point, tolerance, snap_results) ;
123
+ snap_normals ( path, normals, point, tolerance, snap_results) ;
125
124
}
125
+ snap_tangents ( path, tangents, point, tolerance, snap_results) ;
126
126
}
127
127
}
128
128
@@ -262,7 +262,7 @@ impl LayerSnapper {
262
262
}
263
263
}
264
264
265
- fn normals_and_tangents ( path : & SnapCandidatePath , normals : bool , tangents : bool , point : & SnapCandidatePoint , tolerance : f64 , snap_results : & mut SnapResults ) {
265
+ fn snap_normals ( path : & SnapCandidatePath , normals : bool , point : & SnapCandidatePoint , tolerance : f64 , snap_results : & mut SnapResults ) {
266
266
if normals && path. bounds . is_none ( ) {
267
267
for & neighbor in & point. neighbors {
268
268
for t in path. document_curve . normals_to_point ( neighbor) {
@@ -284,27 +284,68 @@ fn normals_and_tangents(path: &SnapCandidatePath, normals: bool, tangents: bool,
284
284
}
285
285
}
286
286
}
287
- if tangents && path. bounds . is_none ( ) {
288
- for & neighbor in & point. neighbors {
289
- for t in path. document_curve . tangents_to_point ( neighbor) {
290
- let tangent_point = path. document_curve . evaluate ( TValue :: Parametric ( t) ) ;
291
- let distance = tangent_point. distance ( point. document_point ) ;
292
- if distance > tolerance {
293
- continue ;
294
- }
295
- snap_results. points . push ( SnappedPoint {
296
- snapped_point_document : tangent_point,
297
- target : SnapTarget :: Path ( PathSnapTarget :: TangentToPath ) ,
298
- distance,
299
- tolerance,
300
- outline_layers : [ Some ( path. layer ) , None ] ,
301
- source : point. source ,
302
- constrained : true ,
303
- ..Default :: default ( )
304
- } ) ;
305
- }
287
+ }
288
+
289
+ // TODO: Snap rectangles and ellipses to ellipses tangents, find out why point.neighbors is empty while drawing rectangles and ellipses
290
+ fn snap_tangents ( path : & SnapCandidatePath , tangents : bool , point : & SnapCandidatePoint , tolerance : f64 , snap_results : & mut SnapResults ) {
291
+ if !tangents || point. neighbors . len ( ) != 1 {
292
+ return ;
293
+ }
294
+ let neighbor = point. neighbors [ 0 ] ;
295
+ for t in path. document_curve . tangents_to_point ( neighbor) {
296
+ let tangent_point = path. document_curve . evaluate ( TValue :: Parametric ( t) ) ;
297
+
298
+ if let Some ( closest_point) = closest_point_along_line ( neighbor, point. document_point , & path. document_curve , tolerance, 20 ) {
299
+ let tangent = ( tangent_point - neighbor) . normalize ( ) ;
300
+ let offset = ( point. document_point - tangent_point) . dot ( tangent) ;
301
+ let snap_to = tangent_point + tangent * offset;
302
+
303
+ let distance = snap_to. distance ( point. document_point ) ;
304
+ snap_results. points . push ( SnappedPoint {
305
+ snapped_point_document : snap_to,
306
+ source : point. source ,
307
+ target : SnapTarget :: Path ( PathSnapTarget :: TangentToPath ) ,
308
+ at_intersection : true ,
309
+ alignment_target_x : Some ( tangent_point) ,
310
+ distance,
311
+ tolerance,
312
+ outline_layers : [ Some ( path. layer ) , None ] ,
313
+ target_bounds : Some ( Quad ( [ neighbor, neighbor, snap_to, snap_to] ) ) ,
314
+ ..Default :: default ( )
315
+ } ) ;
316
+ }
317
+ }
318
+ }
319
+ fn closest_point_along_line ( start : DVec2 , end : DVec2 , curve : & Bezier , tolerance : f64 , max_iterations : usize ) -> Option < DVec2 > {
320
+ let mut closest_point = None ;
321
+ let mut closest_distance = f64:: INFINITY ;
322
+
323
+ for i in 0 ..=max_iterations {
324
+ let t = i as f64 / max_iterations as f64 ;
325
+
326
+ let curve_point = curve. evaluate ( TValue :: Parametric ( t) ) ;
327
+ let tangent = curve. tangent ( TValue :: Parametric ( t) ) ;
328
+ if tangent. length_squared ( ) == 0.0 {
329
+ continue ;
330
+ }
331
+
332
+ let line_direction = end - start;
333
+ if line_direction. length_squared ( ) == 0.0 {
334
+ break ;
335
+ }
336
+
337
+ let v = curve_point - start;
338
+ let projected_distance = v. dot ( line_direction. normalize ( ) ) ;
339
+ let projected_point = start + projected_distance * line_direction. normalize ( ) ;
340
+
341
+ let distance = projected_point. distance ( curve_point) ;
342
+
343
+ if distance < closest_distance {
344
+ closest_distance = distance;
345
+ closest_point = Some ( projected_point) ;
306
346
}
307
347
}
348
+ if closest_distance < tolerance { closest_point } else { None }
308
349
}
309
350
310
351
#[ derive( Clone , Debug ) ]
0 commit comments