box3d.cpp revision d5ad05ac17abfd7d2eae333a8c1233971e1c1a8f
3f4f0d494ca026eab6c7bba188b98c8a74fc4a02Krzysztof Kosiński * SVG <box3d> implementation
3f4f0d494ca026eab6c7bba188b98c8a74fc4a02Krzysztof Kosiński * Maximilian Albert <Anhalter42@gmx.de>
9f23cdd7a5ae710b8ba3a3f023386b65c98e6f61Jabiertxof * Lauris Kaplinski <lauris@kaplinski.com>
8e7816e2594857eb4a5456120b0cf24344fa9a99Jabiertxof * bulia byak <buliabyak@users.sf.net>
8e7816e2594857eb4a5456120b0cf24344fa9a99Jabiertxof * Copyright (C) 2007 Authors
8e7816e2594857eb4a5456120b0cf24344fa9a99Jabiertxof * Copyright (C) 1999-2002 Lauris Kaplinski
8e7816e2594857eb4a5456120b0cf24344fa9a99Jabiertxof * Copyright (C) 2000-2001 Ximian, Inc.
3f4f0d494ca026eab6c7bba188b98c8a74fc4a02Krzysztof Kosiński * Released under GNU GPL, read the file 'COPYING' for more information
#include "attributes.h"
#include "xml/document.h"
#include "box3d.h"
#include "box3d-side.h"
#include "box3d-context.h"
#include "proj_pt.h"
#include "transf_mat_3x4.h"
#include "perspective-line.h"
#include "inkscape.h"
#include "persp3d.h"
#include "line-geometry.h"
#include "persp3d-reference.h"
#include "uri.h"
#include "sp-guide.h"
#include "sp-namedview.h"
#include "preferences.h"
#include "desktop.h"
#include "desktop-handles.h"
#include "macros.h"
static Inkscape::XML::Node *box3d_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
box3d_get_type(void)
if (!type) {
sizeof(SPBox3DClass),
sizeof(SPBox3D),
return type;
if (!doc)
if (persp) {
switch (key) {
if (value) {
// FIXME: Is the following update doubled by some call in either persp3d.cpp or vanishing_point_new.cpp?
if (old_ref) {
if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
various other places (like the handlers in object-edit.cpp, vanishing-point.cpp, etc. */
static Inkscape::XML::Node *box3d_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
return repr;
static gchar *
for (SPObject *child = sp_object_first_child(SP_OBJECT (box)); child != NULL; child = SP_OBJECT_NEXT(child) ) {
if (item_coords) {
return box3d_get_perspective(box)->perspective_impl->tmat.image(proj_corner).affine() * i2d.inverse();
return box3d_get_perspective(box)->perspective_impl->tmat.image(proj_center).affine() * i2d.inverse();
* To keep the snappoint from jumping randomly between the two lines when the mouse pointer is close to
* their intersection, we remember the last snapped line and keep snapping to this specific line as long
Box3D::Line diag2(A, E); // diag2 is only taken into account if id equals -1, i.e., if we are snapping the center
for (int i = 0; i < num_snap_lines; ++i) {
bool within_tolerance = true;
for (int i = 0; i < num_snap_lines; ++i) {
within_tolerance = false;
for (int i = 0; i < num_snap_lines; ++i) {
snap_index = i;
if (within_tolerance) {
box3d_set_corner (SPBox3D *box, const guint id, Geom::Point const &new_pos, const Box3D::Axis movement, bool constrained) {
if (constrained) {
pt_proj = box3d_snap (box, id, pt_proj, box3d_get_proj_corner (id, box->save_corner0, box->save_corner7));
void box3d_set_center (SPBox3D *box, Geom::Point const &new_pos, Geom::Point const &old_pos, const Box3D::Axis movement, bool constrained) {
if (constrained) {
box->orig_corner0 = Proj::Pt3 ((movement & Box3D::X) ? pt_proj[Proj::X] - radx : box->orig_corner0[Proj::X],
box->orig_corner7 = Proj::Pt3 ((movement & Box3D::X) ? pt_proj[Proj::X] + radx : box->orig_corner7[Proj::X],
// FIXME: This can certainly be done more elegantly/efficiently than by a case-by-case analysis.
switch (axis) {
case Proj::X:
case Proj::Y:
case Proj::Z:
/* Auxiliary function: Checks whether the half-line from A to B crosses the line segment joining C and D */
if (!inters) {
z_orders[0] = a;
int tmp;
switch(central_axis) {
case Box3D::X:
if (!swapped) {
case Box3D::Y:
if (!swapped) {
case Box3D::Z:
if (!swapped) {
if (!swapped) {
box3d_set_new_z_orders_case1 (SPBox3D *box, int z_orders[6], Box3D::Axis central_axis, Box3D::Axis fin_axis) {
// note: in some of the case distinctions below we rely upon the fact that oaxis1 and oaxis2 are ordered
int inside1 = 0;
int inside2 = 0;
switch(central_axis) {
case Box3D::X:
if (!swapped) {
case Box3D::Y:
if (inside2 > 0) {
} else if (inside2 < 0) {
if (!swapped) {
case Box3D::Z:
if (inside2) {
if (!swapped) {
} else if (inside1) {
if (!swapped) {
if (!swapped) {
if (!swapped) {
box3d_set_new_z_orders_case2 (SPBox3D *box, int z_orders[6], Box3D::Axis central_axis, Box3D::Axis /*infinite_axis*/) {
switch(central_axis) {
case Box3D::X:
if (!swapped) {
if (!swapped) {
if (insidexy == 0) {
case Box3D::Y:
if (!swapped) {
case Box3D::Z:
if (!swapped) {
if (!swapped) {
if (box->orig_corner0[Proj::Z] > box->orig_corner7[Proj::Z]) // FIXME: Remove the need to distinguish signs among the cases
return ev;
pos1 = i;
pos2 = i;
if (!persp)
int num_finite = 0;
num_finite++;
switch (num_finite) {
switch (central_axis) {
case Box3D::Y:
case Box3D::Z:
case Box3D::X:
// TODO: If there are still errors in z-orders of everted boxes, we need to choose a variable corner
return sides;
// TODO: Check whether the box is everted in any direction and swap the sides opposite to this direction
box3d_pt_lies_in_PL_sector (SPBox3D const *box, Geom::Point const &pt, int id1, int id2, Box3D::Axis axis) {
int ret = 0;
return ret;
box3d_VP_lies_in_PL_sector (SPBox3D const *box, Proj::Axis vpdir, int id1, int id2, Box3D::Axis axis) {
/* ensure that the coordinates of corner0 and corner7 are in the correct order (to prevent everted boxes) */
return boxes;
Persp3D *
box3d_switch_perspectives(SPBox3D *box, Persp3D *old_persp, Persp3D *new_persp, bool recompute_corners) {
if (recompute_corners) {
SPGroup *
for (SPObject *child = sp_object_first_child(SP_OBJECT(box)); child != NULL; child = SP_OBJECT_NEXT(child) ) {
if (mask)
if (clip_path)