Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
conic-5.cpp
Go to the documentation of this file.
1#include <iostream>
2#include <2geom/path.h>
6#include <2geom/pathvector.h>
7#include <2geom/exception.h>
10#include <2geom/nearest-time.h>
11#include <2geom/line.h>
14
15#include <cstdlib>
16#include <map>
17#include <vector>
18#include <algorithm>
19#include <optional>
20
21#include <toys/path-cairo.h>
24#include <2geom/ord.h>
25
26
27
28#include <2geom/conicsec.h>
29
30using namespace Geom;
31using namespace std;
32
33
34// File: convert.h
35#include <sstream>
36#include <stdexcept>
37
38class BadConversion : public std::runtime_error {
39public:
40 BadConversion(const std::string& s)
41 : std::runtime_error(s)
42 { }
43};
44
45template <typename T>
46inline std::string stringify(T x)
47{
48 std::ostringstream o;
49 if (!(o << x))
50 throw BadConversion("stringify(T)");
51 return o.str();
52}
53
55 cairo_move_to(cr, rq.P[0]);
56 cairo_line_to(cr, rq.P[1]);
57 cairo_line_to(cr, rq.P[2]);
58 cairo_stroke(cr);
59}
60
61
62
63void draw(cairo_t* cr, xAx C, Rect bnd) {
64 if(bnd[1].extent() < 5) return;
65 vector<double> prev_rts;
66 double py = bnd[Y].min();
67 for(int i = 0; i < 100; i++) {
68 double t = i/100.;
69 double y = bnd[Y].valueAt(t);
70 vector<double> rts = C.roots(Point(1, 0), Point(0, y));
71 int top = 0;
72 for(unsigned j = 0; j < rts.size(); j++) {
73 if(bnd[0].contains(rts[j])) {
74 rts[top] = rts[j];
75 top++;
76 }
77 }
78 rts.erase(rts.begin()+top, rts.end());
79
80 if(rts.size() == prev_rts.size()) {
81 for(unsigned j = 0; j < rts.size(); j++) {
82 cairo_move_to(cr, prev_rts[j], py);
83 cairo_line_to(cr, rts[j], y);
84 cairo_stroke(cr);
85 }
86 } else {
87 draw(cr, C, Rect(bnd[X], Interval(py, y)));
88 }
89 prev_rts = rts;
90 py = y;
91 }
92}
93
94template <typename T>
95static T det(T a, T b, T c, T d) {
96 return a*d - b*c;
97}
98
99template <typename T>
100static T det(T M[2][2]) {
101 return M[0][0]*M[1][1] - M[1][0]*M[0][1];
102}
103
104template <typename T>
105static T det3(T M[3][3]) {
106 return ( M[0][0] * det(M[1][1], M[1][2],
107 M[2][1], M[2][2])
108 -M[1][0] * det(M[0][1], M[0][2],
109 M[2][1], M[2][2])
110 +M[2][0] * det(M[0][1], M[0][2],
111 M[1][1], M[1][2]));
112}
113
114double xAx_descr(xAx const & C) {
115 double mC[3][3] = {{C.c[0], (C.c[1])/2, (C.c[3])/2},
116 {(C.c[1])/2, C.c[2], (C.c[4])/2},
117 {(C.c[3])/2, (C.c[4])/2, C.c[5]}};
118
119 return det3(mC);
120}
121
122void draw_ratquad(cairo_t*cr, RatQuad rq, double tol=1e-1) {
123 CubicBezier cb = rq.toCubic();
124 // I tried using the nearest point to 0.5 for the error, but the improvement was negligible
125 if(L2(cb.pointAt(0.5) - rq.pointAt(0.5)) > tol) {
126 RatQuad a, b;
127 rq.split(a, b);
128 draw_ratquad(cr, a, tol);
129 draw_ratquad(cr, b, tol);
130 } else {
131 cairo_curve(cr, cb);
132 //draw_cross(cr, cb.pointAt(0));
133 //draw_cross(cr, cb.pointAt(1));
134 }
135}
136
137
138class Conic5: public Toy {
139 PointSetHandle path_handles;
140 PointHandle oncurve;
141 PointSetHandle cutting_plane;
142 std::vector<Slider> sliders;
143 RectHandle rh;
144
145 void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override {
146 cairo_set_source_rgba (cr, 0., 0., 0, 1);
147 cairo_set_line_width (cr, 1);
148
149 if(0) {
150 Path path;
151 path = Path(path_handles.pts[0]);
152 D2<SBasis> c = handles_to_sbasis(path_handles.pts.begin(), 2);
153 path.append(c);
154
155 cairo_save(cr);
156 cairo_path(cr, path);
157 cairo_set_source_rgba (cr, 0., 1., 0, 0.3);
158 cairo_set_line_width (cr, 3);
159 cairo_stroke(cr);
160 cairo_restore(cr);
161
162 //double w = exp(sliders[0].value());
163 }
164 Point A = path_handles.pts[0];
165 Point B = path_handles.pts[1];
166 Point C = path_handles.pts[2];
167
168 if(1) {
169 QuadraticBezier qb(A, B, C);
170 //double abt = qb.nearestTime(oncurve.pos);
171 //oncurve.pos = qb.pointAt(abt);
172
173 RatQuad rq = RatQuad::fromPointsTangents(A, B-A, oncurve.pos, C, B -C); //( A, B, C, w);
174
175 cairo_save(cr);
176 cairo_set_source_rgba (cr, 0., 0., 0, 1);
177 cairo_set_line_width (cr, 1);
178 draw_ratquad(cr, rq);
179 //cairo_d2_sb(cr, rq.hermite());
180 cairo_stroke(cr);
181 cairo_restore(cr);
182 }
183
184 if(0) {
185 RatQuad rq = RatQuad::circularArc(A, B, C);
186
187 cairo_save(cr);
188 cairo_set_source_rgba (cr, 0., 0., 0, 1);
189 cairo_set_line_width (cr, 1);
190 RatQuad a, b;
191 rq.split(a,b);
192 cairo_curve(cr, a.toCubic());
193 cairo_curve(cr, b.toCubic());
194 cairo_stroke(cr);
195 cairo_restore(cr);
196 }
197
198 Rect screen_rect(Interval(10, width-10), Interval(10, height-10));
199 Line cutLine(cutting_plane.pts[0], cutting_plane.pts[1]);
200 //double dist;
201 //Point norm = cutLine.normalAndDist(dist);
202
203 const unsigned N = 3;
204 xAx sources[N] = {
205 xAx::fromPoint(A)*(exp(-sliders[0].value())),
206 xAx::fromPoint(B)*(exp(-sliders[1].value())),
207 xAx::fromPoint(C)*(exp(-sliders[2].value()))
208 //xAx::fromLine(Line(A, oncurve.pos))
209 };
210 for(unsigned i = 0; i < N; i++) {
211 //*notify << sources[i] << "\n";
212 }
213 for(unsigned i = 0; i < N; i++) {
214 for(unsigned j = i+1; j < N; j++) {
215 xAx Q = sources[i]-sources[j];
216 *notify << Q << " is a " << Q.categorise() << "\n";
217 }
218 }
219 {
220 cairo_save(cr);
221 cairo_set_source_rgba(cr, 0, 0, 1, 0.5);
222
223 ::draw(cr, (sources[0]-sources[1]), screen_rect);
224 ::draw(cr, (sources[0]-sources[2]), screen_rect);
225 ::draw(cr, (sources[1]-sources[2]), screen_rect);
226 cairo_restore(cr);
227 }
228 {
229 string os;
230 for(unsigned i = 0; i < N; i++) {
231 for(unsigned j = i+1; j < N; j++) {
232 xAx Q = sources[i]-sources[j];
233 Interval iQ = Q.extrema(rh.pos);
234 if(iQ.contains(0)) {
235 os += stringify(iQ) + "\n";
236
237 Q.toCurve(rh.pos);
238 vector<Point> crs = Q.crossings(rh.pos);
239 for(auto & ei : crs) {
240 draw_cross(cr, ei);
241 }
242
243 }
244 }
245 }
246
247 draw_text(cr, rh.pos.midpoint(),
248 os);
249 }
250 if(1) {
251 xAx oxo=sources[0] - sources[2];
252 Timer tm;
253
255 tm.start();
256
257 std::vector<Point> intrs = intersect(oxo, sources[0] - sources[1]);
258 Timer::Time als_time = tm.lap();
259 *notify << "intersect time = " << als_time << std::endl;
260 for(auto & intr : intrs) {
261 cairo_save(cr);
262 cairo_set_source_rgb(cr, 1, 0,0);
263 draw_cross(cr, intr);
264 cairo_stroke(cr);
265 cairo_restore(cr);
266 }
267
268 std::optional<RatQuad> orq = oxo.toCurve(rh.pos);
269 if(orq) {
270 RatQuad rq = *orq;
271 draw_hull(cr, rq);
272 vector<SBasis> hrq = rq.homogeneous();
273 SBasis vertex_poly = (sources[0] - sources[1]).evaluate_at(hrq[0], hrq[1], hrq[2]);
274 //*notify << "\n0: " << hrq[0];
275 //*notify << "\n1: " << hrq[1];
276 //*notify << "\n2: " << hrq[2];
277 vector<double> rts = roots(vertex_poly);
278 //*notify << "\nvertex poly:" << vertex_poly << '\n';
279 for(unsigned i = 0; i < rts.size(); i++) {
280 draw_circ(cr, Point(rq.pointAt(rts[i])));
281 *notify << "\nrq" << i << ":" << rts[i];
282 }
283
284 cairo_save(cr);
285 cairo_set_source_rgb(cr, 1, 0, 0);
286 RatQuad a, b;
287 rq.split(a,b);
288 cairo_curve(cr, a.toCubic());
289 cairo_curve(cr, b.toCubic());
290 cairo_stroke(cr);
291 cairo_restore(cr);
292 }
293 }
294 if(0) {
295 RatQuad a, b;
296 //rq.split(a,b);
297 //cairo_move_to(cr, rq.toCubic().pointAt(0.5));
298 cairo_line_to(cr, a.P[2]);
299 cairo_stroke(cr);
300
301 cairo_curve(cr, a.toCubic());
302 cairo_curve(cr, b.toCubic());
303
304 }
305 cairo_stroke(cr);
306
307 //*notify << "w = " << w << "; lambda = " << rq.lambda() << "\n";
308 Toy::draw(cr, notify, width, height, save, timer_stream);
309 }
310
311public:
312 Conic5() {
313 handles.push_back(&path_handles);
314 handles.push_back(&rh);
315 rh.pos = Rect(Point(100,100), Point(200,200));
316 rh.show_center_handle = true;
317 handles.push_back(&oncurve);
318 for(int j = 0; j < 3; j++){
319 path_handles.push_back(uniform()*400, 100+ uniform()*300);
320 }
321 oncurve.pos = ((path_handles.pts[0]+path_handles.pts[1]+path_handles.pts[2])/3);
322 handles.push_back(&cutting_plane);
323 for(int j = 0; j < 2; j++){
324 cutting_plane.push_back(uniform()*400, 100+ uniform()*300);
325 }
326 sliders.emplace_back(0.0, 5.0, 0, 0.0, "a");
327 sliders.emplace_back(0.0, 5.0, 0, 0.0, "b");
328 sliders.emplace_back(0.0, 5.0, 0, 0.0, "c");
329 handles.push_back(&(sliders[0]));
330 handles.push_back(&(sliders[1]));
331 handles.push_back(&(sliders[2]));
332 sliders[0].geometry(Point(50, 20), 250);
333 sliders[1].geometry(Point(50, 50), 250);
334 sliders[2].geometry(Point(50, 80), 250);
335 }
336
337 void first_time(int /*argc*/, char**/* argv*/) override {
338
339 }
340};
341
342int main(int argc, char **argv) {
343 init(argc, argv, new Conic5());
344 return 0;
345}
346
347/*
348 Local Variables:
349 mode:c++
350 c-file-style:"stroustrup"
351 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
352 indent-tabs-mode:nil
353 fill-column:99
354 End:
355*/
356// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Defines the different types of exceptions that 2geom can throw.
Path - a sequence of contiguous curves.
Basic intersection routines.
int main()
Conversion between Bezier control points and SBasis curves.
Bezier curve with compile-time specified order.
Point pointAt(Coord t) const override
Evaluate the curve at a specified time value.
Adaptor that creates 2D functions from 1D ones.
Definition d2.h:55
constexpr bool contains(C val) const
Check whether the interval includes this number.
CPoint midpoint() const
Get the point in the geometric center of the rectangle.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
Range of real numbers that is never empty.
Definition interval.h:59
Infinite line on a plane.
Definition line.h:53
Sequence of contiguous curves, aka spline.
Definition path.h:353
void append(Curve *curve)
Add a new curve to the end of the path.
Definition path.h:750
Two-dimensional point that doubles as a vector.
Definition point.h:66
void split(RatQuad &a, RatQuad &b) const
Definition conicsec.cpp:175
static RatQuad circularArc(Point P0, Point P1, Point P2)
Definition conicsec.cpp:151
static RatQuad fromPointsTangents(Point P0, Point dP0, Point P, Point P2, Point dP2)
Definition conicsec.cpp:115
CubicBezier toCubic() const
Definition conicsec.cpp:156
Point pointAt(double t) const
Definition conicsec.cpp:167
Point P[3]
A curve of the form B02*A + B12*B*w + B22*C/(B02 + B12*w + B22) These curves can exactly represent a ...
Definition conicsec.h:68
std::vector< SBasis > homogeneous() const
Definition conicsec.cpp:197
Axis aligned, non-empty rectangle.
Definition rect.h:92
Polynomial in symmetric power basis.
Definition sbasis.h:70
std::string categorise() const
Definition conicsec.cpp:209
static xAx fromPoint(Point p)
Definition conicsec.cpp:409
double c[6]
Definition conicsec.h:101
std::vector< double > roots(Point d, Point o) const
Definition conicsec.cpp:565
Interval extrema(Rect r) const
Definition conicsec.cpp:648
std::optional< RatQuad > toCurve(Rect const &bnd) const
Definition conicsec.cpp:511
std::vector< Point > crossings(Rect r) const
Definition conicsec.cpp:497
Geom::Point pos
void push_back(double x, double y)
std::vector< Geom::Point > pts
Geom::Rect pos
bool show_center_handle
void ask_for_timeslice()
Ask the OS nicely for a big time slice.
void start()
void lap(long long &ns)
virtual void first_time(int, char **)
vector< Handle * > handles
virtual void save(FILE *f)
virtual void draw(cairo_t *cr, std::ostringstream *notify, int w, int h, bool save, std::ostringstream *timing_stream)
void draw_ratquad(cairo_t *cr, RatQuad rq, double tol=1e-1)
Definition conic-5.cpp:122
void draw_hull(cairo_t *cr, RatQuad rq)
Definition conic-5.cpp:54
void draw(cairo_t *cr, xAx C, Rect bnd)
Definition conic-5.cpp:63
Conic Section.
double c[8][4]
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Infinite straight line.
Various utility functions.
Definition affine.h:22
double xAx_descr(xAx const &C)
Definition conicsec.cpp:352
bool contains(Path const &p, Point const &i, bool evenodd=true)
static T det3(T M[3][3])
Definition conicsec.cpp:71
std::vector< double > roots(SBasis const &s)
D2< SBasis > handles_to_sbasis(T const &handles, unsigned order)
std::string stringify(T x)
Definition conicsec.cpp:92
SBasis L2(D2< SBasis > const &a, unsigned k)
Definition d2-sbasis.cpp:42
static double det(Point a, Point b)
Definition conicsec.cpp:56
std::vector< Point > intersect(const xAx &C1, const xAx &C2)
Definition conicsec.cpp:361
STL namespace.
Nearest time routines for D2<SBasis> and Piecewise<D2<SBasis>>
Comparator template.
void cairo_line_to(cairo_t *cr, Geom::Point p1)
void draw_cross(cairo_t *cr, Geom::Point h)
struct _cairo cairo_t
Definition path-cairo.h:16
void cairo_path(cairo_t *cr, Geom::Path const &p)
void cairo_curve(cairo_t *cr, Geom::Curve const &c)
void draw_circ(cairo_t *cr, Geom::Point h)
void cairo_move_to(cairo_t *cr, Geom::Point p1)
Path intersection.
PathVector - a sequence of subpaths.
two-dimensional geometric operators.
Conversion between SBasis and Bezier basis polynomials.
size_t N
parse SVG path specifications
double height
double width
void draw_text(cairo_t *cr, Geom::Point pos, const char *txt, bool bottom=false, const char *fontdesc="Sans")
double uniform()
void cairo_set_source_rgba(cairo_t *cr, colour c)
void init(int argc, char **argv, Toy *t, int width=600, int height=600)