// SPDX-License-Identifier: GPL-2.0-or-later /* * Class for pure transformations, such as translating, scaling, stretching, skewing, and rotating. Pure means that they * cannot be combined. This is what makes them different from affine transformations. Pure transformations are being * used in the selector tool and node tool * * Authors: * Diederik van Lierop * * Copyright (C) 2015 Diederik van Lierop * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #ifndef SEEN_PURE_TRANSFORM_H #define SEEN_PURE_TRANSFORM_H #include // for g_warning #include "snapper.h" // for SnapConstraint class SnapManager; namespace Inkscape { class PureTransform { protected: virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const = 0; virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const = 0; virtual void storeTransform(SnapCandidatePoint const &original_point, SnappedPoint &snapped_point) = 0; public: //PureTransform(); virtual ~PureTransform() = default;; // virtual PureTransform * clone () const = 0; // https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Virtual_Constructor // Snap a group of points SnappedPoint best_snapped_point; void snap(::SnapManager *sm, std::vector const &points, Geom::Point const &pointer); }; // ************************************************************************************************************** class PureTranslate: public PureTransform { protected: Geom::Point _vector; Geom::Point _vector_snapped; SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const override; Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const override; void storeTransform(SnapCandidatePoint const &original_point, SnappedPoint &snapped_point) override; public: // PureTranslate(); // Default constructor // PureTranslate(PureTranslate const &); // Copy constructor ~PureTranslate() override = default;; PureTranslate(Geom::Point vector = Geom::Point()) : _vector(vector), _vector_snapped(vector) {} Geom::Point getTranslationSnapped() {return _vector_snapped;} // PureTranslate * clone () const {return new PureTranslate(*this);} }; class PureTranslateConstrained: public PureTranslate { protected: Geom::Dim2 _direction; SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const override; public: ~PureTranslateConstrained() override = default; PureTranslateConstrained(Geom::Coord displacement, Geom::Dim2 direction): PureTranslate(), _direction(direction) { _vector[direction] = displacement; _vector[1-direction] = 0.0; } // PureTranslateConstrained * clone () const {return new PureTranslateConstrained(*this);} }; // ************************************************************************************************************** class PureScale: public PureTransform { protected: Geom::Scale _scale; Geom::Scale _scale_snapped; Geom::Point _origin; bool _uniform; SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const override; Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const override; void storeTransform(SnapCandidatePoint const &original_point, SnappedPoint &snapped_point) override; public: // PureScale(); // Default constructor // PureScale(PureScale const &); // Copy constructor ~PureScale() override = default; PureScale(Geom::Scale scale, Geom::Point origin, bool uniform) : _scale (scale), _scale_snapped (scale), _origin (origin), _uniform (uniform) {} Geom::Scale getScaleSnapped() {return _scale_snapped;} // PureScale * clone () const {return new PureScale (*this);} }; class PureScaleConstrained: public PureScale { //Magnitude of the scale components will be the same, but the sign could still be different () protected: SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const override; public: ~PureScaleConstrained() override = default; PureScaleConstrained(Geom::Scale scale, Geom::Point origin): PureScale(scale, origin, true) {}; // Non-uniform constrained scaling is not supported // PureScaleConstrained * clone () const {return new PureScaleConstrained(*this);} }; // ************************************************************************************************************** class PureStretchConstrained: public PureTransform { // A stretch is always implicitly constrained protected: Geom::Coord _magnitude; Geom::Scale _stretch_snapped; Geom::Point _origin; Geom::Dim2 _direction; bool _uniform; SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const override; Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const override; void storeTransform(SnapCandidatePoint const &original_point, SnappedPoint &snapped_point) override; public: ~PureStretchConstrained() override = default;; PureStretchConstrained(Geom::Coord magnitude, Geom::Point origin, Geom::Dim2 direction, bool uniform) : _magnitude (magnitude), _stretch_snapped (Geom::Scale(magnitude, magnitude)), _origin (origin), _direction (direction), _uniform (uniform) { if (not uniform) { _stretch_snapped[1-direction] = 1.0; } } Geom::Scale getStretchSnapped() {return _stretch_snapped;} Geom::Coord getMagnitude() {return _magnitude;} Geom::Coord getMagnitudeSnapped() {return _stretch_snapped[_direction];} // PureStretchConstrained * clone () const {return new PureStretchConstrained(*this);} }; // ************************************************************************************************************** class PureSkewConstrained: public PureTransform { // A skew is always implicitly constrained protected: Geom::Coord _skew; Geom::Coord _skew_snapped; Geom::Coord _scale; Geom::Point _origin; Geom::Dim2 _direction; SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const override; Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const override; void storeTransform(SnapCandidatePoint const &original_point, SnappedPoint &snapped_point) override; public: ~PureSkewConstrained() override = default;; PureSkewConstrained(Geom::Coord skew, Geom::Coord scale, Geom::Point origin, Geom::Dim2 direction) : _skew (skew), _skew_snapped (skew), _scale (scale), _origin (origin), _direction (direction) {}; Geom::Coord getSkewSnapped() {return _skew_snapped;} // PureSkewConstrained * clone () const {return new PureSkewConstrained(*this);} }; // ************************************************************************************************************** class PureRotateConstrained: public PureTransform { // A rotation is always implicitly constrained, so we will hide the constructor by making it protected; devs should use PureRotateConstrained instead // It's _constraint member variable though will be empty protected: double _angle; // in radians double _angle_snapped; Geom::Point _origin; bool _uniform; SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const override; Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const override; void storeTransform(SnapCandidatePoint const &original_point, SnappedPoint &snapped_point) override; public: // PureRotate(); // Default constructor // PureRotate(PureRotate const &); // Copy constructor ~PureRotateConstrained() override = default;; PureRotateConstrained(double angle, Geom::Point origin) : _angle (angle), // in radians! _angle_snapped (angle), _origin (origin), _uniform (true) // We do not yet allow for simultaneous rotation and scaling {} double getAngleSnapped() {return _angle_snapped;} // PureRotate * clone () const {return new PureRotate(*this);} }; } #endif // !SEEN_PURE_TRANSFORM_H