m3_lightmeter/lib/screens/metering/metering_bloc.dart

120 lines
3.7 KiB
Dart
Raw Normal View History

2022-10-29 18:02:45 +00:00
import 'dart:math';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/models/aperture_value.dart';
2022-10-29 18:02:45 +00:00
import 'package:lightmeter/models/exposure_pair.dart';
import 'package:lightmeter/models/iso_value.dart';
import 'package:lightmeter/models/nd_value.dart';
2022-10-29 18:02:45 +00:00
import 'package:lightmeter/models/photography_value.dart';
import 'package:lightmeter/models/shutter_speed_value.dart';
2022-12-04 19:00:43 +00:00
import 'package:lightmeter/utils/log_2.dart';
2022-10-29 18:02:45 +00:00
import 'metering_event.dart';
import 'metering_state.dart';
class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
2022-10-30 18:06:51 +00:00
final StopType stopType;
2022-10-29 18:02:45 +00:00
late final _apertureValues = apertureValues.whereStopType(stopType);
late final _shutterSpeedValues = shutterSpeedValues.whereStopType(stopType);
late final _isoValues = isoValues.whereStopType(stopType);
final _random = Random();
MeteringBloc(this.stopType)
: super(
MeteringState(
iso: isoValues.where((element) => element.value == 100).first,
2022-10-29 18:02:45 +00:00
ev: 21.3,
evCompensation: 0.0,
nd: ndValues.first,
2022-10-29 18:02:45 +00:00
exposurePairs: [],
),
) {
2022-12-04 19:00:43 +00:00
on<IsoChangedEvent>(_onIsoChanged);
on<NdChangedEvent>(_onNdChanged);
2022-10-29 18:02:45 +00:00
on<MeasureEvent>(_onMeasure);
add(const MeasureEvent());
}
2022-12-04 19:00:43 +00:00
void _onIsoChanged(IsoChangedEvent event, Emitter emit) {
final ev = state.ev + log2(event.isoValue.value / state.iso.value);
emit(MeteringState(
iso: event.isoValue,
ev: ev,
evCompensation: state.evCompensation,
nd: state.nd,
exposurePairs: _buildExposureValues(ev),
));
}
void _onNdChanged(NdChangedEvent event, Emitter emit) {
final ev = state.ev - event.ndValue.stopReduction + state.nd.stopReduction;
emit(MeteringState(
iso: state.iso,
ev: ev,
evCompensation: state.evCompensation,
nd: event.ndValue,
exposurePairs: _buildExposureValues(ev),
));
}
2022-10-29 18:14:49 +00:00
/// https://www.scantips.com/lights/exposurecalc.html
2022-10-29 18:02:45 +00:00
void _onMeasure(_, Emitter emit) {
final aperture = _apertureValues[_random.nextInt(_apertureValues.length)];
final shutterSpeed = _shutterSpeedValues[_random.nextInt(_shutterSpeedValues.thirdStops().length)];
final iso = _isoValues[_random.nextInt(_isoValues.thirdStops().length)];
final evAtSystemIso = log2(pow(aperture.value, 2).toDouble() / shutterSpeed.value);
final ev = evAtSystemIso - log2(iso.value / state.iso.value);
2022-10-29 18:02:45 +00:00
emit(MeteringState(
iso: state.iso,
ev: ev,
evCompensation: state.evCompensation,
nd: state.nd,
2022-12-04 19:00:43 +00:00
exposurePairs: _buildExposureValues(ev),
2022-10-29 18:02:45 +00:00
));
}
List<ExposurePair> _buildExposureValues(double ev) {
late final int evSteps;
switch (stopType) {
2022-10-30 18:06:51 +00:00
case StopType.full:
2022-10-29 18:02:45 +00:00
evSteps = ev.floor();
break;
2022-10-30 18:06:51 +00:00
case StopType.half:
2022-10-29 18:02:45 +00:00
evSteps = (ev / 0.5).floor();
break;
2022-10-30 18:06:51 +00:00
case StopType.third:
2022-10-29 18:02:45 +00:00
evSteps = (ev / 0.3).floor();
break;
}
2022-10-30 18:06:51 +00:00
final evOffset = _shutterSpeedValues.indexOf(const ShutterSpeedValue(1, false, StopType.full)) - evSteps;
2022-10-29 18:02:45 +00:00
late final int apertureOffset;
late final int shutterSpeedOffset;
if (evOffset >= 0) {
apertureOffset = 0;
shutterSpeedOffset = evOffset;
} else {
apertureOffset = -evOffset;
shutterSpeedOffset = 0;
}
int itemsCount = min(_apertureValues.length + shutterSpeedOffset, _shutterSpeedValues.length + apertureOffset) -
max(apertureOffset, shutterSpeedOffset);
2022-10-29 18:04:06 +00:00
if (itemsCount < 0) {
return List.empty(growable: false);
}
2022-10-29 18:02:45 +00:00
return List.generate(
itemsCount,
(index) => ExposurePair(
_apertureValues[index + apertureOffset],
_shutterSpeedValues[index + shutterSpeedOffset],
),
growable: false,
);
}
}