Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
metro.cpp
Go to the documentation of this file.
1
7#include <cstdio>
8#include <cstring>
9#include <cstdlib>
10#include <cmath>
11
12#include <gtk/gtk.h>
13#include <cassert>
14#include <algorithm>
15#include <sstream>
16#include <iostream>
17#include <fstream>
18#include <vector>
19#include <string>
20#include <map>
21#include <cairo-pdf.h>
22#include <2geom/point.h>
23#include <2geom/geom.h>
25
26using std::string;
27using std::vector;
28using std::pair;
29using std::make_pair;
30using std::ifstream;
31using std::map;
32using std::cout;
33using std::endl;
34using namespace Geom;
35
36vector<vector<Point> > paths;
37
38class sufficient_stats{
39public:
40 double Sx, Sy, Sxx, Syy, Sxy;
41 double n;
42
43 sufficient_stats() : Sx(0), Sy(0), Sxx(0), Syy(0), Sxy(0), n(0) {}
44 void
45 operator+=(Point p) {
46 Sx += p[0];
47 Sy += p[1];
48 Sxx += p[0]*p[0];
49 Syy += p[1]*p[1];
50 Sxy += p[0]*p[1];
51 n += 1.0;
52 }
53 void
54 operator-=(Point p) {
55 Sx -= p[0];
56 Sy -= p[1];
57 Sxx -= p[0]*p[0];
58 Syy -= p[1]*p[1];
59 Sxy -= p[0]*p[1];
60 n -= 1.0;
61 }
62 /*** What is the best regression we can do? . */
63 Point best_normal() {
64 return rot90(unit_vector(Point(n*Sxx - Sx*Sx,
65 n*Sxy - Sx*Sy)));
66 }
67 /*** Compute the best line for the points, given normal. */
68 double best_line(Point normal, const double dist,
69 double & mean) {
70 mean = (normal[0]*Sx + normal[1]*Sy);
71 return normal[0]*normal[0]*Sxx
72 + normal[1]*normal[1]*Syy
73 + 2*normal[0]*normal[1]*Sxy
74 - 2*dist*mean + n*dist*dist;
75 }
76 /*** Returns the index to the angle in angles that has the line of best fit
77 * passing through mean */
78 unsigned best_schematised_line(vector<Point>& angles, Point p,
79 double & /*mean*/, double & cost) {
80 cost = DBL_MAX;
81 unsigned bestAngle = 0;
82 for(unsigned i=0;i<angles.size();i++) {
83 Point n = unit_vector(rot90(angles[i]));
84 double dist = dot(n, p);
85 double mean;
86 double bl = best_line(n, dist, mean);
87 if(bl < cost) {
88 cost = bl;
89 bestAngle = i;
90 }
91 }
92 return bestAngle;
93 }
94 /*** Compute the best line for the points, given normal. */
95 double best_angled_line(Point normal,
96 double & mean) {
97 mean = (normal[0]*Sx + normal[1]*Sy);
98 double dist = mean/n;
99 return normal[0]*normal[0]*Sxx
100 + normal[1]*normal[1]*Syy
101 + 2*normal[0]*normal[1]*Sxy
102 - 2*dist*mean + n*dist*dist;
103 }
104};
105
106sufficient_stats
107operator+(sufficient_stats const & a, sufficient_stats const &b) {
108 sufficient_stats ss;
109 ss.Sx = a.Sx + b.Sx;
110 ss.Sy = a.Sy + b.Sy;
111 ss.Sxx = a.Sxx + b.Sxx;
112 ss.Sxy = a.Sxy + b.Sxy;
113 ss.Syy = a.Syy + b.Syy;
114 ss.n = a.n + b.n;
115 return ss;
116}
117
118sufficient_stats
119operator-(sufficient_stats const & a, sufficient_stats const &b) {
120 sufficient_stats ss;
121 ss.Sx = a.Sx - b.Sx;
122 ss.Sy = a.Sy - b.Sy;
123 ss.Sxx = a.Sxx - b.Sxx;
124 ss.Sxy = a.Sxy - b.Sxy;
125 ss.Syy = a.Syy - b.Syy;
126 ss.n = a.n - b.n;
127 return ss;
128}
129
130inline std::ostream &operator<< (std::ostream &out_file, const sufficient_stats &s) {
131 out_file << "Sx: " << s.Sx
132 << "Sy: " << s.Sy
133 << "Sxx: " << s.Sxx
134 << "Sxy: " << s.Sxy
135 << "Syy: " << s.Syy
136 << "n: " << s.n;
137 return out_file;
138}
139
140
141
142class fit{
143public:
144 vector<Point> input;
145 vector<Point> solution;
146
147 vector<pair<Point,Point> > lines;
148 vector<int> thickness;
149
150 void
151 draw(cairo_t* cr) {
152 /*
153 if(solution.size() > 1) {
154 //cairo_set_line_width (cr, 1);
155 cairo_move_to(cr, solution[0]);
156 for(unsigned i = 1; i < solution.size(); i++) {
157 cairo_line_to(cr, solution[i]);
158 }
159 }
160 */
161 //cairo_stroke(cr);
162 for(unsigned i = 0;i<lines.size();i++) {
163 if(thickness.size()>i) {
164 cairo_set_line_width (cr, thickness[i]);
165 }
166 cairo_move_to(cr, lines[i].first);
167 cairo_line_to(cr, lines[i].second);
168 cairo_stroke(cr);
169 }
170 }
171
172 void endpoints() {
173 solution.push_back(input[0]);
174 solution.push_back(input.back());
175 }
176
177 void arbitrary();
178 void linear_reg();
179
180 // sufficient stats from start to each point
181 vector<sufficient_stats> ac_ss;
182
183 /*** Compute the least squares error for a line between two points on the line. */
184 double measure(unsigned from, unsigned to, double & mean) {
185 sufficient_stats ss = ac_ss[to+1] - ac_ss[from];
186
187 Point n = unit_vector(rot90(input[to] - input[from]));
188 double dist = dot(n, input[from]);
189 return ss.best_line(n, dist, mean);
190 }
191
192 /*** Compute the best line for the points, given normal. */
193 double best_angled_line(unsigned from, unsigned to,
194 Point n,
195 double & mean) {
196 sufficient_stats ss = ac_ss[to+1] - ac_ss[from];
197 return ss.best_angled_line(n, mean);
198 }
199
200 double simple_measure(unsigned from, unsigned to, double & mean) {
201 Point n = unit_vector(rot90(input[to] - input[from]));
202 double dist = dot(n, input[from]); // distance from origin
203 double error = 0;
204 mean = 0;
205 for(unsigned l = from; l <= to; l++) {
206 double d = dot(input[l], n) - dist;
207 mean += dot(input[l], n);
208 error += d*d;
209 }
210 return error;
211 }
212
213 void simple_dp();
214 void C_simple_dp();
215
216 void C_endpoint();
217
218 vector<Geom::Point> angles;
219 fit(vector<Point> const & in)
220 :input(in) {
221 /*
222 Geom::Point as[] = {Point(0,1), Point(1,0), Point(1,1), Point(1,-1)};
223 for(unsigned c = 0; c < 4; c++) {
224 angles.push_back(unit_vector(as[c]));
225 }
226 */
227 sufficient_stats ss;
228 ss.Sx = ss.Sy = ss.Sxx = ss.Sxy = ss.Syy = 0;
229 ac_ss.push_back(ss);
230 for(auto & l : input) {
231 ss += l;
232 ac_ss.push_back(ss);
233 }
234 }
235
236 class block{
237 public:
238 unsigned next;
239 unsigned angle;
240 sufficient_stats ss;
241 double cost;
242 };
243 vector<block> blocks;
244 void test();
245 void merging_version();
246 void schematised_merging(unsigned number_of_directions);
247
248 double get_block_line(block& b, Point& d, Point& n, Point& c) {
249 n = unit_vector(rot90(d));
250 c = Point(b.ss.Sx/b.ss.n,b.ss.Sy/b.ss.n);
251 return 0;
252 }
253};
254
255class build_bounds{
256public:
257 int total_n;
258 Point starting[2];
259 Rect combined;
260 void add_point(Point const &P) {
261 if(total_n < 2) {
262 starting[total_n] = P;
263 total_n += 1;
264 if(total_n == 2)
265 combined = Rect(starting[0], starting[1]);
266 } else {
267 combined.expandTo(P);
268 total_n += 1;
269 }
270 }
271 OptRect result() const {
272 if(total_n > 1)
273 return combined;
274 return OptRect();
275 }
276 build_bounds() : total_n(0) {}
277};
278
283Point map_point(Point p, Rect src, Point topleft, Point bottomright) {
284 p -= src.min();
285 p[0] /= src[0].extent();
286 p[1] /= src[1].extent();
287 //cout << p << endl;
288 return Point(topleft[0]*(1-p[0]) + bottomright[0]*p[0],
289 topleft[1]*(1-p[1]) + bottomright[1]*p[1]);
290}
291
292void parse_data(vector<vector<Point> >& paths,
293 string location_file_name,
294 string path_file_name) {
295 ifstream location_file(location_file_name.c_str()),
296 path_file(path_file_name.c_str());
297 string id,sx,sy;
298 map<string,Point> idlookup;
299 build_bounds bld_bounds;
300 while (getline(location_file,id,','))
301 {
302 getline(location_file,sx,',');
303 getline(location_file,sy,'\n');
304 char *e;
305 // negative for coordinate system
306 Point p(strtod(sx.c_str(),&e), strtod(sy.c_str(),&e));
307 //cout << id << p << endl;
308 idlookup[id] = p;
309 }
310
311
312 string l;
313 while (getline(path_file,l,'\n')) {
314 vector<Point> ps;
315 if(l.size() < 2) continue; // skip blank lines
316 if(l.find(":",0)!=string::npos) continue; // skip labels
317 string::size_type p=0,q;
318 while((q=l.find(",",p))!=string::npos || (p < l.size() && (q = l.size()))) {
319 id = l.substr(p,q-p);
320 //cout << id << endl;
321 Point pt = 2*idlookup[id];
322 //cout << pt << endl;
323 bld_bounds.add_point(pt);
324 ps.push_back(pt);
325 p=q+1;
326 }
327 paths.push_back(ps);
328 //cout << "*******************************************" << endl;
329 }
330 Rect bounds = *bld_bounds.result();
331 //cout << bounds.min() << " - " << bounds.max() << endl;
332 for(auto & path : paths) {
333 for(auto & j : path) {
334 j = map_point(j, bounds,
335 Point(0,512), Point(512*bounds[0].extent()/bounds[1].extent(),0));
336 }
337 }
338 /*
339 for(map<string,Point>::iterator it = idlookup.begin();
340 it != idlookup.end(); it++) {
341 (*it).second = map_point((*it).second, bounds,
342 Point(0,0), Point(100,100));
343 //Point(0, 512), Point(512,0));
344 cout << (*it).first << ":" << (*it).second << endl;
345 }*/
346 /*
347 unsigned biggest = 0, biggest_i;
348 for(unsigned i=0;i<paths.size();i++) {
349 vector<Point> ps=paths[i];
350 if(ps.size()>biggest) {
351 biggest_i=i;
352 biggest = ps.size();
353 }
354 for(unsigned j=0;j<ps.size();j++) {
355 double x=ps[j][0], y=ps[j][1];
356 cout << "(" << x << "," << y << ")" << ",";
357 }
358 cout << endl;
359 }
360 */
361}
362
363void extremePoints(vector<Point> const & pts, Point const & dir,
364 Point & min, Point & max) {
365 double minProj = DBL_MAX, maxProj = -DBL_MAX;
366 for(auto pt : pts) {
367 double p = dot(pt,dir);
368 if(p < minProj) {
369 minProj = p;
370 min = pt;
371 }
372 if(p > maxProj) {
373 maxProj = p;
374 max = pt;
375 }
376 }
377}
378
379void fit::test() {
380 sufficient_stats ss;
381 const unsigned N = input.size();
382 for(unsigned i = 0; i < N; i++) {
383 ss += input[i];
384 }
385 double best_bl = DBL_MAX;
386 unsigned best = 0;
387 for(unsigned i=0;i<angles.size();i++) {
388 Point n = unit_vector(rot90(angles[i]));
389 double dist = dot(n, input[0]);
390 double mean;
391 double bl = ss.best_line(n, dist, mean);
392 if(bl < best_bl) {
393 best = i;
394 best_bl = bl;
395 }
396 mean/=N;
397 Point d = angles[i];
398 Point a = mean*n;
399 Point min, max;
400 extremePoints(input,d,min,max);
401 Point b = dot(min,d)*d;
402 Point c = dot(max,d)*d;
403 Point start = a+b;
404 Point end = a+c;
405 lines.emplace_back(start,end);
406 thickness.push_back(1);
407 }
408 thickness[best] = 4;
409}
410
411void fit::schematised_merging(unsigned number_of_directions) {
412 const double link_cost = 0;
413 const unsigned N = input.size()-1;
414 blocks.resize(N);
415 for(unsigned i = 0; i<number_of_directions ; i++) {
416 double t = M_PI*i/float(number_of_directions);
417 angles.emplace_back(cos(t),sin(t));
418 }
419 // pairs
420 for(unsigned i = 0; i < N; i++) {
421 block b;
422 sufficient_stats ss;
423 ss += input[i];
424 ss += input[i+1];
425 b.ss = ss;
426 double mean, newcost;
427 b.angle = ss.best_schematised_line(angles, input[i], mean, newcost);
428 b.cost = link_cost + newcost;
429 b.next = i+1;
430 blocks[i] = b;
431 //std::cout << ss
432 //<< std::endl;
433 }
434
435 // merge(a,b)
436 while(N>1)
437 {
438 block best_block;
439 unsigned best_idx = 0;
440 double best = 0;
441 unsigned beg = 0;
442 unsigned middle = blocks[beg].next;
443 unsigned end = blocks[middle].next;
444 while(middle < N) {
445 sufficient_stats ss = blocks[beg].ss + blocks[middle].ss;
446 //ss -= input[middle];
447 double mean, newcost;
448 unsigned bestAngle = ss.best_schematised_line(angles, input[beg], mean, newcost);
449 double deltaCost = -link_cost - blocks[beg].cost - blocks[middle].cost
450 + newcost;
451 /*std::cout << beg << ", "
452 << middle << ", "
453 << end << ", "
454 << deltaCost <<"; "
455 << newcost <<"; "
456 << mean << ": "
457 << ss
458 << std::endl;*/
459 //if(deltaCost < best) {
460 if(blocks[beg].angle==blocks[middle].angle) {
461 best = deltaCost;
462 best = -1;
463 best_idx = beg;
464 best_block.ss = ss;
465 best_block.cost = newcost;
466 best_block.next = end;
467 best_block.angle = bestAngle;
468 }
469 beg = middle;
470 middle = end;
471 end = blocks[end].next;
472 }
473 if(best < 0)
474 blocks[best_idx] = best_block;
475 else // no improvement possible
476 break;
477 }
478 {
479 solution.resize(0); // empty list
480 unsigned beg = 0;
481 unsigned prev = 0;
482 while(beg < N) {
483 block b = blocks[beg];
484 {
485 Point n, c;
486 Point n1, c1;
487 Point d = angles[b.angle];
488 get_block_line(b,d,n,c);
489 Point start = c, end = c+10*angles[b.angle];
491 if(beg==0) {
492 //start = intersection of b.line and
493 // line through input[0] orthogonal to b.line
495 Line::from_normal_distance(d, dot(d,input[0])));
496 assert(c);
497 start = ln.pointAt(c->ta);
498 //line_intersection(n, dot(c,n), d, dot(d,input[0]), start);
499 } else {
500 //start = intersection of b.line and blocks[prev].line
501 block p = blocks[prev];
502 if(b.angle!=p.angle) {
503 get_block_line(p,angles[p.angle],n1,c1);
504 //line_intersection(n, dot(c,n), n1, dot(c1,n1), start);
507 assert(c);
508 start = ln.pointAt(c->ta);
509 }
510 }
511
512 if (b.next < N) {
513 //end = intersection of b.line and blocks[b.next].line
514 block next = blocks[b.next];
515 if(b.angle!=next.angle) {
516 get_block_line(next,angles[next.angle],n1,c1);
517 //line_intersection(n, dot(c,n), n1, dot(c1,n1), end);
520 assert(c);
521 end = ln.pointAt(c->ta);
522 }
523 } else {
524 //end = intersection of b.line and
525 // line through input[N-1] orthogonal to b.line
526 //line_intersection(n, dot(c,n), d, dot(d,input[N]), end);
528 Line::from_normal_distance(d, dot(d,input[N])));
529 assert(c);
530 end = ln.pointAt(c->ta);
531 }
532 lines.emplace_back(start,end);
533 }
534 prev = beg;
535 beg = b.next;
536 }
537 }
538}
539void fit::merging_version() {
540 const double link_cost = 100;
541 const unsigned N = input.size();
542 blocks.resize(N);
543 // pairs
544 for(unsigned i = 0; i < N; i++) {
545 block b;
546 sufficient_stats ss;
547 ss.Sx = ss.Sy = ss.Sxx = ss.Sxy = ss.Syy = 0;
548 ss.n = 0;
549 ss += input[i];
550 ss += input[i+1];
551 b.ss = ss;
552 b.cost = link_cost;
553 b.next = i+1;
554 blocks[i] = b;
555 //std::cout << ss
556 //<< std::endl;
557 }
558
559 // merge(a,b)
560 while(1)
561 {
562 block best_block;
563 unsigned best_idx = 0;
564 double best = 0;
565 unsigned beg = 0;
566 unsigned middle = blocks[beg].next;
567 unsigned end = blocks[middle].next;
568 while(end != N) {
569 sufficient_stats ss = blocks[beg].ss + blocks[middle].ss;
570 ss -= input[middle];
571 double mean;
572 Point normal = unit_vector(rot90(input[end] - input[beg]));
573 double dist = dot(normal, input[beg]);
574 double newcost = ss.best_line(normal, dist, mean);
575 double deltaCost = -link_cost - blocks[beg].cost - blocks[middle].cost
576 + newcost;
577 /*std::cout << beg << ", "
578 << middle << ", "
579 << end << ", "
580 << deltaCost <<"; "
581 << newcost <<"; "
582 << mean << ": "
583 << ss
584 << std::endl;*/
585 if(deltaCost < best) {
586 best = deltaCost;
587 best_idx = beg;
588 best_block.ss = ss;
589 best_block.cost = newcost;
590 best_block.next = end;
591 }
592 beg = middle;
593 middle = end;
594 end = blocks[end].next;
595 }
596 if(best < 0)
597 blocks[best_idx] = best_block;
598 else // no improvement possible
599 break;
600 }
601 {
602 solution.resize(0); // empty list
603 unsigned beg = 0;
604 while(beg != N) {
605 solution.push_back(input[beg]);
606 beg = blocks[beg].next;
607 }
608 }
609}
610
611
612void fit::arbitrary() {
613 /*solution.resize(input.size());
614 copy(input.begin(), input.end(), solution.begin());*/
615 // normals
616
617 double best_error = INFINITY;
618 double best_mean = 0;
619 unsigned best_angle = 0;
620 for(unsigned i = 0; i < angles.size(); i++) {
621 Point angle = angles[i];
622 double mean = 0;
623 double error = 0;
624 for(unsigned l = 0; l < input.size(); l++) {
625 mean += dot(input[i], angle);
626 }
627 mean /= input.size();
628 for(unsigned l = 0; l < input.size(); l++) {
629 double d = dot(input[i], angle) - mean;
630 error += d*d;
631 }
632 if(error < best_error) {
633 best_mean = mean;
634 best_error = error;
635 best_angle = i;
636 }
637 }
638 Point angle = angles[best_angle];
639 solution.push_back(angle*best_mean + dot(input[0], rot90(angle))*rot90(angle));
640 solution.push_back(angle*best_mean + dot(input.back(), rot90(angle))*rot90(angle));
641}
642
643class reg_line{
644public:
645 Point parallel, centre, normal;
646 double Sr, Srr;
647 unsigned n;
648};
649
650template<class T>
651reg_line
652line_best_fit(T b, T e) {
653 double Sx = 0,
654 Sy = 0,
655 Sxx = 0,
656 Syy = 0,
657 Sxy = 0;
658 unsigned n = e - b;
659 reg_line rl;
660 rl.n = n;
661 for(T p = b; p != e; p++) {
662 Sx += (*p)[0];
663 Sy += (*p)[1];
664 Sxx += (*p)[0]*(*p)[0];
665 Syy += (*p)[1]*(*p)[1];
666 Sxy += (*p)[0]*(*p)[1];
667 }
668
669 rl.parallel = unit_vector(Point(n*Sxx - Sx*Sx,
670 n*Sxy - Sx*Sy));
671 rl.normal = rot90(rl.parallel);
672 rl.centre = Point(Sx/n, Sy/n);
673 rl.Sr = rl.Srr = 0;
674 for(T p = b; p != e; p++) {
675 double r = dot(rl.parallel, (*p) - rl.centre);
676 rl.Sr += fabs(r);
677 rl.Srr += r*r;
678 }
679 return rl;
680}
681
682void fit::linear_reg() {
683 reg_line rl = line_best_fit(input.begin(),
684 input.end());
685 solution.push_back(rl.centre + dot(rl.parallel, input[0] - rl.centre)*rl.parallel);
686 solution.push_back(rl.centre + dot(rl.parallel, input.back() - rl.centre)*rl.parallel);
687}
688
689void fit::simple_dp() {
690 const unsigned N = input.size();
691 vector<unsigned> prev(N);
692 vector<double> penalty(N);
693 const double bend_pen = 100;
694
695 for(unsigned i = 1; i < input.size(); i++) {
696 double mean;
697 double best = measure(0, i, mean);
698 unsigned best_prev = 0;
699 for(unsigned j = 1; j < i; j++) {
700 double err = penalty[j] + bend_pen + measure(j, i, mean);
701 if(err < best) {
702 best = err;
703 best_prev = j;
704 }
705 }
706 penalty[i] = best;
707 prev[i] = best_prev;
708 }
709
710 unsigned i = prev.size()-1;
711 while(i > 0) {
712 solution.push_back(input[i]);
713 i = prev[i];
714 }
715 solution.push_back(input[i]);
716 reverse(solution.begin(), solution.end());
717}
718
719void fit::C_endpoint() {
720 const unsigned N = input.size();
721
722 double best_mean;
723 double best = best_angled_line(0, N-1, angles[0], best_mean);
724 unsigned best_dir = 0;
725 for(unsigned c = 1; c < angles.size(); c++) {
726 double m;
727 double err = best_angled_line(0, N-1, angles[c], m);
728 if(err < best) {
729 best = err;
730 best_mean = m;
731 best_dir = c;
732 }
733
734 }
735 Point dir = angles[best_dir];
736 Point dirT = rot90(dir);
737 Point centre = dir*best_mean/N;
738
739 solution.push_back(centre + dot(dirT, input[0] - centre)*dirT);
740 solution.push_back(centre + dot(dirT, input.back() - centre)*dirT);
741}
742
743void fit::C_simple_dp() {
744 const unsigned N = input.size();
745
746 vector<int> prev(N);
747 vector<double> penalty(N);
748 vector<unsigned> dir(N);
749 vector<double> mean(N);
750 const double bend_pen = 0;
751
752 for(unsigned i = 1; i < input.size(); i++) {
753 double best_mean;
754 double best = best_angled_line(0, i, angles[0], best_mean);
755 unsigned best_prev = 0;
756 unsigned best_dir = 0;
757 for(unsigned c = 1; c < angles.size(); c++) {
758 double m;
759 double err = best_angled_line(0, i, angles[c], m);
760 if(err < best) {
761 best = err;
762 best_mean = m;
763 best_dir = c;
764 best_prev = 0;
765 }
766
767 }
768 for(unsigned j = 1; j < i; j++) {
769 for(unsigned c = 0; c < angles.size(); c++) {
770 double m;
771 if(c == dir[j])
772 continue;
773 double err = penalty[j] + bend_pen +
774 best_angled_line(j, i, angles[c], m);
775 if(err < best) {
776 best = err;
777 best_mean = m;
778 best_dir = c;
779 best_prev = j;
780 }
781
782 }
783 }
784 penalty[i] = best;
785 prev[i] = best_prev;
786 dir[i] = best_dir;
787 mean[i] = best_mean;
788 }
789
790 prev[0] = -1;
791 unsigned i = prev.size()-1;
792 unsigned pi = i;
793 while(i > 0) {
794 Point bdir = angles[dir[i]];
795 Point bdirT = rot90(bdir);
796 Point centre = bdir*mean[i]/N;
797 solution.push_back(centre + dot(bdirT, input[i] - centre)*bdirT);
798 solution.push_back(centre + dot(bdirT, input[pi] - centre)*bdirT);
799 pi = i;
800 i = prev[i];
801 }
802 /*Point a = angles[dir[i]];
803 Point aT = rot90(a);
804 solution.push_back(a*mean[i] +
805 dot(input[i], aT)*aT);*/
806 reverse(solution.begin(), solution.end());
807}
808
809
810
811
812
813
814class MetroMap: public Toy {
815public:
816 vector<PointSetHandle> metro_lines;
817 PointHandle directions;
818
819 bool should_draw_numbers() override { return false; }
820
821 void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override {
822 double slider_margin = 20;
823 double slider_top = 20;
824 double slider_bot = 200;
825 directions.pos[X] = slider_margin;
826 if (directions.pos[Y]<slider_top) directions.pos[Y] = slider_top;
827 if (directions.pos[Y]>slider_bot) directions.pos[Y] = slider_bot;
828
829 unsigned num_directions = 2 + 15*(slider_bot-directions.pos[Y])/(slider_bot-slider_top);
830
831 cairo_move_to(cr,Geom::Point(slider_margin,slider_bot));
832 cairo_line_to(cr,Geom::Point(slider_margin,slider_top));
833 cairo_set_line_width(cr,.5);
834 cairo_set_source_rgba (cr, 0., 0.3, 0., 1.);
835 cairo_stroke(cr);
836
837 cairo_set_source_rgba (cr, 0., 0.5, 0, 1);
838 cairo_set_line_width (cr, 1);
839 cairo_set_source_rgba (cr, 0., 0., 0, 0.8);
840 cairo_set_line_width (cr, 1);
841
842 unsigned N= paths.size();
843 for(unsigned i=0;i<N;i++) {
844 double R,G,B;
845 convertHSVtoRGB(360.*double(i)/double(N),1,0.75,R,G,B);
846 metro_lines[i].rgb[0] = R;
847 metro_lines[i].rgb[1] = G;
848 metro_lines[i].rgb[2] = B;
849 cairo_set_source_rgba (cr, R, G, B, 0.8);
850 fit f(metro_lines[i].pts);
851 f.schematised_merging(num_directions);
852 f.draw(cr);
853 cairo_stroke(cr);
854 }
855 cairo_set_source_rgba (cr, 0., 0., 0, 1);
856 {
857 PangoLayout* layout = pango_cairo_create_layout (cr);
858 pango_layout_set_text(layout,
859 notify->str().c_str(), -1);
860
861 PangoFontDescription *font_desc = pango_font_description_new();
862 pango_font_description_set_family(font_desc, "Sans");
863 const unsigned size_px = 10;
864 pango_font_description_set_absolute_size(font_desc, size_px * 1024.0);
865 pango_layout_set_font_description(layout, font_desc);
866 PangoRectangle logical_extent;
867 pango_layout_get_pixel_extents(layout,
868 NULL,
869 &logical_extent);
870 cairo_move_to(cr, 0, height-logical_extent.height);
871 pango_cairo_show_layout(cr, layout);
872 }
873 Toy::draw(cr, notify, width, height, save,timer_stream);
874 }
875
876 void first_time(int argc, char** argv) override {
877 string location_file_name("data/london-locations.csv");
878 string path_file_name("data/london.txt");
879 if(argc > 2) {
880 location_file_name = argv[1];
881 path_file_name = argv[2];
882 }
883 cout << location_file_name << ", " << path_file_name << endl;
884 parse_data(paths, location_file_name, path_file_name);
885 for(auto & path : paths) {
886 metro_lines.emplace_back();
887 for(auto & j : path) {
888 metro_lines.back().push_back(j);
889 }
890 }
891 for(auto & metro_line : metro_lines) {
892 handles.push_back(&metro_line);
893 }
894 handles.push_back(&directions);
895 }
896
897 MetroMap() {
898 }
899
900};
901
902
903
904
905
906int main(int argc, char **argv) {
907 init(argc, argv, new MetroMap());
908
909 return 0;
910}
911
912/*
913 Local Variables:
914 mode:c++
915 c-file-style:"stroustrup"
916 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
917 indent-tabs-mode:nil
918 fill-column:99
919 End:
920*/
921// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
922
int test()
Definition 2junctions.cpp:5
Various geometrical calculations.
Cartesian point / 2D vector and related operations.
_PangoFontDescription PangoFontDescription
Definition Layout-TNG.h:44
int main()
struct _PangoLayout PangoLayout
Geom::IntRect bounds
Definition canvas.cpp:182
void expandTo(CPoint const &p)
Enlarge the rectangle to contain the given point.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
Infinite line on a plane.
Definition line.h:53
static Line from_normal_distance(Point const &n, Coord c)
Create a line normal to a vector at a specified distance from origin.
Definition line.h:105
Point pointAt(Coord t) const
Definition line.h:231
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Two-dimensional point that doubles as a vector.
Definition point.h:66
Axis aligned, non-empty rectangle.
Definition rect.h:92
Geom::Point pos
virtual void first_time(int, char **)
virtual bool should_draw_numbers()
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(cairo_t *cr, xAx C, Rect bnd)
Definition conic-5.cpp:63
Css & result
double c[8][4]
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Geom::Point start
Geom::Point end
void parse_data(vector< vector< Point > > &paths, string location_file_name, string path_file_name)
Definition metro.cpp:292
void extremePoints(vector< Point > const &pts, Point const &dir, Point &min, Point &max)
Definition metro.cpp:363
reg_line line_best_fit(T b, T e)
Definition metro.cpp:652
Point map_point(Point p, Rect src, Point topleft, Point bottomright)
returns a point which is portionally between topleft and bottomright in the same way that p was in sr...
Definition metro.cpp:283
vector< vector< Point > > paths
Definition metro.cpp:36
double dist(const Point &a, const Point &b)
Definition geometry.cpp:310
void normal(std::vector< Point > &N, std::vector< Point > const &B)
double angle(std::vector< Point > const &A)
Various utility functions.
Definition affine.h:22
SBasisN< n > cos(LinearN< n > bo, int k)
Bezier reverse(const Bezier &a)
Definition bezier.h:342
MultiDegree< n > max(MultiDegree< n > const &p, MultiDegree< n > const &q)
Returns the maximal degree appearing in the two arguments for each variables.
Definition sbasisN.h:158
D2< T > operator+=(D2< T > &a, D2< T > const &b)
Definition d2.h:219
std::optional< Crossing > OptCrossing
Definition crossing.h:64
OptCrossing intersection(Ray const &r1, Line const &l2)
Definition line.h:545
D2< T > operator-(D2< T > const &a, D2< T > const &b)
Definition d2.h:209
D2< T > operator-=(D2< T > &a, D2< T > const &b)
Definition d2.h:228
@ parallel
Definition geom.cpp:17
D2< T > operator+(D2< T > const &a, D2< T > const &b)
Definition d2.h:199
Piecewise< SBasis > min(SBasis const &f, SBasis const &g)
Return the more negative of the two functions pointwise.
T dot(D2< T > const &a, D2< T > const &b)
Definition d2.h:355
Point unit_vector(Point const &a)
SBasisN< n > sin(LinearN< n > bo, int k)
D2< T > rot90(D2< T > const &a)
Definition d2.h:397
int n
Definition spiro.cpp:57
constexpr float pi
Definition ok-color.cpp:37
void cairo_line_to(cairo_t *cr, Geom::Point p1)
struct _cairo cairo_t
Definition path-cairo.h:16
void cairo_move_to(cairo_t *cr, Geom::Point p1)
void convertHSVtoRGB(const double H, const double S, const double V, double &R, double &G, double &B)
unsigned n1
size_t N
double height
double width
void cairo_set_source_rgba(cairo_t *cr, colour c)
void init(int argc, char **argv, Toy *t, int width=600, int height=600)