Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
box3d-side.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * 3D box face implementation
4 *
5 * Authors:
6 * Maximilian Albert <Anhalter42@gmx.de>
7 * Abhishek Sharma
8 * Jon A. Cruz <jon@joncruz.org>
9 *
10 * Copyright (C) 2007 Authors
11 *
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14
15#include "box3d-side.h"
16
17#include "attributes.h"
18#include "document.h"
19
20#include "object/box3d.h"
22#include "svg/svg.h"
23#include "xml/document.h"
24
25static void box3d_side_compute_corner_ids(Box3DSide *side, unsigned int corners[4]);
26
32
33Box3DSide::~Box3DSide() = default;
34
40
41
43 if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
44 // this is where we end up when saving as plain SVG (also in other circumstances?)
45 // thus we don' set "sodipodi:type" so that the box is only saved as an ordinary svg:path
46 repr = xml_doc->createElement("svg:path");
47 }
48
49 if (flags & SP_OBJECT_WRITE_EXT) {
50 repr->setAttributeInt("inkscape:box3dsidetype", this->dir1 ^ this->dir2 ^ this->front_or_rear);
51 }
52
53 this->set_shape();
54
55 // Nulls might be possible if this called iteratively
56 if (!_curve) {
57 return nullptr;
58 }
59
61
62 SPPolygon::write(xml_doc, repr, flags);
63
64 return repr;
65}
66
67void Box3DSide::set(SPAttr key, const gchar* value) {
68 // TODO: In case the box was recreated (by undo, e.g.) we need to recreate the path
69 // (along with other info?) from the parent box.
70
71 /* fixme: we should really collect updates */
72 switch (key) {
74 if (value) {
75 guint desc = atoi (value);
76
77 if (!Box3D::is_face_id(desc)) {
78 g_warning ("desc is not a face id: =%s=", value);
79 return;
80 }
81
82 Box3D::Axis plane = (Box3D::Axis) (desc & 0x7);
83 plane = (Box3D::is_plane(plane) ? plane : Box3D::orth_plane_or_axis(plane));
86 this->front_or_rear = (Box3D::FrontOrRear) (desc & 0x8);
87
88 this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
89 }
90 break;
91 default:
92 SPPolygon::set(key, value);
93 break;
94 }
95}
96
97void Box3DSide::update(SPCtx* ctx, guint flags) {
98 if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
99 flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore
100 }
101
102 if (flags & (SP_OBJECT_MODIFIED_FLAG |
103 SP_OBJECT_STYLE_MODIFIED_FLAG |
104 SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
105
106 this->set_shape();
107 }
108
109 SPPolygon::update(ctx, flags);
110}
111
112/* Create a new Box3DSide and append it to the parent box */
114{
115 Box3DSide *box3d_side = nullptr;
116 Inkscape::XML::Document *xml_doc = box->document->getReprDoc();;
117 Inkscape::XML::Node *repr_side = xml_doc->createElement("svg:path");
118 repr_side->setAttribute("sodipodi:type", "inkscape:box3dside");
119 box3d_side = static_cast<Box3DSide *>(box->appendChildRepr(repr_side));
120 return box3d_side;
121}
122
123/*
124 * Function which return the type attribute for Box3D.
125 * Acts as a replacement for directly accessing the XML Tree directly.
126 */
128{
129 return this->getIntAttribute("inkscape:box3dsidetype", -1);
130}
131
132void
134 this->set_shape();
135
136 // This call is responsible for live update of the sides during the initial drag
137 this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
138}
139
141 if (!this->document->getRoot()) {
142 // avoid a warning caused by sp_document_height() (which is called from sp_item_i2d_affine() below)
143 // when reading a file containing 3D boxes
144 return;
145 }
146
147 SPObject *parent = this->parent;
148
149 auto box = cast<SPBox3D>(parent);
150 if (!box) {
151 g_warning("Parent of 3D box side is not a 3D box.");
152 return;
153 }
154
155 Persp3D *persp = this->perspective();
156
157 if (!persp) {
158 return;
159 }
160
161 // TODO: Draw the correct quadrangle here
162 // To do this, determine the perspective of the box, the orientation of the side (e.g., XY-FRONT)
163 // compute the coordinates of the corners in P^3, project them onto the canvas, and draw the
164 // resulting path.
165
166 unsigned int corners[4];
168
169 if (!box->get_corner_screen(corners[0]).isFinite() ||
170 !box->get_corner_screen(corners[1]).isFinite() ||
171 !box->get_corner_screen(corners[2]).isFinite() ||
172 !box->get_corner_screen(corners[3]).isFinite() )
173 {
174 g_warning ("Trying to draw a 3D box side with invalid coordinates.");
175 return;
176 }
177
179 c.start(box->get_corner_screen(corners[0]));
180 c.appendNew<Geom::LineSegment>(box->get_corner_screen(corners[1]));
181 c.appendNew<Geom::LineSegment>(box->get_corner_screen(corners[2]));
182 c.appendNew<Geom::LineSegment>(box->get_corner_screen(corners[3]));
183 c.close();
184
185 /* Reset the shape's curve to the "original_curve"
186 * This is very important for LPEs to work properly! (the bbox might be recalculated depending on the curve in shape)*/
187
188 auto const *before = curveBeforeLPE();
189 if (before && *before != c) {
190 setCurveBeforeLPE(std::move(c));
191 sp_lpe_item_update_patheffect(this, true, false);
192 return;
193 }
194
196 setCurveBeforeLPE(std::move(c));
197 return;
198 }
199
200 // This happends on undo, fix bug:#1791784
201 setCurveInsync(std::move(c));
202}
203
204Glib::ustring Box3DSide::axes_string() const
205{
206 Glib::ustring result(Box3D::string_from_axes((Box3D::Axis) (this->dir1 ^ this->dir2)));
207
208 switch ((Box3D::Axis) (this->dir1 ^ this->dir2)) {
209 case Box3D::XY:
210 result += ((this->front_or_rear == Box3D::FRONT) ? "front" : "rear");
211 break;
212
213 case Box3D::XZ:
214 result += ((this->front_or_rear == Box3D::FRONT) ? "top" : "bottom");
215 break;
216
217 case Box3D::YZ:
218 result += ((this->front_or_rear == Box3D::FRONT) ? "right" : "left");
219 break;
220
221 default:
222 break;
223 }
224
225 return result;
226}
227
228static void
230 Box3D::Axis orth = Box3D::third_axis_direction (side->dir1, side->dir2);
231
232 corners[0] = (side->front_or_rear ? orth : 0);
233 corners[1] = corners[0] ^ side->dir1;
234 corners[2] = corners[0] ^ side->dir1 ^ side->dir2;
235 corners[3] = corners[0] ^ side->dir2;
236}
237
238Persp3D *
240 auto box = cast<SPBox3D>(parent);
241 return box ? box->persp_ref->getObject() : nullptr;
242}
243
245 // TODO: Copy over all important attributes (see sp_selected_item_to_curved_repr() for an example)
246 SPDocument *doc = this->document;
247 Inkscape::XML::Document *xml_doc = doc->getReprDoc();
248
249 Inkscape::XML::Node *repr = xml_doc->createElement("svg:path");
250 repr->setAttribute("d", this->getAttribute("d"));
251 repr->setAttribute("style", this->getAttribute("style"));
252
253 return repr;
254}
255
256/*
257 Local Variables:
258 mode:c++
259 c-file-style:"stroustrup"
260 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
261 indent-tabs-mode:nil
262 fill-column:99
263 End:
264*/
265// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Lookup dictionary for attributes/properties.
SPAttr
Definition attributes.h:27
@ INKSCAPE_BOX3D_SIDE_TYPE
static void box3d_side_compute_corner_ids(Box3DSide *side, unsigned int corners[4])
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
Box3D::FrontOrRear front_or_rear
Definition box3d-side.h:33
void set(SPAttr key, char const *value) override
void update(SPCtx *ctx, unsigned int flags) override
static Box3DSide * createBox3DSide(SPBox3D *box)
void set_shape() override
Persp3D * perspective() const
Glib::ustring axes_string() const
Box3D::Axis dir2
Definition box3d-side.h:32
Inkscape::XML::Node * convert_to_path() const
void build(SPDocument *doc, Inkscape::XML::Node *repr) override
void position_set()
~Box3DSide() override
Box3D::Axis dir1
Definition box3d-side.h:31
int getFaceId()
Sequence of contiguous curves, aka spline.
Definition path.h:353
void start(Point const &p)
Definition path.cpp:426
Interface for refcounted XML nodes.
Definition node.h:80
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
Definition node.cpp:25
bool setAttributeInt(Util::const_char_ptr key, int val)
Definition node.cpp:92
Typed SVG document implementation.
Definition document.h:101
SPRoot * getRoot()
Returns our SPRoot.
Definition document.h:200
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
Definition document.h:211
void update(SPCtx *ctx, unsigned int flags) override
Definition sp-item.cpp:779
bool hasPathEffectOnClipOrMaskRecursive(SPLPEItem *shape) const
returns true when any LPE apply to clip or mask.
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
int getIntAttribute(char const *key, int def)
Inkscape::XML::Node * repr
Definition sp-object.h:193
char * desc() const
Returns the description of this object, or NULL if there is none.
SPDocument * document
Definition sp-object.h:188
void readAttr(char const *key)
Read value of key attribute from XML node into object.
char const * getAttribute(char const *name) const
SPObject * appendChildRepr(Inkscape::XML::Node *repr)
Append repr as child of this object.
void requestDisplayUpdate(unsigned int flags)
Queues an deferred update of this object's display.
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
void build(SPDocument *document, Inkscape::XML::Node *repr) override
void set(SPAttr key, char const *value) override
std::shared_ptr< Geom::PathVector const > _curve
Definition sp-shape.h:70
void setCurveInsync(Geom::PathVector const *)
Definition sp-shape.cpp:955
void setCurveBeforeLPE(Geom::PathVector const *)
Definition sp-shape.cpp:939
Geom::PathVector const * curveBeforeLPE() const
Return a borrowed pointer of the curve before LPE (if any exists) or NULL if there is no curve.
Definition sp-shape.cpp:975
Css & result
Geom::Point corners[8]
double c[8][4]
static char const *const parent
Definition dir-util.cpp:70
Box3D::Axis third_axis_direction(Box3D::Axis dir1, Box3D::Axis dir2)
Given two axis directions out of {X, Y, Z} or the corresponding plane, return the remaining one We do...
Definition axis-manip.h:213
Box3D::Axis orth_plane_or_axis(Box3D::Axis axis)
Definition axis-manip.h:231
Glib::ustring string_from_axes(Box3D::Axis axis)
FrontOrRear
Definition axis-manip.h:73
@ FRONT
Definition axis-manip.h:74
bool is_face_id(unsigned int face_id)
Definition axis-manip.h:181
Box3D::Axis extract_first_axis_direction(Box3D::Axis dirs)
Definition axis-manip.h:221
Box3D::Axis extract_second_axis_direction(Box3D::Axis dirs)
Definition axis-manip.h:227
bool is_plane(Box3D::Axis plane)
Definition axis-manip.h:200
static cairo_user_data_key_t key
void sp_lpe_item_update_patheffect(SPLPEItem *lpeitem, bool wholetree, bool write, bool with_satellites)
Calls any registered handlers for the update_patheffect action.
Interface for XML documents.
Definition document.h:43
virtual Node * createElement(char const *name)=0
Unused.
Definition sp-object.h:94
static void sp_svg_write_path(Inkscape::SVG::PathString &str, Geom::Path const &p, bool normalize=false)
Definition svg-path.cpp:109
Interface for XML documents.