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