// Dart side of the cross-language parity harness (T07). // Must stay fixture-for-fixture identical to tool/parity/main.kt. import 'dart:math' as math; import 'package:rippr/src/domain/models.dart'; import 'package:rippr/src/geo/geo.dart'; import 'package:rippr/src/stats/ride_statistics.dart'; /// Same LCG as the Kotlin oracle. Dart ints are 64-bit two's complement on the VM and /// multiplication wraps, matching Kotlin's Long. class Lcg { Lcg(this._s); int _s; double nextDouble() { _s = _s * 6364136223846793005 + 1442695040888963407; final bits = (_s >>> 11) & ((1 << 53) - 1); return bits / (1 << 53); } } TrackPoint p(int seg, int ts, double lat, double lon, double sp, double alt, int id) => TrackPoint(id: id, tripId: 1, segmentId: seg, timestamp: ts, latitude: lat, longitude: lon, speedKmh: sp, altitudeM: alt); void main() { void out(String k, Object v) => print('$k=$v'); out('haversine_calgary_edmonton', haversineMeters(51.0447, -114.0719, 53.5461, -113.4938)); out('haversine_short_hop', haversineMeters(51.0447, -114.0719, 51.04480, -114.0719)); out('perp_beyond_end', perpendicularDistanceMeters( const LatLon(51.003, -114.0), const LatLon(51.000, -114.0), const LatLon(51.002, -114.0))); final ride = List.generate(21600, (i) => LatLon(51.0 + i * 0.00001, -114.0 + math.sin(i / 100.0) * 0.001)); final simplified = simplify(ride, 5.0); out('simplify_count', simplified.length); out('simplify_last_lat', simplified.last.lat); out('path_length_ride', pathLengthMeters(ride)); final rng = Lcg(42); final noisy = List.generate(600, (i) => p(1, i * 1000, 51.0, -114.0, 0.0, 1000.0 + (rng.nextDouble() * 16.0 - 8.0), i + 1)); out('noisy_gain', computeSummary(noisy).elevationGainM); out('noisy_loss', computeSummary(noisy).elevationLossM); final climb = List.generate(101, (i) => p(1, i * 1000, 51.0 + i * 0.0001, -114.0, 50.0, 1000.0 + i, i + 1)); out('climb_gain', computeSummary(climb).elevationGainM); final run = List.generate(100, (i) => p(1, i * 1000, 51.0 + i * 0.0001, -114.0, 40.0, 1000.0, i + 1)); final s = computeSummary(run); out('run_distance', s.distanceM); out('run_moving_millis', s.movingMillis); out('run_avg_speed', s.avgMovingSpeedKmh); final prof = elevationProfile(run, maxSamples: 200); out('profile_size', prof.length); out('profile_last_distance', prof.last.distanceM); final hist = speedHistogram(run, bucketKmh: 10); out('hist_buckets', hist.length); out('hist_first_millis', hist.first.millis); }