2022-10-29 18:02:45 +00:00
|
|
|
import 'dart:math';
|
|
|
|
|
|
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
2022-12-04 19:12:52 +00:00
|
|
|
import 'package:lightmeter/models/aperture_value.dart';
|
2022-10-29 18:02:45 +00:00
|
|
|
import 'package:lightmeter/models/exposure_pair.dart';
|
2022-12-04 19:12:52 +00:00
|
|
|
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';
|
2022-12-04 19:12:52 +00:00
|
|
|
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(
|
2022-12-01 20:49:06 +00:00
|
|
|
MeteringState(
|
|
|
|
iso: isoValues.where((element) => element.value == 100).first,
|
2022-10-29 18:02:45 +00:00
|
|
|
ev: 21.3,
|
|
|
|
evCompensation: 0.0,
|
2022-12-04 19:12:52 +00:00
|
|
|
nd: ndValues.first,
|
2022-10-29 18:02:45 +00:00
|
|
|
exposurePairs: [],
|
|
|
|
),
|
|
|
|
) {
|
2022-12-04 19:00:43 +00:00
|
|
|
on<IsoChangedEvent>(_onIsoChanged);
|
2022-12-04 19:12:52 +00:00
|
|
|
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),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2022-12-04 19:12:52 +00:00
|
|
|
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)];
|
|
|
|
|
2022-12-04 20:10:04 +00:00
|
|
|
final evAtSystemIso = log2(pow(aperture.value, 2).toDouble() / shutterSpeed.value);
|
2022-12-01 20:49:06 +00:00
|
|
|
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,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|