Another project
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 4.5 kB View raw
1use bone_solver::{ConstraintSystem, DofConfig, LineHandle, PointHandle, Residual, analyze_dof}; 2use bone_types::{Parameter, ParameterIndex, ResidualIndex}; 3 4fn p(i: u32) -> ParameterIndex { 5 ParameterIndex::new(i) 6} 7 8fn point(x: u32, y: u32) -> PointHandle { 9 PointHandle { x: p(x), y: p(y) } 10} 11 12fn parameters(values: &[f64]) -> Vec<Parameter> { 13 values.iter().copied().map(Parameter::new).collect() 14} 15 16#[test] 17fn fully_constrained_pin_has_zero_dof_and_no_flags() { 18 let system = ConstraintSystem::new( 19 parameters(&[0.0]), 20 vec![Residual::Pin { 21 param: p(0), 22 target: 5.0, 23 }], 24 ); 25 let report = analyze_dof(&system, DofConfig::DEFAULT); 26 assert_eq!(report.dof().value(), 0); 27 assert!(report.under_constrained().is_empty()); 28 assert!(report.over_constrained().is_empty()); 29 assert!(report.redundant_consistent().is_empty()); 30} 31 32#[test] 33fn under_constrained_horizontal_reports_free_parameters() { 34 let system = ConstraintSystem::new( 35 parameters(&[0.0, 0.0, 1.0, 0.0]), 36 vec![Residual::Horizontal(LineHandle { 37 a: point(0, 1), 38 b: point(2, 3), 39 })], 40 ); 41 let report = analyze_dof(&system, DofConfig::DEFAULT); 42 assert_eq!(report.dof().value(), 3); 43 assert_eq!(report.under_constrained().len(), 3); 44 assert!(report.over_constrained().is_empty()); 45 assert!(report.redundant_consistent().is_empty()); 46} 47 48#[test] 49fn redundant_pin_is_consistent_not_conflict() { 50 let system = ConstraintSystem::new( 51 parameters(&[5.0]), 52 vec![ 53 Residual::Pin { 54 param: p(0), 55 target: 5.0, 56 }, 57 Residual::Pin { 58 param: p(0), 59 target: 5.0, 60 }, 61 ], 62 ); 63 let report = analyze_dof(&system, DofConfig::DEFAULT); 64 assert_eq!(report.dof().value(), 0); 65 assert!(report.over_constrained().is_empty()); 66 assert_eq!(report.redundant_consistent().len(), 1); 67 let flagged = report.redundant_consistent()[0]; 68 assert!(flagged == ResidualIndex::new(0) || flagged == ResidualIndex::new(1)); 69} 70 71#[test] 72fn dof_fixture_matrix_snapshot() { 73 let fully_constrained = ConstraintSystem::new( 74 parameters(&[0.0]), 75 vec![Residual::Pin { 76 param: p(0), 77 target: 5.0, 78 }], 79 ); 80 let under_constrained = ConstraintSystem::new( 81 parameters(&[0.0, 0.0, 1.0, 0.0]), 82 vec![Residual::Horizontal(LineHandle { 83 a: point(0, 1), 84 b: point(2, 3), 85 })], 86 ); 87 let redundant_consistent = ConstraintSystem::new( 88 parameters(&[5.0]), 89 vec![ 90 Residual::Pin { 91 param: p(0), 92 target: 5.0, 93 }, 94 Residual::Pin { 95 param: p(0), 96 target: 5.0, 97 }, 98 ], 99 ); 100 let conflicting = ConstraintSystem::new( 101 parameters(&[3.0]), 102 vec![ 103 Residual::Pin { 104 param: p(0), 105 target: 3.0, 106 }, 107 Residual::Pin { 108 param: p(0), 109 target: 7.0, 110 }, 111 ], 112 ); 113 let bundle = [ 114 ("fully_constrained", fully_constrained), 115 ("under_constrained", under_constrained), 116 ("redundant_consistent", redundant_consistent), 117 ("conflicting", conflicting), 118 ]; 119 let rendered: String = bundle 120 .iter() 121 .map(|(label, system)| { 122 format!( 123 "{label}: {}", 124 analyze_dof(system, DofConfig::DEFAULT).display() 125 ) 126 }) 127 .collect::<Vec<_>>() 128 .join("\n"); 129 insta::assert_snapshot!("dof_matrix", rendered); 130} 131 132#[test] 133fn conflicting_pins_yield_over_constrained_row() { 134 let system = ConstraintSystem::new( 135 parameters(&[3.0]), 136 vec![ 137 Residual::Pin { 138 param: p(0), 139 target: 3.0, 140 }, 141 Residual::Pin { 142 param: p(0), 143 target: 7.0, 144 }, 145 ], 146 ); 147 let report = analyze_dof(&system, DofConfig::DEFAULT); 148 assert_eq!(report.dof().value(), 0); 149 assert_eq!(report.over_constrained().len(), 1); 150 assert!(report.redundant_consistent().is_empty()); 151 let flagged = report.over_constrained()[0]; 152 assert!(flagged == ResidualIndex::new(0) || flagged == ResidualIndex::new(1)); 153}