Code

096e7d7a6bbbd9868bbef2e94c6699f95b1f3178
[inkscape.git] / src / box3d-face.cpp
1 #define __SP_3DBOX_FACE_C__
3 /*
4  * Face of a 3D box ('perspectivic rectangle')
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 "svg/svg.h"
15 #include "box3d-face.h"
17 // FIXME: It's quite redundant to pass the box plus the corners plus the axes. At least the corners can
18 //        theoretically be reconstructed from the box and the axes, but in order to do this we need
19 //        access to box->corners, which is not possible if we only have a forward declaration of SP3DBox
20 //        in box3d-face.h. (But we can't include box3d.h itself because the latter already includes
21 //        box3d-face.h).
22 Box3DFace::Box3DFace(SP3DBox *box, NR::Point &A, NR::Point &B, NR::Point &C, NR::Point &D,
23                      Box3D::Axis plane, Box3D::FrontOrRear rel_pos)
24     : front_or_rear (rel_pos), path (NULL), parent_box3d (box)
25  {
26     dir1 = extract_first_axis_direction (plane);
27     dir2 = extract_second_axis_direction (plane);
28     /*
29     Box3D::Axis axis = (rel_pos == Box3D::FRONT ? Box3D::NONE : Box3D::third_axis_direction (plane));
30     set_corners (box->corners[axis],
31                  box->corners[axis ^ dir1],
32                  box->corners[axis ^ dir1 ^ dir2],
33                  box->corners[axis ^ dir2]);
34     */
35     set_corners (A, B, C, D);
36 }
38 Box3DFace::~Box3DFace()
39 {
40     for (int i = 0; i < 4; ++i) {
41         if (this->corners[i]) {
42             //delete this->corners[i];
43             this->corners[i] = NULL;
44         }
45     }
46
48 void Box3DFace::set_corners(NR::Point &A, NR::Point &B, NR::Point &C, NR::Point &D)
49 {
50     corners[0] = &A;
51     corners[1] = &B;
52     corners[2] = &C;
53     corners[3] = &D;
54 }
56 /***
57 void Box3DFace::set_shape(NR::Point const ul, NR::Point const lr,
58                      Box3D::Axis const dir1, Box3D::Axis const dir2,
59                      unsigned int shift_count, NR::Maybe<NR::Point> pt_align, bool align_along_PL)
60 {
61     corners[0] = ul;
62     if (!pt_align) {
63         corners[2] = lr;
64     } else {
65         if (align_along_PL) {
66             Box3D::Axis dir3 = Box3D::third_axis_direction (dir1, dir2);
67             Box3D::Line line1(*Box3D::Perspective3D::current_perspective->get_vanishing_point(dir1), lr);
68             Box3D::Line line2(*pt_align, *Box3D::Perspective3D::current_perspective->get_vanishing_point(dir3));
69             corners[2] = *line1.intersect(line2);
70         } else {
71             corners[2] = Box3D::Line(*pt_align, *Box3D::Perspective3D::current_perspective->get_vanishing_point(dir1)).closest_to(lr);
72         }
73     }
75     Box3D::PerspectiveLine first_line  (corners[0], dir1);
76     Box3D::PerspectiveLine second_line (corners[2], dir2);
77     NR::Maybe<NR::Point> ur = first_line.intersect(second_line);
79     Box3D::PerspectiveLine third_line  (corners[0], dir2);
80     Box3D::PerspectiveLine fourth_line (corners[2], dir1);
81     NR::Maybe<NR::Point> ll = third_line.intersect(fourth_line);
83     // FIXME: How to handle the case if one of the intersections doesn't exist?
84     //        Maybe set them equal to the corresponding VPs? 
85     if (!ur) ur = NR::Point(0.0, 0.0);    
86     if (!ll) ll = NR::Point(0.0, 0.0);
88     corners[1] = *ll;
89     corners[3] = *ur;
91     this->dir1 = dir1;
92     this->dir2 = dir2;
94     // FIXME: Can be made more concise
95     NR::Point tmp_pt;
96     for (unsigned int i=0; i < shift_count; i++) {
97         tmp_pt = corners[3];
98         corners[1] = corners[0];
99         corners[2] = corners[1];
100         corners[3] = corners[2];
101         corners[0] = tmp_pt;
102     }
104 ***/
106 Box3DFace::Box3DFace(Box3DFace const &box3dface)
108     for (int i = 0; i < 4; ++i) {
109         this->corners[i] = box3dface.corners[i];
110     }
111     this->dir1 = box3dface.dir1;
112     this->dir2 = box3dface.dir2;
115 /**
116  * Construct a 3D box face with opposite corners A and C whose sides are directed
117  * along axis1 and axis2. The corners have the following order:
118  *
119  * A = corners[0]  --> along axis1 --> B = corners[1] --> along axis2 --> C = corners[2]
120  *                 --> along axis1 --> D = corners[3] --> along axis2 --> D = corners[0].
121  * 
122  * Note that several other functions rely on this precise order.
123  */
124 /***
125 void
126 Box3DFace::set_face (NR::Point const A, NR::Point const C, Box3D::Axis const axis1, Box3D::Axis const axis2)
128     *corners[0] = A;
129     *corners[2] = C;
130     if (!SP_IS_3DBOX_CONTEXT(inkscape_active_event_context()))
131         return;
132     SP3DBoxContext *bc = SP_3DBOX_CONTEXT(inkscape_active_event_context());
133     
134     Box3D::PerspectiveLine line1 (A, axis1, Box3D::Perspective3D::current_perspective);
135     Box3D::PerspectiveLine line2 (C, axis2, Box3D::Perspective3D::current_perspective);
136     NR::Maybe<NR::Point> B = line1.intersect(line2);
138     Box3D::PerspectiveLine line3 (*corners[0], axis2, Box3D::Perspective3D::current_perspective);
139     Box3D::PerspectiveLine line4 (*corners[2], axis1, Box3D::Perspective3D::current_perspective);
140     NR::Maybe<NR::Point> D = line3.intersect(line4);
142     // FIXME: How to handle the case if one of the intersections doesn't exist?
143     //        Maybe set them equal to the corresponding VPs? 
144     if (!D) D = NR::Point(0.0, 0.0);    
145     if (!B) B = NR::Point(0.0, 0.0);
147     *corners[1] = *B;
148     *corners[3] = *D;
150     this->dir1 = axis1;
151     this->dir2 = axis2;
153 ***/
155 NR::Point Box3DFace::operator[](unsigned int i)
157     return *corners[i % 4];
162 /**
163  * Append the curve's path as a child to the given 3D box (since SP3DBox
164  * is derived from SPGroup, so we can append children to its svg representation)
165  */
166 void Box3DFace::hook_path_to_3dbox(SPPath * existing_path)
168     if (this->path) {
169         //g_print ("Path already exists. Returning ...\n");
170         return;
171     }
173     if (existing_path != NULL) {
174         // no need to create a new path
175         this->path = existing_path;
176         return;
177     }
179     SPDesktop *desktop = inkscape_active_desktop();
180     Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(SP_OBJECT(parent_box3d)));
181     GString *pstring = g_string_new("");
182     g_string_printf (pstring, "tools.shapes.3dbox.%s", axes_string());
184     Inkscape::XML::Node *repr_face = xml_doc->createElement("svg:path");
185     sp_desktop_apply_style_tool (desktop, repr_face, pstring->str, false);
186     this->path = SP_PATH(SP_OBJECT(parent_box3d)->appendChildRepr(repr_face));
187     Inkscape::GC::release(repr_face);
190 /**
191  * Write the path's "d" attribute to the SVG representation.
192  */
193 void Box3DFace::set_path_repr()
195     NR::Matrix const i2d (sp_item_i2d_affine (SP_ITEM (this->parent_box3d)));
196     SPCurve * curve = sp_curve_new();
197     sp_curve_moveto (curve, ((*corners[0]) * i2d)[NR::X], ((*corners[0]) * i2d)[NR::Y]);
198     sp_curve_lineto (curve, ((*corners[1]) * i2d)[NR::X], ((*corners[1]) * i2d)[NR::Y]);
199     sp_curve_lineto (curve, ((*corners[2]) * i2d)[NR::X], ((*corners[2]) * i2d)[NR::Y]);
200     sp_curve_lineto (curve, ((*corners[3]) * i2d)[NR::X], ((*corners[3]) * i2d)[NR::Y]);
201     sp_curve_closepath (curve);
202     SP_OBJECT(this->path)->repr->setAttribute("d", sp_svg_write_path (SP_CURVE_BPATH(curve)));
205 void Box3DFace::set_curve()
207     if (this->path == NULL) {
208         g_warning("this->path is NULL! \n");
209         return;
210     }
211     NR::Matrix const i2d (sp_item_i2d_affine (SP_ITEM (this->parent_box3d)));
212     SPCurve *curve = sp_curve_new();
213     sp_curve_moveto(curve, (*corners[0]) * i2d);
214     sp_curve_lineto(curve, (*corners[1]) * i2d);
215     sp_curve_lineto(curve, (*corners[2]) * i2d);
216     sp_curve_lineto(curve, (*corners[3]) * i2d);
217     sp_curve_closepath(curve);
218     sp_shape_set_curve(SP_SHAPE(this->path), curve, true);
219     sp_curve_unref(curve);
222 gchar * Box3DFace::axes_string()
224     GString *pstring = g_string_new("");
225     g_string_printf (pstring, "%s", Box3D::string_from_axes ((Box3D::Axis) (dir1 ^ dir2)));
226     switch ((Box3D::Axis) (dir1 ^ dir2)) {
227         case Box3D::XY:
228             g_string_append_printf (pstring, (front_or_rear == Box3D::FRONT) ? "front" : "rear");
229             break;
230         case Box3D::XZ:
231             g_string_append_printf (pstring, (front_or_rear == Box3D::FRONT) ? "top" : "bottom");
232             break;
233         case Box3D::YZ:
234             g_string_append_printf (pstring, (front_or_rear == Box3D::FRONT) ? "right" : "left");
235             break;
236         default:
237             break;
238     }
239     return pstring->str;
242 /*
243   Local Variables:
244   mode:c++
245   c-file-style:"stroustrup"
246   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
247   indent-tabs-mode:nil
248   fill-column:99
249   End:
250 */
251 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :