Skip to content

Commit a90af24

Browse files
committed
Partial new implementation of convex hull of arcline
1 parent f2a7f46 commit a90af24

1 file changed

Lines changed: 291 additions & 0 deletions

File tree

src/algo/convex_hull_arcs.rs

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2167,4 +2167,295 @@ mod tests {
21672167
assert_eq!(result[1].a, point(0.0, 0.1)); // t1
21682168
assert_eq!(result[1].b, point(0.6, 0.1)); // t2 = arc2.b
21692169
}
2170+
2171+
// ===== hull_seg_arc Tests =====
2172+
2173+
#[test]
2174+
fn test_hull_seg_arc_tangent_from_seg_end() {
2175+
// Segment to arc where tangent from seg.b to arc exists and is on the arc
2176+
// Horizontal segment, arc to the right and above
2177+
let seg = arcseg(point(0.0, 0.0), point(2.0, 0.0));
2178+
let arc_center = point(5.0, 0.0);
2179+
let arc_radius = 2.0;
2180+
// Arc on right side of circle, top quadrant
2181+
let arc2 = arc(point(7.0, 0.0), point(5.0, 2.0), arc_center, arc_radius);
2182+
2183+
let result = hull_seg_arc(seg, arc2);
2184+
2185+
// Tangent connects to arc start, so: tangent line + full arc
2186+
assert_eq!(result.len(), 2);
2187+
assert!(result[0].is_seg());
2188+
assert_eq!(result[0].a, point(2.0, 0.0)); // seg.b
2189+
assert_eq!(result[0].b, point(7.0, 0.0)); // arc2.a
2190+
assert!(!result[1].is_seg());
2191+
assert_eq!(result[1].a, point(7.0, 0.0));
2192+
assert_eq!(result[1].b, point(5.0, 2.0));
2193+
}
2194+
2195+
#[test]
2196+
fn test_hull_seg_arc_tangent_point_on_arc() {
2197+
// Segment with tangent point that lies exactly on the arc
2198+
let seg = arcseg(point(0.0, 0.0), point(1.0, 0.0));
2199+
// Circle at (5, 0) radius 2, arc from right to top
2200+
let arc2 = arc(point(7.0, 0.0), point(5.0, 2.0), point(5.0, 0.0), 2.0);
2201+
2202+
let result = hull_seg_arc(seg, arc2);
2203+
2204+
// Tangent connects to arc start
2205+
assert_eq!(result.len(), 2);
2206+
assert!(result[0].is_seg());
2207+
assert_eq!(result[0].a, point(1.0, 0.0)); // seg.b
2208+
assert_eq!(result[0].b, point(7.0, 0.0)); // arc2.a
2209+
assert!(!result[1].is_seg());
2210+
assert_eq!(result[1], arc2);
2211+
}
2212+
2213+
#[test]
2214+
fn test_hull_seg_arc_no_tangent_connect_to_arc_start() {
2215+
// Segment and arc where tangent computation finds valid tangent on arc
2216+
let seg = arcseg(point(0.0, 0.0), point(1.0, 1.0));
2217+
let arc2 = arc(point(3.0, 0.0), point(4.0, 1.0), point(4.0, 0.0), 1.0);
2218+
2219+
let result = hull_seg_arc(seg, arc2);
2220+
2221+
// Tangent connection produces 2 elements
2222+
assert_eq!(result.len(), 2);
2223+
assert!(result[0].is_seg());
2224+
assert!(!result[1].is_seg());
2225+
}
2226+
2227+
#[test]
2228+
fn test_hull_seg_arc_segment_below_arc() {
2229+
// Horizontal segment below a convex arc
2230+
let seg = arcseg(point(0.0, 0.0), point(2.0, 0.0));
2231+
let arc2 = arc(point(3.0, 0.0), point(3.0, 2.0), point(3.0, 1.0), 1.0);
2232+
2233+
let result = hull_seg_arc(seg, arc2);
2234+
2235+
// Produces tangent or endpoint connection, 2 elements
2236+
assert_eq!(result.len(), 2);
2237+
assert!(result[0].is_seg());
2238+
assert!(!result[1].is_seg());
2239+
}
2240+
2241+
#[test]
2242+
fn test_hull_seg_arc_segment_to_left_of_arc() {
2243+
// Segment to the left of arc
2244+
let seg = arcseg(point(0.0, 0.0), point(0.0, 2.0)); // Vertical segment
2245+
let arc2 = arc(point(3.0, 0.0), point(5.0, 1.0), point(4.0, 0.0), 1.414);
2246+
2247+
let result = hull_seg_arc(seg, arc2);
2248+
2249+
// Tangent connection, 2 elements
2250+
assert_eq!(result.len(), 2);
2251+
assert!(result[0].is_seg());
2252+
assert!(!result[1].is_seg());
2253+
}
2254+
2255+
#[test]
2256+
fn test_hull_seg_arc_vertical_segment_horizontal_arc() {
2257+
// Vertical segment connecting to horizontally oriented arc
2258+
let seg = arcseg(point(0.0, 0.0), point(0.0, 2.0));
2259+
let arc2 = arc(point(2.0, 3.0), point(4.0, 3.0), point(3.0, 3.0), 1.0);
2260+
2261+
let result = hull_seg_arc(seg, arc2);
2262+
2263+
// Tangent connection, 2 elements
2264+
assert_eq!(result.len(), 2);
2265+
assert!(result[0].is_seg());
2266+
assert!(!result[1].is_seg());
2267+
}
2268+
2269+
#[test]
2270+
fn test_hull_seg_arc_diagonal_segment_to_arc() {
2271+
// Diagonal segment to arc
2272+
let seg = arcseg(point(0.0, 0.0), point(2.0, 1.0));
2273+
let arc2 = arc(point(4.0, 2.0), point(5.0, 3.0), point(5.0, 2.0), 1.0);
2274+
2275+
let result = hull_seg_arc(seg, arc2);
2276+
2277+
// Connection, 2 elements
2278+
assert_eq!(result.len(), 2);
2279+
assert!(result[0].is_seg());
2280+
assert!(!result[1].is_seg());
2281+
}
2282+
2283+
#[test]
2284+
fn test_hull_seg_arc_segment_far_from_arc() {
2285+
// Segment far away from arc
2286+
let seg = arcseg(point(0.0, 0.0), point(1.0, 0.0));
2287+
let arc2 = arc(point(10.0, 5.0), point(11.0, 6.0), point(11.0, 5.0), 1.0);
2288+
2289+
let result = hull_seg_arc(seg, arc2);
2290+
2291+
// Tangent connection, 2 elements
2292+
assert_eq!(result.len(), 2);
2293+
assert!(result[0].is_seg());
2294+
assert!(!result[1].is_seg());
2295+
}
2296+
2297+
#[test]
2298+
fn test_hull_seg_arc_touching_segment_and_arc() {
2299+
// Segment endpoint touches arc start, but tangent from seg.a to arc exists
2300+
let seg = arcseg(point(0.0, 0.0), point(2.0, 0.0));
2301+
let arc2 = arc(point(2.0, 0.0), point(3.0, 1.0), point(3.0, 0.0), 1.0);
2302+
2303+
let result = hull_seg_arc(seg, arc2);
2304+
2305+
// Tangent from seg.a found on arc, produces 2 elements
2306+
assert_eq!(result.len(), 2);
2307+
assert!(result[0].is_seg());
2308+
// Tangent from (0,0) to arc's circle
2309+
assert!(result[0].a == seg.a);
2310+
assert!(!result[1].is_seg());
2311+
}
2312+
2313+
#[test]
2314+
fn test_hull_seg_arc_small_arc() {
2315+
// Small arc to test numerical stability
2316+
let seg = arcseg(point(0.0, 0.0), point(0.1, 0.0));
2317+
let arc2 = arc(point(0.3, 0.0), point(0.4, 0.05), point(0.4, 0.0), 0.05);
2318+
2319+
let result = hull_seg_arc(seg, arc2);
2320+
2321+
// Should produce 2 elements
2322+
assert_eq!(result.len(), 2);
2323+
assert!(result[0].is_seg());
2324+
assert!(!result[1].is_seg());
2325+
}
2326+
2327+
#[test]
2328+
fn test_hull_seg_arc_large_arc() {
2329+
// Large arc with segment
2330+
let seg = arcseg(point(0.0, 0.0), point(5.0, 0.0));
2331+
let arc2 = arc(point(10.0, 0.0), point(10.0, 10.0), point(10.0, 5.0), 5.0);
2332+
2333+
let result = hull_seg_arc(seg, arc2);
2334+
2335+
// Connection, 2 elements
2336+
assert_eq!(result.len(), 2);
2337+
assert!(result[0].is_seg());
2338+
assert!(!result[1].is_seg());
2339+
}
2340+
2341+
#[test]
2342+
fn test_hull_seg_arc_negative_coordinates() {
2343+
// Segment and arc with negative coordinates
2344+
let seg = arcseg(point(-5.0, -2.0), point(-3.0, -2.0));
2345+
let arc2 = arc(point(-1.0, -1.0), point(0.0, 0.0), point(0.0, -1.0), 1.0);
2346+
2347+
let result = hull_seg_arc(seg, arc2);
2348+
2349+
// Connection, 2 elements
2350+
assert_eq!(result.len(), 2);
2351+
assert!(result[0].is_seg());
2352+
assert!(!result[1].is_seg());
2353+
}
2354+
2355+
#[test]
2356+
fn test_hull_seg_arc_arc_below_segment() {
2357+
// Arc positioned below the segment
2358+
let seg = arcseg(point(0.0, 5.0), point(2.0, 5.0));
2359+
let arc2 = arc(point(3.0, 2.0), point(4.0, 1.0), point(4.0, 2.0), 1.0);
2360+
2361+
let result = hull_seg_arc(seg, arc2);
2362+
2363+
// Connection, 2 elements
2364+
assert_eq!(result.len(), 2);
2365+
assert!(result[0].is_seg());
2366+
assert!(!result[1].is_seg());
2367+
}
2368+
2369+
#[test]
2370+
fn test_hull_seg_arc_semicircle() {
2371+
// Segment to semicircular arc
2372+
let seg = arcseg(point(0.0, 0.0), point(1.0, 0.0));
2373+
let arc2 = arc(point(3.0, 0.0), point(5.0, 0.0), point(4.0, 0.0), 1.0);
2374+
2375+
let result = hull_seg_arc(seg, arc2);
2376+
2377+
// Tangent connection, 2 elements
2378+
assert_eq!(result.len(), 2);
2379+
assert!(result[0].is_seg());
2380+
assert!(!result[1].is_seg());
2381+
}
2382+
2383+
#[test]
2384+
fn test_hull_seg_arc_quarter_circle() {
2385+
// Segment to quarter circle arc
2386+
let seg = arcseg(point(0.0, 0.0), point(1.0, 0.0));
2387+
// Quarter arc from right to top
2388+
let arc2 = arc(point(3.0, 0.0), point(2.0, 1.0), point(2.0, 0.0), 1.0);
2389+
2390+
let result = hull_seg_arc(seg, arc2);
2391+
2392+
// Connection from seg.b to arc start + full arc
2393+
assert_eq!(result.len(), 2);
2394+
assert!(result[0].is_seg());
2395+
assert_eq!(result[0].a, point(1.0, 0.0)); // seg.b
2396+
assert_eq!(result[0].b, point(3.0, 0.0)); // arc2.a
2397+
assert_eq!(result[1], arc2);
2398+
}
2399+
2400+
#[test]
2401+
fn test_hull_seg_arc_arc_wrapping_around() {
2402+
// Arc that wraps significantly (large angular span)
2403+
let seg = arcseg(point(0.0, 0.0), point(1.0, 0.0));
2404+
// Large arc spanning more than 180 degrees
2405+
let arc2 = arc(point(4.0, 0.0), point(2.0, 0.0), point(3.0, 0.0), 1.0);
2406+
2407+
let result = hull_seg_arc(seg, arc2);
2408+
2409+
// Connection from seg.b to arc start + full arc
2410+
assert_eq!(result.len(), 2);
2411+
assert!(result[0].is_seg());
2412+
assert_eq!(result[0].a, point(1.0, 0.0)); // seg.b
2413+
assert_eq!(result[0].b, point(4.0, 0.0)); // arc2.a
2414+
assert_eq!(result[1], arc2);
2415+
}
2416+
2417+
#[test]
2418+
fn test_hull_seg_arc_parallel_segment_and_arc_chord() {
2419+
// Segment parallel to arc's chord
2420+
let seg = arcseg(point(0.0, 0.0), point(2.0, 0.0));
2421+
let arc2 = arc(point(3.0, 1.0), point(5.0, 1.0), point(4.0, 1.0), 1.0);
2422+
2423+
let result = hull_seg_arc(seg, arc2);
2424+
2425+
// Connection, 2 elements
2426+
assert_eq!(result.len(), 2);
2427+
assert!(result[0].is_seg());
2428+
assert!(!result[1].is_seg());
2429+
}
2430+
2431+
#[test]
2432+
fn test_hull_seg_arc_perpendicular_configurations() {
2433+
// Segment perpendicular to arc's general direction
2434+
let seg = arcseg(point(0.0, 0.0), point(0.0, 2.0)); // Vertical
2435+
let arc2 = arc(point(2.0, 3.0), point(4.0, 3.0), point(3.0, 3.0), 1.0); // Horizontal arc
2436+
2437+
let result = hull_seg_arc(seg, arc2);
2438+
2439+
// Tangent connection, 2 elements
2440+
assert_eq!(result.len(), 2);
2441+
assert!(result[0].is_seg());
2442+
assert!(!result[1].is_seg());
2443+
}
2444+
2445+
#[test]
2446+
fn test_hull_seg_arc_segment_inside_arc_circle() {
2447+
// Segment that's inside the circle's radius but arc doesn't cover it
2448+
let seg = arcseg(point(0.0, 0.0), point(1.0, 0.0));
2449+
// Circle center at (2, 0), radius 3, but arc only covers top portion
2450+
let arc2 = arc(point(5.0, 0.0), point(2.0, 3.0), point(2.0, 0.0), 3.0);
2451+
2452+
let result = hull_seg_arc(seg, arc2);
2453+
2454+
// Connection from seg.b to arc start + full arc
2455+
assert_eq!(result.len(), 2);
2456+
assert!(result[0].is_seg());
2457+
assert_eq!(result[0].a, point(1.0, 0.0)); // seg.b
2458+
assert_eq!(result[0].b, point(5.0, 0.0)); // arc2.a
2459+
assert_eq!(result[1], arc2);
2460+
}
21702461
}

0 commit comments

Comments
 (0)