1 //:
2 // \file
3 // \author Philip C. Pritchett, RRG, University of Oxford
4 // \date 24 Mar 1999
5 // \brief See vgui_soview2D.h for a description of this file.
6
7 #include <cmath>
8 #include <iostream>
9 #include "vgui_soview2D.h"
10
11 #ifdef _MSC_VER
12 # include "vcl_msvc_warnings.h"
13 #endif
14
15 #include "vgl/vgl_distance.h"
16 #include "vnl/vnl_math.h" // for twopi
17 #include "vil/vil_image_view_base.h"
18 #include "vil/vil_new.h"
19 #include "vil1/vil1_image.h"
20 #include "vgui/vgui_range_map_params.h"
21 #include "vgui/vgui_gl.h"
22 #include "vgui/vgui_style.h"
23 #include "vgui/vgui_section_buffer.h"
24 #include <vgui/internals/vgui_draw_line.h>
25
26 //--------------------------------------------------------------------------//
27
28 std::ostream &
print(std::ostream & s) const29 vgui_soview2D_point::print(std::ostream & s) const
30 {
31 s << "[ vgui_soview2D_point " << x << ',' << y << ' ';
32 return vgui_soview2D::print(s) << " ]";
33 }
34
35 void
draw() const36 vgui_soview2D_point::draw() const
37 {
38 #if 0
39 style->apply_point_size();
40 #endif // 0
41 glBegin(GL_POINTS);
42 glVertex2f(x, y);
43 glEnd();
44 }
45
46 void
draw_select() const47 vgui_soview2D_point::draw_select() const
48 {
49 // It's much faster to draw a polygon than a point. (At least, it is
50 // on Win2000 OpenGL.) For selection, we just need to draw some
51 // little area in the vicinity of the point. We make the area really
52 // small to account for large zoom factors. In principle, we should
53 // take the zoom factor into account when determining the radius,
54 // but that's too much trouble. The radius should be large enough
55 // that it doesn't get swallowed up when added to x and to y.
56
57 // This will allow a 10000x zoom before the "circle" gets bigger
58 // than one pixel. Should be good enough!
59 //
60 float const rad = 0.0001f;
61 glBegin(GL_POLYGON);
62 glVertex2f(x - rad, y - rad);
63 glVertex2f(x + rad, y - rad);
64 glVertex2f(x + rad, y + rad);
65 glVertex2f(x - rad, y + rad);
66 glEnd();
67 }
68
69 float
distance_squared(float vx,float vy) const70 vgui_soview2D_point::distance_squared(float vx, float vy) const
71 {
72 float dx = x - vx;
73 float dy = y - vy;
74 return dx * dx + dy * dy;
75 }
76
77 void
get_centroid(float * vx,float * vy) const78 vgui_soview2D_point::get_centroid(float * vx, float * vy) const
79 {
80 *vx = x;
81 *vy = y;
82 }
83
84 void
translate(float tx,float ty)85 vgui_soview2D_point::translate(float tx, float ty)
86 {
87 x += tx;
88 y += ty;
89 }
90
91 //--------------------------------------------------------------------------//
92
93 std::ostream &
print(std::ostream & s) const94 vgui_soview2D_lineseg::print(std::ostream & s) const
95 {
96 s << "[ vgui_soview2D_lineseg " << x0 << ',' << y0 << " -- " << x1 << ',' << y1 << ' ';
97 return vgui_soview2D::print(s) << " ]";
98 }
99
100 void
draw() const101 vgui_soview2D_lineseg::draw() const
102 {
103 #ifdef DEBUG
104 std::cerr << "vgui_soview2D_lineseg::draw() line id=" << id << '\n';
105 #endif
106
107 #if 0
108 style->apply_line_width();
109 #endif // 0
110 glBegin(GL_LINES);
111 glVertex2f(x0, y0);
112 glVertex2f(x1, y1);
113 glEnd();
114 }
115
116 float
distance_squared(float vx,float vy) const117 vgui_soview2D_lineseg::distance_squared(float vx, float vy) const
118 {
119 // Here we explicitly cast some parameters to type float to help
120 // the Borland compiler, which otherwise tries to use
121 // vgl_distance2_to_linesegment<const float>, presumably because
122 // this is a const member function so some of the parameters passed
123 // to vgl_distance2_to_linesegment are effectively of type const
124 // float.
125 return (float)vgl_distance2_to_linesegment(x0, y0, x1, y1, vx, vy);
126 }
127
128 void
get_centroid(float * vx,float * vy) const129 vgui_soview2D_lineseg::get_centroid(float * vx, float * vy) const
130 {
131 *vx = (x0 + x1) / 2;
132 *vy = (y0 + y1) / 2;
133 }
134
135 void
translate(float tx,float ty)136 vgui_soview2D_lineseg::translate(float tx, float ty)
137 {
138 x0 += tx;
139 y0 += ty;
140 x1 += tx;
141 y1 += ty;
142 }
143
144 //--------------------------------------------------------------------------//
145
~vgui_soview2D_group()146 vgui_soview2D_group::~vgui_soview2D_group()
147 {
148 for (unsigned int i = 0; i < ls.size(); i++)
149 if (ls[i])
150 delete ls[i];
151
152 // clear vector
153 ls.clear();
154 }
155
156 void
set_style(const vgui_style_sptr & s)157 vgui_soview2D_group::set_style(const vgui_style_sptr & s)
158 {
159 for (unsigned int i = 0; i < ls.size(); i++)
160 if (!ls[i]->get_style())
161 ls[i]->set_style(s);
162
163 vgui_soview::set_style(s);
164 }
165
166 std::ostream &
print(std::ostream & s) const167 vgui_soview2D_group::print(std::ostream & s) const
168 {
169 s << "[ vgui_soview2D_group ";
170
171 for (unsigned int i = 0; i < ls.size(); i++)
172 ls[i]->print(s);
173
174 return vgui_soview2D::print(s) << " ]";
175 }
176
177 void
draw() const178 vgui_soview2D_group::draw() const
179 {
180 for (unsigned int i = 0; i < ls.size(); i++)
181 ls[i]->draw();
182 }
183
184 void
draw_select() const185 vgui_soview2D_group::draw_select() const
186 {
187 for (unsigned int i = 0; i < ls.size(); i++)
188 ls[i]->draw_select();
189 }
190
191 float
distance_squared(float vx,float vy) const192 vgui_soview2D_group::distance_squared(float vx, float vy) const
193 {
194 if (ls.size() == 0)
195 return -1e30f;
196
197 float min = ls[0]->distance_squared(vx, vy);
198
199 for (unsigned int i = 1; i < ls.size(); i++)
200 {
201 float d = ls[i]->distance_squared(vx, vy);
202 if (d < min)
203 min = d;
204 }
205
206 return min;
207 }
208
209 void
get_centroid(float * vx,float * vy) const210 vgui_soview2D_group::get_centroid(float * vx, float * vy) const
211 {
212 *vx = 0;
213 *vy = 0;
214 const int n = ls.size();
215
216 for (int i = 0; i < n; i++)
217 {
218 float cx, cy;
219 ls[i]->get_centroid(&cx, &cy);
220 *vx += cx;
221 *vy += cy;
222 }
223
224 float s = 1.0f / n;
225 *vx *= s;
226 *vy *= s;
227 }
228
229 void
translate(float tx,float ty)230 vgui_soview2D_group::translate(float tx, float ty)
231 {
232 for (unsigned int i = 0; i < ls.size(); i++)
233 ls[i]->translate(tx, ty);
234 }
235
236 //--------------------------------------------------------------------------//
237
238 std::ostream &
print(std::ostream & s) const239 vgui_soview2D_infinite_line::print(std::ostream & s) const
240 {
241 s << "[ vgui_soview2D_infinite_line " << a << ',' << b << ',' << c << ' ';
242 return vgui_soview2D::print(s) << " ]";
243 }
244
245 void
draw() const246 vgui_soview2D_infinite_line::draw() const
247 {
248 vgui_draw_line(a, b, c);
249 }
250
251 float
distance_squared(float vx,float vy) const252 vgui_soview2D_infinite_line::distance_squared(float vx, float vy) const
253 {
254 float tmp = a * vx + b * vy + c;
255 return tmp * tmp / (a * a + b * b);
256 }
257
258 void
get_centroid(float * vx,float * vy) const259 vgui_soview2D_infinite_line::get_centroid(float * vx, float * vy) const
260 {
261 *vx = 0;
262 *vy = 0;
263 }
264
265 void
translate(float tx,float ty)266 vgui_soview2D_infinite_line::translate(float tx, float ty)
267 {
268 c += a * tx + b * ty;
269 }
270
271 //--------------------------------------------------------------------------//
272
273 constexpr int vgui__CIRCLE2D_LIST = 1;
274
275 void
compile()276 vgui_soview2D_circle::compile()
277 {
278 glNewList(vgui__CIRCLE2D_LIST, GL_COMPILE);
279 glBegin(GL_LINE_LOOP);
280 for (unsigned int i = 0; i < 100; i++)
281 {
282 double angle = vnl_math::twopi * 0.01 * i;
283 glVertex2d(std::cos(angle), std::sin(angle));
284 }
285 glEnd();
286 glEndList();
287 }
288
289
290 std::ostream &
print(std::ostream & s) const291 vgui_soview2D_circle::print(std::ostream & s) const
292 {
293 s << "[ vgui_soview2D_circle " << x << ',' << y << " r" << r << ' ';
294 return vgui_soview2D::print(s) << " ]";
295 }
296
297 void
draw() const298 vgui_soview2D_circle::draw() const
299 {
300 glBegin(GL_LINE_LOOP);
301 for (unsigned int i = 0; i < 100; i++)
302 {
303 double angle = vnl_math::twopi * 0.01 * i;
304 glVertex2d(x + r * std::cos(angle), y + r * std::sin(angle));
305 }
306 glEnd();
307 }
308
309 float
distance_squared(float vx,float vy) const310 vgui_soview2D_circle::distance_squared(float vx, float vy) const
311 {
312 float dx = x - vx;
313 float dy = y - vy;
314
315 // distance from point to centre
316 float dcentre = std::sqrt(dx * dx + dy * dy);
317
318 // signed distance from point to circumference
319 float dcircum = dcentre - this->r;
320
321 return dcircum * dcircum;
322 }
323
324 void
get_centroid(float * vx,float * vy) const325 vgui_soview2D_circle::get_centroid(float * vx, float * vy) const
326 {
327 *vx = x;
328 *vy = y;
329 }
330
331 void
translate(float tx,float ty)332 vgui_soview2D_circle::translate(float tx, float ty)
333 {
334 x += tx;
335 y += ty;
336 }
337
338 //--------------------------------------------------------------------------------//
339
340 std::ostream &
print(std::ostream & s) const341 vgui_soview2D_ellipse::print(std::ostream & s) const
342 {
343 s << "[ vgui_soview2D_ellipse " << x << ',' << y << " w" << w << " h" << h << " phi" << phi << ' ';
344 return vgui_soview2D::print(s) << " ]";
345 }
346
347 void
draw() const348 vgui_soview2D_ellipse::draw() const
349 {
350 double px, py;
351
352 glBegin(GL_LINE_LOOP);
353 for (unsigned int i = 0; i < 100; i++)
354 {
355 double angle = vnl_math::twopi * 0.01 * i;
356 px = w * std::cos(this->phi) * std::cos(angle) + h * std::sin(this->phi) * std::sin(angle);
357 py = h * std::cos(this->phi) * std::sin(angle) - w * std::sin(this->phi) * std::cos(angle);
358 glVertex2d(x + px, y + py);
359 }
360 glEnd();
361 }
362
363 //:
364 // \todo not correctly implemented (assumes a circle)
365 float
distance_squared(float vx,float vy) const366 vgui_soview2D_ellipse::distance_squared(float vx, float vy) const
367 {
368 return (vx - x) * (vx - x) + (vy - y) * (vy - y);
369 }
370
371 void
get_centroid(float * vx,float * vy) const372 vgui_soview2D_ellipse::get_centroid(float * vx, float * vy) const
373 {
374 *vx = x;
375 *vy = y;
376 }
377
378 void
translate(float tx,float ty)379 vgui_soview2D_ellipse::translate(float tx, float ty)
380 {
381 x += tx;
382 y += ty;
383 }
384
385
386 //--------------------------------------------------------------------------------//
387
vgui_soview2D_linestrip(unsigned n_,float const * x_,float const * y_)388 vgui_soview2D_linestrip::vgui_soview2D_linestrip(unsigned n_, float const * x_, float const * y_)
389 : n(n_)
390 , x(new float[n])
391 , y(new float[n])
392 {
393 for (unsigned i = 0; i < n; ++i)
394 {
395 x[i] = x_[i];
396 y[i] = y_[i];
397 }
398 }
399
~vgui_soview2D_linestrip()400 vgui_soview2D_linestrip::~vgui_soview2D_linestrip()
401 {
402 n = 0;
403 delete[] x;
404 x = nullptr;
405 delete[] y;
406 y = nullptr;
407 }
408
409 void
draw() const410 vgui_soview2D_linestrip::draw() const
411 {
412 glBegin(GL_LINE_STRIP);
413 for (unsigned i = 0; i < n; ++i)
414 glVertex2f(x[i], y[i]);
415 glEnd();
416 }
417
418 std::ostream &
print(std::ostream & s) const419 vgui_soview2D_linestrip::print(std::ostream & s) const
420 {
421 return s << "[ a linestrip. FIXME ]";
422 }
423
424 float
distance_squared(float vx,float vy) const425 vgui_soview2D_linestrip::distance_squared(float vx, float vy) const
426 {
427 double tmp = vgl_distance_to_non_closed_polygon(x, y, this->n, vx, vy);
428 return static_cast<float>(tmp * tmp);
429 }
430
431 void
get_centroid(float * vx,float * vy) const432 vgui_soview2D_linestrip::get_centroid(float * vx, float * vy) const
433 {
434 *vx = 0;
435 *vy = 0;
436 for (unsigned i = 0; i < n; ++i)
437 {
438 *vx += x[i];
439 *vy += y[i];
440 }
441 float s = 1.0f / float(n);
442 *vx *= s;
443 *vy *= s;
444 }
445
446 void
translate(float tx,float ty)447 vgui_soview2D_linestrip::translate(float tx, float ty)
448 {
449 for (unsigned i = 0; i < n; ++i)
450 {
451 x[i] += tx;
452 y[i] += ty;
453 }
454 }
455
456 void
set_size(unsigned nn)457 vgui_soview2D_linestrip::set_size(unsigned nn)
458 {
459 if (nn < n)
460 {
461 n = nn;
462 return;
463 }
464
465 // we know that n <= nn
466 float * nx = new float[nn];
467 float * ny = new float[nn];
468 for (unsigned i = 0; i < n; ++i)
469 {
470 nx[i] = x[i];
471 ny[i] = y[i];
472 }
473
474 n = nn;
475 delete[] x;
476 x = nx;
477 delete[] y;
478 y = ny;
479 }
480
481 //--------------------------------------------------------------------------------//
482
vgui_soview2D_polygon(unsigned n_,float const * x_,float const * y_,bool fill)483 vgui_soview2D_polygon::vgui_soview2D_polygon(unsigned n_, float const * x_, float const * y_, bool fill)
484 : n(n_)
485 , x(new float[n])
486 , y(new float[n])
487 , filled(fill)
488 {
489 for (unsigned i = 0; i < n; ++i)
490 {
491 x[i] = x_[i];
492 y[i] = y_[i];
493 }
494 }
495
~vgui_soview2D_polygon()496 vgui_soview2D_polygon::~vgui_soview2D_polygon()
497 {
498 n = 0;
499 delete[] x;
500 x = nullptr;
501 delete[] y;
502 y = nullptr;
503 }
504
505 void
draw() const506 vgui_soview2D_polygon::draw() const
507 {
508 if (filled)
509 {
510 glBegin(GL_POLYGON);
511 for (unsigned i = 0; i < n; ++i)
512 glVertex2f(x[i], y[i]);
513 glEnd();
514 }
515 else
516 {
517 glBegin(GL_LINE_LOOP);
518 for (unsigned i = 0; i < n; ++i)
519 glVertex2f(x[i], y[i]);
520 glEnd();
521 }
522 }
523
524 std::ostream &
print(std::ostream & s) const525 vgui_soview2D_polygon::print(std::ostream & s) const
526 {
527 return s << "[ a polygon. FIXME ]";
528 }
529
530 float
distance_squared(float vx,float vy) const531 vgui_soview2D_polygon::distance_squared(float vx, float vy) const
532 {
533 double tmp = vgl_distance_to_closed_polygon(x, y, this->n, vx, vy);
534 return static_cast<float>(tmp * tmp);
535 }
536
537 void
get_centroid(float * vx,float * vy) const538 vgui_soview2D_polygon::get_centroid(float * vx, float * vy) const
539 {
540 *vx = 0;
541 *vy = 0;
542 for (unsigned i = 0; i < n; ++i)
543 {
544 *vx += x[i];
545 *vy += y[i];
546 }
547 float s = 1.0f / float(n);
548 *vx *= s;
549 *vy *= s;
550 }
551
552 void
translate(float tx,float ty)553 vgui_soview2D_polygon::translate(float tx, float ty)
554 {
555 for (unsigned i = 0; i < n; ++i)
556 {
557 x[i] += tx;
558 y[i] += ty;
559 }
560 }
561
562 void
set_size(unsigned nn)563 vgui_soview2D_polygon::set_size(unsigned nn)
564 {
565 if (nn < n)
566 {
567 n = nn;
568 return;
569 }
570
571 // we know that n <= nn
572 float * nx = new float[nn];
573 float * ny = new float[nn];
574 for (unsigned i = 0; i < n; ++i)
575 {
576 nx[i] = x[i];
577 ny[i] = y[i];
578 }
579
580 n = nn;
581 delete[] x;
582 x = nx;
583 delete[] y;
584 y = ny;
585 }
586
587
588 //-----------------------------------------------------------
589
vgui_soview2D_image(float in_x,float in_y,vil1_image const & img,bool in_blend,GLenum format,GLenum type)590 vgui_soview2D_image::vgui_soview2D_image(float in_x,
591 float in_y,
592 vil1_image const & img,
593 bool in_blend,
594 GLenum format,
595 GLenum type)
596 : x_(in_x)
597 , y_(in_y)
598 , w_(img.width())
599 , h_(img.height())
600 , blend_(in_blend)
601 , buffer_(new vgui_section_buffer(0, 0, w_, h_, format, type))
602 {
603 buffer_->apply(img, (vgui_range_map_params *)nullptr);
604 }
605
vgui_soview2D_image(float in_x,float in_y,vil_image_view_base const & img,bool in_blend,GLenum format,GLenum type)606 vgui_soview2D_image::vgui_soview2D_image(float in_x,
607 float in_y,
608 vil_image_view_base const & img,
609 bool in_blend,
610 GLenum format,
611 GLenum type)
612 : x_(in_x)
613 , y_(in_y)
614 , w_(img.ni())
615 , h_(img.nj())
616 , blend_(in_blend)
617 , buffer_(new vgui_section_buffer(0, 0, w_, h_, format, type))
618 {
619 buffer_->apply(vil_new_image_resource_of_view(img), (vgui_range_map_params *)nullptr);
620 }
621
~vgui_soview2D_image()622 vgui_soview2D_image::~vgui_soview2D_image()
623 {
624 delete buffer_;
625 }
626
627 void
draw() const628 vgui_soview2D_image::draw() const
629 {
630 // Get the current blend state so we can restore it later
631 GLboolean blend_on;
632 glGetBooleanv(GL_BLEND, &blend_on);
633
634 if (blend_)
635 {
636 glEnable(GL_BLEND);
637 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
638 }
639 else
640 glDisable(GL_BLEND);
641
642 glTranslatef(x_, y_, 0.0f);
643 buffer_->draw_as_image() || buffer_->draw_as_rectangle();
644 glTranslatef(-x_, -y_, 0.0f);
645
646 if (blend_on)
647 glEnable(GL_BLEND);
648 else
649 glDisable(GL_BLEND);
650 }
651
652 std::ostream &
print(std::ostream & s) const653 vgui_soview2D_image::print(std::ostream & s) const
654 {
655 return s << "[ vgui_soview2D_image " << w_ << 'x' << h_ << ", blend=" << blend_ << " ]";
656 }
657
658 float
distance_squared(float vx,float vy) const659 vgui_soview2D_image::distance_squared(float vx, float vy) const
660 {
661 float dx = (x_ + (w_ / 2.0f)) - vx;
662 float dy = (y_ + (h_ / 2.0f)) - vy;
663 return dx * dx + dy * dy;
664 }
665
666 void
get_centroid(float * vx,float * vy) const667 vgui_soview2D_image::get_centroid(float * vx, float * vy) const
668 {
669 float x1 = x_ + (w_ / 2.0f);
670 float y1 = y_ + (h_ / 2.0f);
671
672 *vx = x1;
673 *vy = y1;
674 }
675
676 void
translate(float tx,float ty)677 vgui_soview2D_image::translate(float tx, float ty)
678 {
679 x_ += tx;
680 y_ += ty;
681 }
682