| // Copyright 2022 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "ink_stroke_modeler/params.h" |
| |
| #include <cmath> |
| |
| #include "absl/status/status.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/strings/substitute.h" |
| #include "absl/types/variant.h" |
| #include "ink_stroke_modeler/internal/validation.h" |
| |
| // This convenience macro evaluates the given expression, and if it does not |
| // return an OK status, returns and propagates the status. |
| #define RETURN_IF_ERROR(expr) \ |
| do { \ |
| if (auto status = (expr); !status.ok()) return status; \ |
| } while (false) |
| |
| namespace ink { |
| namespace stroke_model { |
| |
| absl::Status ValidatePositionModelerParams( |
| const PositionModelerParams& params) { |
| RETURN_IF_ERROR(ValidateGreaterThanZero(params.spring_mass_constant, |
| "PredictionParams::spring_mass")); |
| return ValidateGreaterThanZero(params.drag_constant, |
| "PredictionParams::drag_ratio"); |
| } |
| |
| absl::Status ValidateSamplingParams(const SamplingParams& params) { |
| RETURN_IF_ERROR(ValidateGreaterThanZero(params.min_output_rate, |
| "PredictionParams::min_output_rate")); |
| RETURN_IF_ERROR(ValidateGreaterThanZero( |
| params.end_of_stroke_stopping_distance, |
| "PredictionParams::end_of_stroke_stopping_distance")); |
| return ValidateGreaterThanZero( |
| params.end_of_stroke_max_iterations, |
| "PredictionParams::end_of_stroke_stopping_distance"); |
| } |
| |
| absl::Status ValidateStylusStateModelerParams( |
| const StylusStateModelerParams& params) { |
| return ValidateGreaterThanZero(params.max_input_samples, |
| "StylusStateModelerParams::max_input_samples"); |
| } |
| |
| absl::Status ValidateWobbleSmootherParams(const WobbleSmootherParams& params) { |
| RETURN_IF_ERROR(ValidateGreaterThanOrEqualToZero( |
| params.timeout.Value(), "WobbleSmootherParams::timeout")); |
| RETURN_IF_ERROR(ValidateGreaterThanOrEqualToZero( |
| params.speed_floor, "WobbleSmootherParams::speed_floor")); |
| RETURN_IF_ERROR(ValidateIsFiniteNumber( |
| params.speed_ceiling, "WobbleSmootherParams::speed_ceiling")); |
| if (params.speed_ceiling < params.speed_floor) { |
| return absl::InvalidArgumentError(absl::Substitute( |
| "WobbleSmootherParams::speed_ceiling must be greater than or " |
| "equal to WobbleSmootherParams::speed_floor ($0). Actual " |
| "value: $1", |
| params.speed_floor, params.speed_ceiling)); |
| } |
| return absl::OkStatus(); |
| } |
| |
| absl::Status ValidatePredictionParams(const PredictionParams& params) { |
| if (absl::holds_alternative<StrokeEndPredictorParams>(params)) { |
| // Nothing to validate. |
| return absl::OkStatus(); |
| } |
| |
| const KalmanPredictorParams& kalman_params = |
| absl::get<KalmanPredictorParams>(params); |
| RETURN_IF_ERROR(ValidateGreaterThanZero( |
| kalman_params.process_noise, "KalmanPredictorParams::process_noise")); |
| RETURN_IF_ERROR( |
| ValidateGreaterThanZero(kalman_params.measurement_noise, |
| "KalmanPredictorParams::measurement_noise")); |
| RETURN_IF_ERROR( |
| ValidateGreaterThanZero(kalman_params.min_stable_iteration, |
| "KalmanPredictorParams::min_stable_iteration")); |
| RETURN_IF_ERROR( |
| ValidateGreaterThanZero(kalman_params.max_time_samples, |
| "KalmanPredictorParams::max_time_samples")); |
| RETURN_IF_ERROR( |
| ValidateGreaterThanZero(kalman_params.min_catchup_velocity, |
| "KalmanPredictorParams::min_catchup_velocity")); |
| RETURN_IF_ERROR( |
| ValidateIsFiniteNumber(kalman_params.acceleration_weight, |
| "KalmanPredictorParams::acceleration_weight")); |
| RETURN_IF_ERROR(ValidateIsFiniteNumber(kalman_params.jerk_weight, |
| "KalmanPredictorParams::jerk_weight")); |
| RETURN_IF_ERROR( |
| ValidateGreaterThanZero(kalman_params.prediction_interval.Value(), |
| "KalmanPredictorParams::jerk_weight")); |
| |
| const KalmanPredictorParams::ConfidenceParams& confidence_params = |
| kalman_params.confidence_params; |
| RETURN_IF_ERROR(ValidateGreaterThanZero( |
| confidence_params.desired_number_of_samples, |
| "KalmanPredictorParams::ConfidenceParams::desired_number_of_samples")); |
| RETURN_IF_ERROR(ValidateGreaterThanZero( |
| confidence_params.max_estimation_distance, |
| "KalmanPredictorParams::ConfidenceParams::max_estimation_distance")); |
| RETURN_IF_ERROR(ValidateGreaterThanOrEqualToZero( |
| confidence_params.min_travel_speed, |
| "KalmanPredictorParams::ConfidenceParams::min_travel_speed")); |
| RETURN_IF_ERROR(ValidateIsFiniteNumber( |
| confidence_params.max_travel_speed, |
| "KalmanPredictorParams::ConfidenceParams::max_travel_speed")); |
| if (confidence_params.max_travel_speed < confidence_params.min_travel_speed) { |
| return absl::InvalidArgumentError( |
| absl::Substitute("KalmanPredictorParams::ConfidenceParams::max_" |
| "travel_speed must be greater than or equal to " |
| "KalmanPredictorParams::ConfidenceParams::min_" |
| "travel_speed ($0). Actual value: $1", |
| confidence_params.min_travel_speed, |
| confidence_params.max_travel_speed)); |
| } |
| RETURN_IF_ERROR(ValidateGreaterThanZero( |
| confidence_params.max_linear_deviation, |
| "KalmanPredictorParams::ConfidenceParams::max_linear_deviation")); |
| if (confidence_params.baseline_linearity_confidence < 0 || |
| confidence_params.baseline_linearity_confidence > 1) { |
| return absl::InvalidArgumentError(absl::Substitute( |
| "KalmanPredictorParams::ConfidenceParams::baseline_linearity_" |
| "confidence must lie in the interval [0, 1]. Actual value: $0", |
| confidence_params.baseline_linearity_confidence)); |
| } |
| return absl::OkStatus(); |
| } |
| |
| absl::Status ValidateStrokeModelParams(const StrokeModelParams& params) { |
| RETURN_IF_ERROR(ValidateWobbleSmootherParams(params.wobble_smoother_params)); |
| RETURN_IF_ERROR( |
| ValidatePositionModelerParams(params.position_modeler_params)); |
| RETURN_IF_ERROR(ValidateSamplingParams(params.sampling_params)); |
| RETURN_IF_ERROR( |
| ValidateStylusStateModelerParams(params.stylus_state_modeler_params)); |
| return ValidatePredictionParams(params.prediction_params); |
| } |
| |
| } // namespace stroke_model |
| } // namespace ink |
| |
| #undef RETURN_IF_ERROR |