Code

Enable center-dragging of boxes ('in perspective') within the XY-plane
[inkscape.git] / src / perspective-line.cpp
1 #define __PERSPECTIVE_LINE_C__
3 /*
4  * Perspective line for 3D perspectives
5  *
6  * Authors:
7  *   Maximilian Albert <Anhalter42@gmx.de>
8  *
9  * Copyright (C) 2007 authors
10  *
11  * Released under GNU GPL, read the file 'COPYING' for more information
12  */
14 #include "perspective-line.h"
15 #include "desktop.h"
17 namespace Box3D {
19 PerspectiveLine::PerspectiveLine (NR::Point const &pt, Box3D::Axis const axis, Perspective3D *perspective) :
20         Line (pt, *(perspective->get_vanishing_point(axis)), true)
21 {
22     g_assert (perspective != NULL);
23     g_assert (Box3D::is_single_axis_direction (axis));
25     if (perspective->get_vanishing_point(axis)->state == VP_INFINITE) {
26         this->set_direction(perspective->get_vanishing_point(axis)->v_dir);
27     }
28     this->vp_dir = axis;
29     this->persp  = perspective;
30 }
32 // This function makes sure not to return NR::Nothing()
33 // FIXME: How to gracefully handle parallel lines?
34 NR::Maybe<NR::Point> PerspectiveLine::intersect (Line const &line)
35 {
36     NR::Maybe<NR::Point> pt = this->Line::intersect(line);
37     if (!pt) {
38         Box3D::VanishingPoint vp = *(persp->get_vanishing_point(vp_dir));
39         if (vp.state == VP_INFINITE) {
40             pt = vp;
41         } else {
42             pt = NR::Point (0.0, 0.0); // FIXME: Better solution needed
43         }
44     }
45     return pt; 
46 }
48 // FIXME: Do we really need two intersection methods?
49 NR::Point PerspectiveLine::meet(Line const &line)
50 {
51     return *intersect(line); // works since intersect() does not return NR::Nothing()
52 }
54 NR::Point PerspectiveLine::pt_with_given_cross_ratio (NR::Point const &C, NR::Point const &D, double gamma)
55 {
56     if (persp->get_vanishing_point (vp_dir)->is_finite()) {
57         NR::Point V (*persp->get_vanishing_point (vp_dir));
58         return fourth_pt_with_given_cross_ratio (V, C, D, gamma);
59     } else {
60         if (fabs (gamma - 1) < epsilon) {
61             g_warning ("Cannot compute point with given cross ratio.\n");
62             return NR::Point (0.0, 0.0);
63         }
64         Line line (C, D);
65         double lambda_C = line.lambda (C);
66         double lambda_D = line.lambda (D);
67         return line.point_from_lambda ((lambda_D - gamma * lambda_C) / (1 - gamma));
68     }
69 }
71 NR::Maybe<NR::Point> PerspectiveLine::intersection_with_viewbox (SPDesktop *desktop)
72 {
73     NR::Rect vb = desktop->get_display_area();
74     /* remaining viewbox corners */
75     NR::Point ul (vb.min()[NR::X], vb.max()[NR::Y]);
76     NR::Point lr (vb.max()[NR::X], vb.min()[NR::Y]);
78     std::pair <NR::Point, NR::Point> e = side_of_intersection (vb.min(), lr, vb.max(), ul, this->pt, this->v_dir);
79     if (e.first == e.second) {
80         // perspective line lies outside the canvas
81         return NR::Nothing();
82     }
84     Line line (e.first, e.second);
85     return this->intersect (line);
86 }
88 } // namespace Box3D 
89  
90 /*
91   Local Variables:
92   mode:c++
93   c-file-style:"stroustrup"
94   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
95   indent-tabs-mode:nil
96   fill-column:99
97   End:
98 */
99 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :