File indexing completed on 2024-12-15 04:01:12
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <QPointF> 0010 #include <QTransform> 0011 #include "math/vector.hpp" 0012 #include "math/math.hpp" 0013 0014 namespace glaxnimate::math::bezier { 0015 0016 enum PointType 0017 { 0018 Corner, 0019 Smooth, 0020 Symmetrical, 0021 }; 0022 0023 struct Point 0024 { 0025 QPointF pos; 0026 QPointF tan_in; 0027 QPointF tan_out; 0028 PointType type; 0029 0030 Point( 0031 const QPointF& pos, 0032 const QPointF& tan_in, 0033 const QPointF& tan_out, 0034 PointType type = Corner 0035 ) : pos(pos), tan_in(tan_in), tan_out(tan_out), type(type) 0036 {} 0037 0038 Point(const QPointF& pos = {0, 0}) 0039 : Point(pos, pos, pos, Corner) 0040 {} 0041 0042 static Point from_relative( 0043 const QPointF& pos, 0044 const QPointF& tan_in_rel = {0, 0}, 0045 const QPointF& tan_out_rel = {0, 0}, 0046 PointType type = Corner 0047 ) 0048 { 0049 return {pos, pos+tan_in_rel, pos+tan_out_rel, type}; 0050 } 0051 0052 QPointF relative_tan_in() const 0053 { 0054 return tan_in - pos; 0055 } 0056 0057 QPointF relative_tan_out() const 0058 { 0059 return tan_out - pos; 0060 } 0061 0062 PolarVector<QPointF> polar_tan_in() const 0063 { 0064 return relative_tan_in(); 0065 } 0066 0067 PolarVector<QPointF> polar_tan_out() const 0068 { 0069 return relative_tan_out(); 0070 } 0071 0072 void drag_tan_in(const QPointF& p) 0073 { 0074 tan_in = p; 0075 tan_out = drag_tangent(tan_in, tan_out, pos, type); 0076 } 0077 0078 void drag_tan_out(const QPointF& p) 0079 { 0080 tan_out = p; 0081 tan_in = drag_tangent(tan_out, tan_in, pos, type); 0082 } 0083 0084 void adjust_handles_from_type(); 0085 0086 void set_point_type(PointType t) 0087 { 0088 type = t; 0089 adjust_handles_from_type(); 0090 } 0091 0092 static QPointF drag_tangent(const QPointF& dragged, const QPointF& other, const QPointF& pos, PointType type) 0093 { 0094 if ( type == math::bezier::PointType::Symmetrical ) 0095 { 0096 return 2*pos - dragged; 0097 } 0098 else if ( type == math::bezier::PointType::Smooth ) 0099 { 0100 return math::PolarVector<QPointF>{ 0101 math::length(other - pos), 0102 pi + math::angle(dragged - pos) 0103 }.to_cartesian() + pos; 0104 } 0105 0106 return other; 0107 } 0108 0109 void translate(const QPointF& delta) 0110 { 0111 pos += delta; 0112 tan_in += delta; 0113 tan_out += delta; 0114 } 0115 0116 void translate_to(const QPointF& new_pos) 0117 { 0118 translate(new_pos - pos); 0119 } 0120 0121 void transform(const QTransform& t); 0122 0123 QPointF position() const { return pos; } 0124 }; 0125 0126 0127 } // namespace glaxnimate::math::bezier 0128 0129 Q_DECLARE_METATYPE(glaxnimate::math::bezier::Point)