1 // Copyright (C) 2012-2019 The VPaint Developers. 2 // See the COPYRIGHT file at the top-level directory of this distribution 3 // and at https://github.com/dalboris/vpaint/blob/master/COPYRIGHT 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #ifndef VAC_EDGE_GEOMETRY_H 18 #define VAC_EDGE_GEOMETRY_H 19 20 #include <QList> 21 #include <QString> 22 #include "Eigen.h" 23 24 #include "EdgeSample.h" 25 #include "SculptCurve.h" 26 #include "Triangles.h" 27 28 class QTextStream; 29 class XmlStreamWriter; 30 class XmlStreamReader; 31 32 namespace VectorAnimationComplex 33 { 34 35 class EdgeGeometry 36 { 37 public: 38 EdgeGeometry(double ds = 5.0); 39 virtual ~EdgeGeometry(); 40 41 42 virtual EdgeGeometry * clone(); 43 44 // draw the edge with its stored variable width 45 virtual void draw(); 46 virtual void triangulate(Triangles & triangles); 47 48 // draw the edges with a fixed width (ignore stored width) 49 virtual void draw(double width); 50 virtual void triangulate(double width, Triangles & triangles); 51 52 // override these for your specific curve representation 53 Eigen::Vector2d pos2d(double s); 54 virtual EdgeSample pos(double s) const; 55 virtual Eigen::Vector2d der(double s); 56 virtual double length() const; 57 virtual EdgeGeometry * trimmed(double from, double to); 58 59 // convenient methods 60 virtual EdgeSample leftPos() const; 61 virtual EdgeSample rightPos() const; 62 Eigen::Vector2d leftPos2d(); 63 Eigen::Vector2d rightPos2d(); 64 65 // no need to override sample(ds) unless pos(s) is 66 // expensive and sample(ds) can be done more efficiently 67 // than in length/ds * pos(s) operations. 68 void resample(); 69 void resample(double ds); 70 QList<Eigen::Vector2d> & sampling(); 71 QList<Eigen::Vector2d> & sampling(double ds); 72 virtual QList<EdgeSample> edgeSampling() const; 73 74 void clearSampling(); // call this if the geometry changed 75 76 // geometry manipulation 77 virtual void setLeftRightPos(const Eigen::Vector2d & left, 78 const Eigen::Vector2d & right); 79 virtual void setRightDer(const Eigen::Vector2d & rightDer, double radius, bool resample); 80 virtual void setLeftDer(const Eigen::Vector2d & leftDer, double radius, bool resample); 81 virtual void setWidth(double newWidth); 82 // sculpting 83 virtual double updateSculpt(double x, double y, double radius); 84 virtual EdgeSample sculptVertex() const; 85 virtual double arclengthOfSculptVertex() const; 86 // deform 87 virtual void beginSculptDeform(double x, double y); 88 virtual void continueSculptDeform(double x, double y); 89 virtual void endSculptDeform(); 90 // change edge width 91 virtual void beginSculptEdgeWidth(double x, double y); 92 virtual void continueSculptEdgeWidth(double x, double y); 93 virtual void endSculptEdgeWidth(); 94 // smooth 95 virtual void beginSculptSmooth(double x, double y); 96 virtual void continueSculptSmooth(double x, double y); 97 virtual void endSculptSmooth(); 98 // loop drag and drop 99 virtual void prepareDragAndDrop(); 100 virtual void performDragAndDrop(double dx, double dy); 101 // affine transform 102 virtual void prepareAffineTransform(); 103 virtual void performAffineTransform(const Eigen::Affine2d & xf); 104 105 106 // Save and Load 107 static EdgeGeometry * read(QTextStream & in); 108 static EdgeGeometry * read(XmlStreamReader & xml); 109 void save(QTextStream & out); 110 virtual void exportSVG(QTextStream & out); stringType()111 virtual QString stringType() const {return "EdgeGeometry";} 112 virtual void write(XmlStreamWriter & xml) const; 113 114 // Others isClosed()115 bool isClosed() const {return isClosed_;} makeLoop()116 void makeLoop() { isClosed_ = true; makeLoop_(); } 117 118 // Closest vertex queries 119 struct ClosestVertexInfo { 120 EdgeSample p; // closest point 121 double s; // arclength of the closest point 122 double d; // distance from the query to the closest point 123 }; 124 virtual ClosestVertexInfo closestPoint(double x, double y); 125 126 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 127 128 protected: 129 // override this only if sample_(ds) can be done in less 130 // than length/ds * pos(s) operations. 131 virtual void resample_(double ds); 132 QList<Eigen::Vector2d> sampling_; 133 134 // Save and Load 135 virtual void save_(QTextStream & out); 136 137 // Others makeLoop_()138 virtual void makeLoop_() {} 139 bool isClosed_; 140 141 142 private: 143 double ds_; 144 145 }; 146 147 class LinearSpline: public EdgeGeometry 148 { 149 public: 150 LinearSpline(double ds = 5.0); 151 LinearSpline(const QList<EdgeSample> & samples, bool loop = false); 152 LinearSpline(const std::vector<EdgeSample,Eigen::aligned_allocator<EdgeSample> > & samples, bool loop = false); 153 LinearSpline(const SculptCurve::Curve<EdgeSample> & other, bool loop = false); 154 LinearSpline(EdgeGeometry & other); // non-const cause 155 // sampling computed 156 LinearSpline(const QList<Eigen::Vector2d> & vertices, bool loop = false); 157 virtual ~LinearSpline(); 158 159 LinearSpline * clone(); 160 161 virtual void draw(); 162 virtual void draw(double width); 163 virtual void triangulate(Triangles & triangles); 164 virtual void triangulate(double width, Triangles & triangles); 165 166 void exportSVG(QTextStream & out); 167 168 virtual EdgeSample leftPos() const; 169 virtual EdgeSample rightPos() const; 170 virtual QList<EdgeSample> edgeSampling() const; 171 172 EdgeSample pos(double s) const; 173 Eigen::Vector2d der(double s); 174 double length() const; 175 EdgeGeometry * trimmed(double from, double to); 176 void setLeftRightPos(const Eigen::Vector2d & left, 177 const Eigen::Vector2d & right); 178 void setRightDer(const Eigen::Vector2d & rightDer, double radius, bool resample); 179 void setLeftDer(const Eigen::Vector2d & leftDer, double radius, bool resample); 180 void setWidth(double newWidth); 181 182 // Sculpting 183 double updateSculpt(double x, double y, double radius); 184 EdgeSample sculptVertex() const; 185 double arclengthOfSculptVertex() const; 186 // Deform 187 void beginSculptDeform(double x, double y); 188 void continueSculptDeform(double x, double y); 189 void endSculptDeform(); 190 // Change Edge Width 191 void beginSculptEdgeWidth(double x, double y); 192 void continueSculptEdgeWidth(double x, double y); 193 void endSculptEdgeWidth(); 194 // Change Edge Width 195 void beginSculptSmooth(double x, double y); 196 void continueSculptSmooth(double x, double y); 197 void endSculptSmooth(); 198 // loop drag and drop 199 void prepareDragAndDrop(); 200 void performDragAndDrop(double dx, double dy); 201 // affine transform 202 void prepareAffineTransform(); 203 void performAffineTransform(const Eigen::Affine2d & xf); 204 // Compute closest point on curve 205 ClosestVertexInfo closestPoint(double x, double y); 206 207 208 LinearSpline(QTextStream & in); 209 //LinearSpline(XmlStreamReader & xml); 210 LinearSpline(const QStringRef & str); // str = curve data from XML, without the type stringType()211 QString stringType() const {return "LinearSpline";} 212 213 SculptCurve::Curve<EdgeSample> & curve(); 214 215 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 216 217 // Sketch 218 int size() const; 219 EdgeSample operator[] (int i) const; 220 void beginSketch(const EdgeSample & resample); 221 void continueSketch(const EdgeSample & resample); 222 void endSketch(); 223 224 protected: 225 void save_(QTextStream & out); 226 void write(XmlStreamWriter & xml) const; 227 228 private: 229 void resample_(double ds); // linear time 230 //void computeLength(); 231 //double length_; 232 //QList<Eigen::Vector2d> vertices_; 233 234 SculptCurve::Curve<EdgeSample> curve_; 235 236 // Store initial curve for affine tranform 237 SculptCurve::Curve<EdgeSample> curveBeforeTransform_; 238 239 // Others 240 void makeLoop_(); 241 242 // sculpting (needs cleaning...) 243 double sculptRadius_; 244 double w_(double s) const; 245 double w2_(double d, double r0, double w0) const; 246 std::vector<EdgeSample,Eigen::aligned_allocator<EdgeSample> > vertices_; 247 std::vector<double> arclengths_; 248 int sculptIndex_; 249 double sculptStartX_; 250 double sculptStartY_; 251 struct SculptTemp 252 { SculptTempSculptTemp253 SculptTemp(int i, double w, double width) : i(i), w(w), width(width) {} 254 int i; double w; double width; 255 }; 256 std::vector<SculptTemp> sculptTemp_; 257 258 // drag and drop 259 double dragAndDrop_lastDx_; 260 double dragAndDrop_lastDy_; 261 }; 262 263 } 264 265 #endif 266