| // Copyright 2016 Google Inc. All Rights Reserved. |
| // |
| // 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. |
| |
| #ifndef COBALT_RENDERER_RASTERIZER_COMMON_STREAMING_BEST_FIT_LINE_H_ |
| #define COBALT_RENDERER_RASTERIZER_COMMON_STREAMING_BEST_FIT_LINE_H_ |
| |
| #include <math.h> |
| |
| #include <vector> |
| |
| #include "cobalt/math/exponential_moving_average.h" |
| #include "cobalt/math/point_f.h" |
| |
| namespace cobalt { |
| namespace renderer { |
| namespace rasterizer { |
| namespace common { |
| |
| // Represents a line that is a valid function (i.e. its slope is not infinity). |
| // Primarily used as the result of StreamingBestFitLine. |
| class Line { |
| public: |
| Line(float y_intercept, float slope) |
| : y_intercept_(y_intercept), slope_(slope) {} |
| |
| float value_at(float x) const { return y_intercept_ + slope_ * x; } |
| float y_intercept() const { return y_intercept_; } |
| float slope() const { return slope_; } |
| |
| private: |
| float y_intercept_; |
| float slope_; |
| }; |
| |
| // StreamingBestFitLine takes a sequence of points provided via calls to |
| // AddValue() and internally fits a line to these points, which can be obtained |
| // by a call to line(). Every time AddValue() is called, a sliding window of |
| // a constant number of points is updated and a best fit line that minimizes |
| // the sum of squared differences from the points to the line is calculated. |
| // The new best fit line's parameters are then used to slightly adjust |
| // exponential moving averages for |y_intercept_| and |line_angle_radians_|, to |
| // smooth out changes to the line. |
| class StreamingBestFitLine { |
| public: |
| // |new_value_weight| is forwarded into the constructors for the |
| // ExponentialMovingAverage members of this class and affects how slowly the |
| // line estimate adjusts to new data. If |force_non_negative_slope| is true, |
| // the best estimate line's slope will be clamped to non-negative values. |
| // If |force_non_negative_y_intercept| is true, the best estimate line's |
| // y intercept will be clamped to non-negative values. |
| explicit StreamingBestFitLine(float new_value_weight, |
| bool force_non_negative_slope, |
| bool force_non_negative_y_intercept) |
| : force_non_negative_slope_(force_non_negative_slope), |
| force_non_negative_y_intercept_(force_non_negative_y_intercept), |
| y_intercept_(new_value_weight), |
| line_angle_radians_(new_value_weight), |
| next_point_position_(0) {} |
| |
| // Returns our current best estimate at the line. Note that we translate |
| // the internally stored line angle back into slope. |
| Line best_estimate() const { |
| return Line(*y_intercept_.average(), tan(*line_angle_radians_.average())); |
| } |
| |
| // Adds a new point and updates the internal line estimate to reflect the new |
| // data. |
| void AddValue(float x, float y) { AddValue(math::PointF(x, y)); } |
| void AddValue(const math::PointF& point); |
| |
| private: |
| // Helper function to add a new point to the list of points. |
| void InsertPoint(const math::PointF& point); |
| |
| const bool force_non_negative_slope_; |
| const bool force_non_negative_y_intercept_; |
| |
| math::ExponentialMovingAverage<float> y_intercept_; |
| math::ExponentialMovingAverage<float> line_angle_radians_; |
| |
| // Our set of recent points. |
| std::vector<math::PointF> points_; |
| |
| // Describes where within |points_| the next unique point should be inserted. |
| int next_point_position_; |
| }; |
| |
| } // namespace common |
| } // namespace rasterizer |
| } // namespace renderer |
| } // namespace cobalt |
| |
| #endif // COBALT_RENDERER_RASTERIZER_COMMON_STREAMING_BEST_FIT_LINE_H_ |