02a49b4e40ab5e920eb2334a5d5b163ae71642e7
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 "box3d-face.h"
15 #include <iostream>
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(*SP3DBoxContext::current_perspective->get_vanishing_point(dir1), lr);
68 Box3D::Line line2(*pt_align, *SP3DBoxContext::current_perspective->get_vanishing_point(dir3));
69 corners[2] = *line1.intersect(line2);
70 } else {
71 corners[2] = Box3D::Line(*pt_align, *SP3DBoxContext::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 }
103 }
104 ***/
106 Box3DFace::Box3DFace(Box3DFace const &box3dface)
107 {
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;
113 }
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 void
125 Box3DFace::set_face (NR::Point const A, NR::Point const C, Box3D::Axis const axis1, Box3D::Axis const axis2)
126 {
127 *corners[0] = A;
128 *corners[2] = C;
129 if (!SP_IS_3DBOX_CONTEXT(inkscape_active_event_context()))
130 return;
131 SP3DBoxContext *bc = SP_3DBOX_CONTEXT(inkscape_active_event_context());
133 Box3D::PerspectiveLine line1 (A, axis1);
134 Box3D::PerspectiveLine line2 (C, axis2);
135 NR::Maybe<NR::Point> B = line1.intersect(line2);
137 Box3D::PerspectiveLine line3 (*corners[0], axis2);
138 Box3D::PerspectiveLine line4 (*corners[2], axis1);
139 NR::Maybe<NR::Point> D = line3.intersect(line4);
141 // FIXME: How to handle the case if one of the intersections doesn't exist?
142 // Maybe set them equal to the corresponding VPs?
143 if (!D) D = NR::Point(0.0, 0.0);
144 if (!B) B = NR::Point(0.0, 0.0);
146 *corners[1] = *B;
147 *corners[3] = *D;
149 this->dir1 = axis1;
150 this->dir2 = axis2;
151 }
154 NR::Point Box3DFace::operator[](unsigned int i)
155 {
156 return *corners[i % 4];
157 }
161 /**
162 * Append the curve's path as a child to the given 3D box (since SP3DBox
163 * is derived from SPGroup, so we can append children to its svg representation)
164 */
165 void Box3DFace::hook_path_to_3dbox(SPPath * existing_path)
166 {
167 if (this->path) {
168 //g_print ("Path already exists. Returning ...\n");
169 return;
170 }
172 if (existing_path != NULL) {
173 // no need to create a new path
174 this->path = existing_path;
175 return;
176 }
178 SPDesktop *desktop = inkscape_active_desktop();
179 Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(SP_OBJECT(parent_box3d)));
180 GString *pstring = g_string_new("");
181 g_string_printf (pstring, "tools.shapes.3dbox.%s", axes_string());
183 Inkscape::XML::Node *repr_face = xml_doc->createElement("svg:path");
184 sp_desktop_apply_style_tool (desktop, repr_face, pstring->str, false);
185 this->path = SP_PATH(SP_OBJECT(parent_box3d)->appendChildRepr(repr_face));
186 Inkscape::GC::release(repr_face);
187 }
189 /**
190 * Write the path's "d" attribute to the SVG representation.
191 */
192 void Box3DFace::set_path_repr()
193 {
194 SP_OBJECT(this->path)->repr->setAttribute("d", svg_repr_string());
195 }
197 void Box3DFace::set_curve()
198 {
199 if (this->path == NULL) {
200 g_warning("this->path is NULL! \n");
201 return;
202 }
203 NR::Matrix const i2d (sp_item_i2d_affine (SP_ITEM (this->parent_box3d)));
204 SPCurve *curve = sp_curve_new();
205 sp_curve_moveto(curve, (*corners[0]) * i2d);
206 sp_curve_lineto(curve, (*corners[1]) * i2d);
207 sp_curve_lineto(curve, (*corners[2]) * i2d);
208 sp_curve_lineto(curve, (*corners[3]) * i2d);
209 sp_curve_closepath(curve);
210 sp_shape_set_curve(SP_SHAPE(this->path), curve, true);
211 sp_curve_unref(curve);
212 }
214 gchar * Box3DFace::axes_string()
215 {
216 GString *pstring = g_string_new("");
217 g_string_printf (pstring, "%s", Box3D::string_from_axes ((Box3D::Axis) (dir1 ^ dir2)));
218 switch ((Box3D::Axis) (dir1 ^ dir2)) {
219 case Box3D::XY:
220 g_string_append_printf (pstring, (front_or_rear == Box3D::FRONT) ? "front" : "rear");
221 break;
222 case Box3D::XZ:
223 g_string_append_printf (pstring, (front_or_rear == Box3D::FRONT) ? "top" : "bottom");
224 break;
225 case Box3D::YZ:
226 g_string_append_printf (pstring, (front_or_rear == Box3D::FRONT) ? "right" : "left");
227 break;
228 default:
229 break;
230 }
231 return pstring->str;
232 }
234 gchar * Box3DFace::svg_repr_string()
235 {
236 NR::Matrix const i2d (sp_item_i2d_affine (SP_ITEM (this->parent_box3d)));
237 GString *pstring = g_string_new("");
238 gchar str[G_ASCII_DTOSTR_BUF_SIZE];
240 g_string_append_printf (pstring, "M ");
241 g_string_append_printf (pstring, "%s", g_ascii_dtostr (str, sizeof (str), ((*corners[0]) * i2d)[NR::X]));
242 g_string_append_printf (pstring, ",");
243 g_string_append_printf (pstring, "%s", g_ascii_dtostr (str, sizeof (str), ((*corners[0]) * i2d)[NR::Y]));
245 g_string_append_printf (pstring, " L ");
246 g_string_append_printf (pstring, "%s", g_ascii_dtostr (str, sizeof (str), ((*corners[1]) * i2d)[NR::X]));
247 g_string_append_printf (pstring, ",");
248 g_string_append_printf (pstring, "%s", g_ascii_dtostr (str, sizeof (str), ((*corners[1]) * i2d)[NR::Y]));
250 g_string_append_printf (pstring, " L ");
251 g_string_append_printf (pstring, "%s", g_ascii_dtostr (str, sizeof (str), ((*corners[2]) * i2d)[NR::X]));
252 g_string_append_printf (pstring, ",");
253 g_string_append_printf (pstring, "%s", g_ascii_dtostr (str, sizeof (str), ((*corners[2]) * i2d)[NR::Y]));
255 g_string_append_printf (pstring, " L ");
256 g_string_append_printf (pstring, "%s", g_ascii_dtostr (str, sizeof (str), ((*corners[3]) * i2d)[NR::X]));
257 g_string_append_printf (pstring, ",");
258 g_string_append_printf (pstring, "%s", g_ascii_dtostr (str, sizeof (str), ((*corners[3]) * i2d)[NR::Y]));
260 g_string_append_printf (pstring, " z");
262 return pstring->str;
263 }
265 /*
266 Local Variables:
267 mode:c++
268 c-file-style:"stroustrup"
269 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
270 indent-tabs-mode:nil
271 fill-column:99
272 End:
273 */
274 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :