Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
conic-6.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#include <2geom/conicsec.h>
27
28std::vector<Geom::RatQuad> xAx_to_RatQuads(Geom::xAx const &/*C*/, Geom::Rect const &/*bnd*/) {
29 // find points on boundary
30 // if there are exactly 0 points return
31 // if there are exactly 2 points fit ratquad and return
32 // if there are an odd number, split bnd on the point with the smallest dot(unit_vector(grad), rect_edge)
33 // sort into clockwise order ABCD
34 // compute corresponding tangents
35 // test boundary points against the line through A
36 // if all on one side
37 //
38 // if A,X and Y,Z
39 // ratquad from A,X and Y,Z
40 return std::vector<Geom::RatQuad>();
41}
42
43
44
45using namespace Geom;
46using namespace std;
47
48
49// File: convert.h
50#include <sstream>
51#include <stdexcept>
52
53class BadConversion : public std::runtime_error {
54public:
55 BadConversion(const std::string& s)
56 : std::runtime_error(s)
57 { }
58};
59
60template <typename T>
61inline std::string stringify(T x)
62{
63 std::ostringstream o;
64 if (!(o << x))
65 throw BadConversion("stringify(T)");
66 return o.str();
67}
68
69namespace Geom{
71};
72
74 cairo_move_to(cr, rq.P[0]);
75 cairo_line_to(cr, rq.P[1]);
76 cairo_line_to(cr, rq.P[2]);
77 cairo_stroke(cr);
78}
79
80
81
82void draw(cairo_t* cr, xAx C, Rect bnd) {
83 if(bnd[1].extent() < 5) return;
84 vector<double> prev_rts;
85 double py = bnd[Y].min();
86 for(int i = 0; i < 100; i++) {
87 double t = i/100.;
88 double y = bnd[Y].valueAt(t);
89 vector<double> rts = C.roots(Point(1, 0), Point(0, y));
90 int top = 0;
91 for(unsigned j = 0; j < rts.size(); j++) {
92 if(bnd[0].contains(rts[j])) {
93 rts[top] = rts[j];
94 top++;
95 }
96 }
97 rts.erase(rts.begin()+top, rts.end());
98
99 if(rts.size() == prev_rts.size()) {
100 for(unsigned j = 0; j < rts.size(); j++) {
101 cairo_move_to(cr, prev_rts[j], py);
102 cairo_line_to(cr, rts[j], y);
103 cairo_stroke(cr);
104 }
105/* } else if(prev_rts.size() == 1) {
106 for(unsigned j = 0; j < rts.size(); j++) {
107 cairo_move_to(cr, prev_rts[0], py);
108 cairo_line_to(cr, rts[j], y);
109 cairo_stroke(cr);
110 }
111 } else if(rts.size() == 1) {
112 for(unsigned j = 0; j < prev_rts.size(); j++) {
113 cairo_move_to(cr, prev_rts[j], py);
114 cairo_line_to(cr, rts[0], y);
115 cairo_stroke(cr);
116 }*/
117 } else {
118 draw(cr, C, Rect(bnd[0], Interval(py, y)));
119 /*for(unsigned j = 0; j < rts.size(); j++) {
120 cairo_move_to(cr, rts[j], y);
121 cairo_rel_line_to(cr, 1,1);
122 }*/
123 }
124 prev_rts = rts;
125 py = y;
126 }
127}
128
129template <typename T>
130static T det(T a, T b, T c, T d) {
131 return a*d - b*c;
132}
133
134template <typename T>
135static T det(T M[2][2]) {
136 return M[0][0]*M[1][1] - M[1][0]*M[0][1];
137}
138
139template <typename T>
140static T det3(T M[3][3]) {
141 return ( M[0][0] * det(M[1][1], M[1][2],
142 M[2][1], M[2][2])
143 -M[1][0] * det(M[0][1], M[0][2],
144 M[2][1], M[2][2])
145 +M[2][0] * det(M[0][1], M[0][2],
146 M[1][1], M[1][2]));
147}
148
149class Conic6: public Toy {
150 PointSetHandle C1H, C2H;
151 std::vector<Slider> sliders;
152 Point mouse_sampler;
153
154 void mouse_moved(Geom::Point const &pos, unsigned modifiers) override {
155 mouse_sampler = pos;
156 Toy::mouse_moved(pos, modifiers);
157 }
158
159 void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override {
160 cairo_set_source_rgba (cr, 0., 0., 0, 1);
161 cairo_set_line_width (cr, 1);
162 Rect screen_rect(Interval(10, width-10), Interval(10, height-10));
163
164 Geom::xAx C1 = xAx::fromPoints(C1H.pts);
165 ::draw(cr, C1, screen_rect);
166 *notify << C1;
167
168 Geom::xAx C2 = xAx::fromPoints(C2H.pts);
169 ::draw(cr, C2, screen_rect);
170 *notify << C2;
171
172
173 SBasis T(Linear(-1,1));
174 SBasis S(Linear(1,1));
175 SBasis C[3][3] = {{T*C1.c[0]+S*C2.c[0], (T*C1.c[1]+S*C2.c[1])/2, (T*C1.c[3]+S*C2.c[3])/2},
176 {(T*C1.c[1]+S*C2.c[1])/2, T*C1.c[2]+S*C2.c[2], (T*C1.c[4]+S*C2.c[4])/2},
177 {(T*C1.c[3]+S*C2.c[3])/2, (T*C1.c[4]+S*C2.c[4])/2, T*C1.c[5]+S*C2.c[5]}};
178
179 SBasis D = det3(C);
180 std::vector<double> rts = Geom::roots(D);
181 if(rts.empty()) {
182 T = Linear(1,1);
183 S = Linear(-1,1);
184 SBasis C[3][3] = {{T*C1.c[0]+S*C2.c[0], (T*C1.c[1]+S*C2.c[1])/2, (T*C1.c[3]+S*C2.c[3])/2},
185 {(T*C1.c[1]+S*C2.c[1])/2, T*C1.c[2]+S*C2.c[2], (T*C1.c[4]+S*C2.c[4])/2},
186 {(T*C1.c[3]+S*C2.c[3])/2, (T*C1.c[4]+S*C2.c[4])/2, T*C1.c[5]+S*C2.c[5]}};
187
188 D = det3(C);
189 rts = Geom::roots(D);
190 }
191 // at this point we have a T and S and perhaps some roots that represent our degenerate conic
192 // Let's just pick one randomly (can we do better?)
193 //for(unsigned i = 0; i < rts.size(); i++) {
194 if(!rts.empty()) {
195 cairo_save(cr);
196
197 unsigned i = 0;
198 double t = T.valueAt(rts[i]);
199 double s = S.valueAt(rts[i]);
200 *notify << t << "; " << s << std::endl;
201 /*double C0[3][3] = {{t*C1.c[0]+s*C2.c[0], (t*C1.c[1]+s*C2.c[1])/2, (t*C1.c[3]+s*C2.c[3])/2},
202 {(t*C1.c[1]+s*C2.c[1])/2, t*C1.c[2]+s*C2.c[2], (t*C1.c[4]+s*C2.c[4])/2},
203 {(t*C1.c[3]+s*C2.c[3])/2, (t*C1.c[4]+s*C2.c[4])/2, t*C1.c[5]+s*C2.c[5]}};*/
204 xAx xC0 = C1*t + C2*s;
205 //::draw(cr, xC0, screen_rect); // degen
206
207 std::optional<Point> oB0 = xC0.bottom();
208
209 Point B0 = *oB0;
210 //*notify << B0 << " = " << C1.gradient(B0);
211 draw_circ(cr, B0);
212
213 Point n0, n1;
214 // Are these just the eigenvectors of A11?
215 if(fabs(xC0.c[0]) > fabs(xC0.c[2])) {
216 double b = 0.5*xC0.c[1]/xC0.c[0];
217 double c = xC0.c[2]/xC0.c[0];
218 double d = std::sqrt(b*b-c);
219 n0 = Point(1, b+d);
220 n1 = Point(1, b-d);
221 } else {
222
223 double b = 0.5*xC0.c[1]/xC0.c[2];
224 double c = xC0.c[0]/xC0.c[2];
225 double d = std::sqrt(b*b-c);
226 n0 = Point(b+d, 1);
227 n1 = Point(b-d, 1);
228 }
229 cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
230
232 draw_line(cr, L0, screen_rect);
234 draw_line(cr, L1, screen_rect);
235
236 cairo_set_source_rgb(cr, 1, 0., 0.);
237 rts = C1.roots(L0);
238 for(double rt : rts) {
239 Point P = L0.pointAt(rt);
240 draw_cross(cr, P);
241 *notify << C1.valueAt(P) << "; " << C2.valueAt(P) << "\n";
242 }
243 rts = C1.roots(L1);
244 for(double rt : rts) {
245 Point P = L1.pointAt(rt);
246 draw_cross(cr, P);
247 *notify << C1.valueAt(P) << "; "<< C2.valueAt(P) << "\n";
248 }
249 cairo_stroke(cr);
250 cairo_restore(cr);
251 }
252
253 ::draw(cr, C1*sliders[0].value() + C2*sliders[1].value(), screen_rect);
254
255 std::vector<Point> res = intersect(C1, C2);
256 for(auto & re : res) {
257 draw_circ(cr, re);
258 }
259
260 cairo_stroke(cr);
261
262 //*notify << "w = " << w << "; lambda = " << rq.lambda() << "\n";
263 Toy::draw(cr, notify, width, height, save, timer_stream);
264 }
265
266public:
267 Conic6() {
268 for(int j = 0; j < 5; j++){
269 C1H.push_back(uniform()*400, 100+ uniform()*300);
270 C2H.push_back(uniform()*400, 100+ uniform()*300);
271 }
272 handles.push_back(&C1H);
273 handles.push_back(&C2H);
274 sliders.emplace_back(-1.0, 1.0, 0, 0.0, "a");
275 sliders.emplace_back(-1.0, 1.0, 0, 0.0, "b");
276 sliders.emplace_back(0.0, 5.0, 0, 0.0, "c");
277 handles.push_back(&(sliders[0]));
278 handles.push_back(&(sliders[1]));
279 handles.push_back(&(sliders[2]));
280 sliders[0].geometry(Point(50, 20), 250);
281 sliders[1].geometry(Point(50, 50), 250);
282 sliders[2].geometry(Point(50, 80), 250);
283 }
284
285 void first_time(int /*argc*/, char**/* argv*/) override {
286
287 }
288};
289
290int main(int argc, char **argv) {
291 init(argc, argv, new Conic6());
292 return 0;
293}
294
295/*
296 Local Variables:
297 mode:c++
298 c-file-style:"stroustrup"
299 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
300 indent-tabs-mode:nil
301 fill-column:99
302 End:
303*/
304// 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.
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
static Line from_origin_and_vector(Point const &o, Point const &v)
Create a line from origin and unit vector.
Definition line.h:114
Point pointAt(Coord t) const
Definition line.h:231
Function that interpolates linearly between two values.
Definition linear.h:55
Two-dimensional point that doubles as a vector.
Definition point.h:66
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
Axis aligned, non-empty rectangle.
Definition rect.h:92
Polynomial in symmetric power basis.
Definition sbasis.h:70
static xAx fromPoints(std::vector< Point > const &pts)
Definition conicsec.cpp:428
double c[6]
Definition conicsec.h:101
std::vector< double > roots(Point d, Point o) const
Definition conicsec.cpp:565
double valueAt(Point P) const
Definition conicsec.cpp:450
std::optional< Point > bottom() const
Definition conicsec.cpp:640
void push_back(double x, double y)
std::vector< Geom::Point > pts
virtual void first_time(int, char **)
virtual void mouse_moved(Geom::Point const &pos, unsigned modifiers)
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_hull(cairo_t *cr, RatQuad rq)
Definition conic-6.cpp:73
std::vector< Geom::RatQuad > xAx_to_RatQuads(Geom::xAx const &, Geom::Rect const &)
Definition conic-6.cpp:28
void draw(cairo_t *cr, xAx C, Rect bnd)
Definition conic-6.cpp:82
Conic Section.
double c[8][4]
@ Y
Definition coord.h:48
Infinite straight line.
Various utility functions.
Definition affine.h:22
Coord L1(Point const &p)
xAx degen
Definition conic-6.cpp:70
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)
std::string stringify(T x)
Definition conicsec.cpp:92
static double det(Point a, Point b)
Definition conicsec.cpp:56
D2< T > rot90(D2< T > const &a)
Definition d2.h:397
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 draw_circ(cairo_t *cr, Geom::Point h)
void cairo_move_to(cairo_t *cr, Geom::Point p1)
void draw_line(cairo_t *cr, const Geom::Line &l, const Geom::Rect &r)
Path intersection.
PathVector - a sequence of subpaths.
unsigned n1
two-dimensional geometric operators.
Conversion between SBasis and Bezier basis polynomials.
parse SVG path specifications
double height
double width
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)