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)