92 lines
2.4 KiB
Dart
92 lines
2.4 KiB
Dart
import 'package:abawo_bt_app/model/gear_ratio_codec.dart';
|
|
|
|
enum GearRetentionMode { keepHighest, keepAll }
|
|
|
|
class GearConfiguratorCalculation {
|
|
const GearConfiguratorCalculation({
|
|
required this.ratios,
|
|
required this.discardedBelowRange,
|
|
required this.discardedAboveRange,
|
|
required this.duplicateCount,
|
|
required this.truncatedCount,
|
|
});
|
|
|
|
final List<double> ratios;
|
|
final int discardedBelowRange;
|
|
final int discardedAboveRange;
|
|
final int duplicateCount;
|
|
final int truncatedCount;
|
|
}
|
|
|
|
GearConfiguratorCalculation calculateGearRatios({
|
|
required List<int> chainrings,
|
|
required List<int> sprockets,
|
|
required GearRetentionMode mode,
|
|
int maxRatios = 32,
|
|
}) {
|
|
final sortedChainrings = List<int>.from(chainrings)..sort();
|
|
final sortedSprockets = List<int>.from(sprockets)..sort((a, b) => b - a);
|
|
|
|
var discardedBelowRange = 0;
|
|
var discardedAboveRange = 0;
|
|
var duplicateCount = 0;
|
|
final encoded = <int>{};
|
|
final ratios = <double>[];
|
|
|
|
void addRatio(double ratio) {
|
|
if (ratio < gearRatioMin) {
|
|
discardedBelowRange++;
|
|
return;
|
|
}
|
|
if (ratio > gearRatioMax) {
|
|
discardedAboveRange++;
|
|
return;
|
|
}
|
|
|
|
final raw = encodeGearRatioByte(ratio);
|
|
if (!encoded.add(raw)) {
|
|
duplicateCount++;
|
|
return;
|
|
}
|
|
ratios.add(decodeGearRatioByte(raw));
|
|
}
|
|
|
|
switch (mode) {
|
|
case GearRetentionMode.keepAll:
|
|
for (final chainring in sortedChainrings) {
|
|
for (final sprocket in sortedSprockets) {
|
|
addRatio(chainring / sprocket);
|
|
}
|
|
}
|
|
break;
|
|
case GearRetentionMode.keepHighest:
|
|
var threshold = double.negativeInfinity;
|
|
for (final chainring in sortedChainrings) {
|
|
final beforeLength = ratios.length;
|
|
for (final sprocket in sortedSprockets) {
|
|
final ratio = chainring / sprocket;
|
|
if (ratio >= threshold) {
|
|
addRatio(ratio);
|
|
}
|
|
}
|
|
if (ratios.length > beforeLength) {
|
|
threshold = ratios.reduce((a, b) => a > b ? a : b);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
ratios.sort();
|
|
final truncatedCount =
|
|
ratios.length > maxRatios ? ratios.length - maxRatios : 0;
|
|
final limited = ratios.take(maxRatios).toList(growable: false);
|
|
|
|
return GearConfiguratorCalculation(
|
|
ratios: limited,
|
|
discardedBelowRange: discardedBelowRange,
|
|
discardedAboveRange: discardedAboveRange,
|
|
duplicateCount: duplicateCount,
|
|
truncatedCount: truncatedCount,
|
|
);
|
|
}
|