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 }