File indexing completed on 2025-02-02 04:11:07

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #include "round_corners.hpp"
0008 
0009 GLAXNIMATE_OBJECT_IMPL(glaxnimate::model::RoundCorners)
0010 
0011 using namespace glaxnimate::math;
0012 
0013 QIcon glaxnimate::model::RoundCorners::static_tree_icon()
0014 {
0015     return QIcon::fromTheme("transform-affect-rounded-corners");
0016 }
0017 
0018 QString glaxnimate::model::RoundCorners::static_type_name_human()
0019 {
0020     return i18n("Round Corners");
0021 }
0022 
0023 bool glaxnimate::model::RoundCorners::process_collected() const
0024 {
0025     return false;
0026 }
0027 
0028 static std::pair<QPointF, QPointF> get_vert_tan(const glaxnimate::math::bezier::Bezier& bezier, const QPointF& current_vertex, int closest_index, qreal round_distance)
0029 {
0030     // value from https://spencermortensen.com/articles/bezier-circle/
0031     static const qreal tangent_length = 0.5519;
0032     if ( closest_index < 0 )
0033         closest_index += bezier.size();
0034     auto closest_vertex = bezier[closest_index].pos;
0035     auto distance = glaxnimate::math::length(current_vertex - closest_vertex);
0036     auto new_pos_perc = distance != 0 ? glaxnimate::math::min(distance/2, round_distance) / distance : 0;
0037     auto vertex = current_vertex + (closest_vertex - current_vertex) * new_pos_perc;
0038     auto tangent = - (vertex - current_vertex) * tangent_length;
0039     return {vertex, tangent};
0040 }
0041 
0042 static glaxnimate::math::bezier::Bezier round_corners(const glaxnimate::math::bezier::Bezier& original, qreal round_distance)
0043 {
0044     glaxnimate::math::bezier::Bezier result;
0045     result.set_closed(original.closed());
0046 
0047     for ( int i = 0; i < original.size(); i++ )
0048     {
0049         if (
0050             (!original.closed() && (i == 0 || i == original.size() - 1)) ||
0051             !fuzzy_compare(original[i].tan_in, original[i].pos) ||
0052             !fuzzy_compare(original[i].tan_out, original[i].pos)
0053         )
0054         {
0055             result.push_back(original[i]);
0056         }
0057         else
0058         {
0059             QPointF vert1, vert2, out_t, in_t;
0060             std::tie(vert1, out_t) = get_vert_tan(original, original[i].pos, i - 1, round_distance);
0061             result.add_point(vert1, {0, 0}, out_t);
0062             std::tie(vert2, in_t) = get_vert_tan(original, original[i].pos, i + 1, round_distance);
0063             result.add_point(vert2, in_t, {0, 0});
0064         }
0065     }
0066 
0067     return result;
0068 }
0069 
0070 glaxnimate::math::bezier::MultiBezier glaxnimate::model::RoundCorners::process(glaxnimate::model::FrameTime t, const math::bezier::MultiBezier& mbez) const
0071 {
0072     qreal round_distance = radius.get_at(t);
0073 
0074     math::bezier::MultiBezier result;
0075     for ( const auto& inbez : mbez.beziers() )
0076         result.beziers().push_back(round_corners(inbez, round_distance));
0077 
0078     return result;
0079 }