summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 833612d)
raw | patch | inline | side by side (parent: 833612d)
author | cilix42 <cilix42@users.sourceforge.net> | |
Mon, 6 Aug 2007 07:49:54 +0000 (07:49 +0000) | ||
committer | cilix42 <cilix42@users.sourceforge.net> | |
Mon, 6 Aug 2007 07:49:54 +0000 (07:49 +0000) |
diff --git a/src/axis-manip.cpp b/src/axis-manip.cpp
index 094da7dde8634909ff660a084f97a0b42e61b601..c2edbfb89d06da593b8bb2b55b3d189887149e26 100644 (file)
--- a/src/axis-manip.cpp
+++ b/src/axis-manip.cpp
Axis planes[3] = { XY, XZ, YZ };
FrontOrRear face_positions [2] = { FRONT, REAR };
+std::pair <Axis, Axis>
+get_remaining_axes (Axis axis) {
+ if (!is_single_axis_direction (axis)) return std::make_pair (NONE, NONE);
+ Axis plane = orth_plane (axis);
+ return std::make_pair (extract_first_axis_direction (plane), extract_second_axis_direction (plane));
+}
+
} // namespace Box3D
/*
diff --git a/src/axis-manip.h b/src/axis-manip.h
index 7ad716046286d9474d633af5925735748498a2a6..7461678d5321f2dd4814e64eb799b02c09dd3958 100644 (file)
--- a/src/axis-manip.h
+++ b/src/axis-manip.h
return pstring->str;
}
+std::pair <Axis, Axis> get_remaining_axes (Axis axis);
+
} // namespace Box3D
#endif /* !SEEN_AXIS_MANIP_H */
diff --git a/src/perspective3d.cpp b/src/perspective3d.cpp
index e5b1f62126f25983d026002cc3a8e5d3fefc3bbc..2137449373735c8a62dfec0f67fb6b95b37692f1 100644 (file)
--- a/src/perspective3d.cpp
+++ b/src/perspective3d.cpp
}
bool
-Perspective3D::operator==(Perspective3D const &other)
+Perspective3D::operator==(Perspective3D const &other) const
{
// Two perspectives are equal iff their vanishing points coincide and have identical states
return (*vp_x == *other.vp_x && *vp_y == *other.vp_y && *vp_z == *other.vp_z);
}
+bool
+Perspective3D::has_vanishing_point (VanishingPoint *vp)
+{
+ return (vp == vp_x || vp == vp_y || vp == vp_z);
+}
+
VanishingPoint *
Perspective3D::get_vanishing_point (Box3D::Axis const dir)
{
}
bool
-Perspective3D::has_box (const SP3DBox *box)
+Perspective3D::has_box (const SP3DBox *box) const
{
return (g_slist_find (this->boxes, box) != NULL);
}
+bool
+Perspective3D::all_boxes_occur_in_list (GSList *boxes_to_do)
+{
+ for (GSList *i = boxes; i != NULL; i = i->next) {
+ if (!g_slist_find (boxes_to_do, i->data)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+GSList *
+Perspective3D::boxes_occurring_in_list (GSList * list_of_boxes)
+{
+ GSList * result = NULL;
+ for (GSList *i = list_of_boxes; i != NULL; i = i->next) {
+ if (this->has_box (SP_3DBOX (i->data))) {
+ result = g_slist_prepend (result, i->data);
+ }
+ }
+ // we reverse so as to retain the same order as in list_of_boxes
+ return g_slist_reverse (result);
+}
+
/**
* Update the shape of a box after a handle was dragged or a VP was changed, according to the stored ratios.
*/
}
}
+// swallow the list of boxes from the other perspective and delete it
+void
+Perspective3D::absorb (Perspective3D *other)
+{
+ g_return_if_fail (*this == *other);
+
+ // FIXME: Is copying necessary? Is other->boxes invalidated when other is deleted below?
+ this->boxes = g_slist_concat (this->boxes, g_slist_copy (other->boxes));
+
+ // Should we delete the other perspective here or at the place from where absorb() is called?
+ delete other;
+ other = NULL;
+}
+
// FIXME: We get compiler errors when we try to move the code from sp_3dbox_get_perspective_string to this function
/***
gchar *
diff --git a/src/perspective3d.h b/src/perspective3d.h
index c3e07b23b3c0b357ee83d69de6e46c8b48444e35..4134b3fc1ffc59d970fa7914a26f6510efbc6bf8 100644 (file)
--- a/src/perspective3d.h
+++ b/src/perspective3d.h
#include "vanishing-point.h"
#include "svg/stringstream.h"
+#include <glib.h>
class SP3DBox;
Perspective3D(Perspective3D &other);
~Perspective3D();
- bool operator== (Perspective3D const &other);
+ bool operator== (Perspective3D const &other) const;
+ bool has_vanishing_point (VanishingPoint *vp);
VanishingPoint *get_vanishing_point (Box3D::Axis const dir);
Axis get_axis_of_VP (VanishingPoint *vp);
void set_vanishing_point (Box3D::Axis const dir, VanishingPoint const &pt);
void set_vanishing_point (Box3D::Axis const dir, gdouble pt_x, gdouble pt_y, gdouble dir_x, gdouble dir_y, VPState st);
void add_box (SP3DBox *box);
void remove_box (const SP3DBox *box);
- bool has_box (const SP3DBox *box);
+ bool has_box (const SP3DBox *box) const;
+ inline guint number_of_boxes () { return g_slist_length (boxes); }
void reshape_boxes (Box3D::Axis axes);
void update_box_reprs ();
+ /* convenience functions for interaction with dragging machinery: */
+ bool all_boxes_occur_in_list (GSList *boxes_to_do);
+ GSList * boxes_occurring_in_list (GSList * list_of_boxes);
+
+ void absorb (Perspective3D *other); // swallow the other perspective if both coincide
+
static gint counter; // for testing only
gint my_counter; // for testing only
static GSList * perspectives; // All existing 3D perspectives
+ // FIXME: Perspectives should be linked to the list of existing ones automatically in the constructor
+ // and removed in the destructor!
static void add_perspective (Box3D::Perspective3D * const persp);
static void remove_perspective (Box3D::Perspective3D * const persp);
- static Box3D::Perspective3D * find_perspective (Box3D::Perspective3D * const persp); // find an existing perspective whose VPs are equal to those of persp
+
+ /* find an existing perspective whose VPs are equal to those of persp */
+ static Box3D::Perspective3D * find_perspective (Box3D::Perspective3D * const persp);
static void print_debugging_info();
static Perspective3D * current_perspective;
index edf769c176388f9c6164836167639bc3fda1ad44..fa77d755fcef9959d29cdd5f7d35a8ea1e0084e1 100644 (file)
--- a/src/vanishing-point.cpp
+++ b/src/vanishing-point.cpp
* Vanishing point for 3D perspectives
*
* Authors:
+ * bulia byak <buliabyak@users.sf.net>
+ * Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
* Maximilian Albert <Anhalter42@gmx.de>
*
- * Copyright (C) 2007 authors
+ * Copyright (C) 2005-2007 authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <glibmm/i18n.h>
+
#include "vanishing-point.h"
#include "desktop-handles.h"
#include "box3d.h"
@@ -144,38 +148,202 @@ vp_drag_sel_modified (Inkscape::Selection *selection, guint flags, gpointer data
//drag->updateLines ();
}
+// auxiliary function
+static GSList *
+eliminate_remaining_boxes_of_persp_starting_from_list_position (GSList *boxes_to_do, const SP3DBox *start_box, const Perspective3D *persp)
+{
+ GSList *i = g_slist_find (boxes_to_do, start_box);
+ g_return_val_if_fail (i != NULL, boxes_to_do);
+
+ SP3DBox *box;
+ GSList *successor;
+
+ i = i->next;
+ while (i != NULL) {
+ successor = i->next;
+ box = SP_3DBOX (i->data);
+ if (persp->has_box (box)) {
+ boxes_to_do = g_slist_remove (boxes_to_do, box);
+ }
+ i = successor;
+ }
+
+ return boxes_to_do;
+}
+
+static bool
+have_VPs_of_same_perspective (VPDragger *dr1, VPDragger *dr2)
+{
+ Perspective3D *persp;
+ for (GSList *i = dr1->vps; i != NULL; i = i->next) {
+ persp = get_persp_of_VP ((VanishingPoint *) i->data);
+ if (dr2->hasPerspective (persp)) {
+ return true;
+ }
+ }
+ return false;
+}
+
static void
vp_knot_moved_handler (SPKnot *knot, NR::Point const *ppointer, guint state, gpointer data)
{
- g_warning ("Please implement vp_knot_moved_handler.\n");
VPDragger *dragger = (VPDragger *) data;
- //VPDrag *drag = dragger->parent;
+ VPDrag *drag = dragger->parent;
NR::Point p = *ppointer;
+ // FIXME: take from prefs
+ double snap_dist = SNAP_DIST / drag->desktop->current_zoom();
+
+ if (!(state & GDK_SHIFT_MASK)) {
+ // without Shift; see if we need to snap to another dragger
+ for (GList *di = dragger->parent->draggers; di != NULL; di = di->next) {
+ VPDragger *d_new = (VPDragger *) di->data;
+ if ((d_new != dragger) && (NR::L2 (d_new->point - p) < snap_dist)) {
+ if (have_VPs_of_same_perspective (dragger, d_new)) {
+ // this would result in degenerate boxes, which we disallow for the time being
+ continue;
+ }
+
+ // update positions ...
+ for (GSList *j = dragger->vps; j != NULL; j = j->next) {
+ ((VanishingPoint *) j->data)->set_pos (d_new->point);
+ }
+ // ... join lists of VPs ...
+ // FIXME: Do we have to copy the second list (i.e, is it invalidated when dragger is deleted below)?
+ d_new->vps = g_slist_concat (d_new->vps, g_slist_copy (dragger->vps));
+
+ // ... delete old dragger ...
+ drag->draggers = g_list_remove (drag->draggers, dragger);
+ delete dragger;
+ dragger = NULL;
+
+ // ... and merge any duplicate perspectives
+ d_new->mergePerspectives();
+
+ // TODO: Update the new merged dragger
+ //d_new->updateKnotShape ();
+ //d_new->updateTip ();
+
+ d_new->reshapeBoxes (p, Box3D::XYZ);
+ d_new->updateBoxReprs ();
+
+ // TODO: Undo machinery; this doesn't work yet because perspectives must be created and
+ // deleted according to changes in the svg representation, not based on any user input
+ // as is currently the case.
+
+ //sp_document_done (sp_desktop_document (drag->desktop), SP_VERB_CONTEXT_3DBOX,
+ // _("Merge vanishing points"));
+
+ return;
+ }
+ }
+ }
+
dragger->point = p;
dragger->reshapeBoxes (p, Box3D::XYZ);
+ dragger->updateBoxReprs ();
+
//dragger->parent->updateLines ();
//drag->local_change = false;
}
+/***
static void
+vp_knot_clicked_handler(SPKnot *knot, guint state, gpointer data)
+{
+ VPDragger *dragger = (VPDragger *) data;
+}
+***/
+
+void
vp_knot_grabbed_handler (SPKnot *knot, unsigned int state, gpointer data)
{
VPDragger *dragger = (VPDragger *) data;
+ VPDrag *drag = dragger->parent;
//sp_canvas_force_full_redraw_after_interruptions(dragger->parent->desktop->canvas, 5);
+
+ if ((state & GDK_SHIFT_MASK) && !drag->hasEmptySelection()) { // FIXME: Is the second check necessary?
+
+ if (drag->allBoxesAreSelected (dragger)) {
+ // if all of the boxes linked to dragger are selected, we don't need to split it
+ return;
+ }
+
+ // we are Shift-dragging; unsnap if we carry more than one VP
+
+ // FIXME: Should we distinguish between the following cases:
+ // 1) there are several VPs in a dragger
+ // 2) there is only a single VP but several boxes linked to it
+ // ?
+ // Or should we simply unlink all selected boxes? Currently we do the latter.
+ if (dragger->numberOfBoxes() > 1) {
+ // create a new dragger
+ VPDragger *dr_new = new VPDragger (drag, dragger->point, NULL);
+ drag->draggers = g_list_prepend (drag->draggers, dr_new);
+
+ // move all the VPs from dragger to dr_new
+ dr_new->vps = dragger->vps;
+ dragger->vps = NULL;
+
+ /* now we move all selected boxes back to the current dragger (splitting perspectives
+ if they also have unselected boxes) so that they are further reshaped during dragging */
+
+ GSList *boxes_to_do = drag->selectedBoxesWithVPinDragger (dr_new);
+
+ for (GSList *i = boxes_to_do; i != NULL; i = i->next) {
+ SP3DBox *box = SP_3DBOX (i->data);
+ Perspective3D *persp = get_persp_of_box (box);
+ VanishingPoint *vp = dr_new->getVPofPerspective (persp);
+ if (vp == NULL) {
+ g_warning ("VP is NULL. We should be okay, though.\n");
+ }
+ if (persp->all_boxes_occur_in_list (boxes_to_do)) {
+ // if all boxes of persp are selected, we can simply move the VP from dr_new back to dragger
+ dr_new->removeVP (vp);
+ dragger->addVP (vp);
+
+ // some cleaning up for efficiency
+ boxes_to_do = eliminate_remaining_boxes_of_persp_starting_from_list_position (boxes_to_do, box, persp);
+ } else {
+ /* otherwise the unselected boxes need to stay linked to dr_new; thus we
+ create a new perspective and link the VPs to the correct draggers */
+ Perspective3D *persp_new = new Perspective3D (*persp);
+ Perspective3D::add_perspective (persp_new);
+
+ Axis vp_axis = persp->get_axis_of_VP (vp);
+ dragger->addVP (persp_new->get_vanishing_point (vp_axis));
+ std::pair<Axis, Axis> rem_axes = get_remaining_axes (vp_axis);
+ drag->addDragger (persp->get_vanishing_point (rem_axes.first));
+ drag->addDragger (persp->get_vanishing_point (rem_axes.second));
+
+ // now we move the selected boxes from persp to persp_new
+ GSList * selected_boxes_of_perspective = persp->boxes_occurring_in_list (boxes_to_do);
+ for (GSList *j = selected_boxes_of_perspective; j != NULL; j = j->next) {
+ persp->remove_box (SP_3DBOX (j->data));
+ persp_new->add_box (SP_3DBOX (j->data));
+ }
+
+ // cleaning up
+ boxes_to_do = eliminate_remaining_boxes_of_persp_starting_from_list_position (boxes_to_do, box, persp);
+ }
+ }
+
+ // TODO: Something is still wrong with updating the boxes' representations after snapping
+ //dr_new->updateBoxReprs ();
+ }
+ }
+
+ // TODO: Update the tips
}
static void
vp_knot_ungrabbed_handler (SPKnot *knot, guint state, gpointer data)
{
- g_warning ("Please fully implement vp_knot_ungrabbed_handler.\n");
-
VPDragger *dragger = (VPDragger *) data;
- //VPDrag *drag = dragger->parent;
//sp_canvas_end_forced_full_redraws(dragger->parent->desktop->canvas);
VPDragger::VPDragger(VPDrag *parent, NR::Point p, VanishingPoint *vp)
{
- if (vp == NULL) {
- g_print ("VP used to create the VPDragger is NULL. This can happen when shift-dragging knots.\n");
- g_print ("How to correctly handle this? Should we just ignore it, as we currently do?\n");
- //g_assert (vp != NULL);
- }
this->vps = NULL;
this->parent = parent;
VPDragger::addVP (VanishingPoint *vp)
{
if (vp == NULL) {
- g_print ("No VP present in addVP. We return without adding a new VP to the list.\n");
return;
}
+ if (g_slist_find (this->vps, vp)) {
+ // don't add the same VP twice
+ return;
+ }
+
vp->set_pos (this->point);
this->vps = g_slist_prepend (this->vps, vp);
//this->updateTip();
}
+// returns the VP contained in the dragger that belongs to persp
+VanishingPoint *
+VPDragger::getVPofPerspective (Perspective3D *persp)
+{
+ for (GSList *i = vps; i != NULL; i = i->next) {
+ if (persp->has_vanishing_point ((VanishingPoint *) i->data)) {
+ return ((VanishingPoint *) i->data);
+ }
+ }
+ return NULL;
+}
+
+bool
+VPDragger::hasBox(const SP3DBox *box)
+{
+ for (GSList *i = this->vps; i != NULL; i = i->next) {
+ if (get_persp_of_VP ((VanishingPoint *) i->data)->has_box (box)) return true;
+ }
+ return false;
+}
+
+guint
+VPDragger::numberOfBoxes ()
+{
+ guint num = 0;
+ for (GSList *i = this->vps; i != NULL; i = i->next) {
+ num += get_persp_of_VP ((VanishingPoint *) i->data)->number_of_boxes ();
+ }
+ return num;
+}
+
+bool
+VPDragger::hasPerspective (const Perspective3D *persp)
+{
+ for (GSList *i = this->vps; i != NULL; i = i->next) {
+ if (*persp == *get_persp_of_VP ((VanishingPoint *) i->data)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+VPDragger::mergePerspectives ()
+{
+ Perspective3D *persp1, *persp2;
+ GSList * successor = NULL;
+ for (GSList *i = this->vps; i != NULL; i = i->next) {
+ persp1 = get_persp_of_VP ((VanishingPoint *) i->data);
+ for (GSList *j = i->next; j != NULL; j = successor) {
+ // if the perspective is deleted, the VP is invalidated, too, so we must store its successor beforehand
+ successor = j->next;
+ persp2 = get_persp_of_VP ((VanishingPoint *) j->data);
+ if (*persp1 == *persp2) {
+ persp1->absorb (persp2); // persp2 is deleted; hopefully this doesn't screw up the list of vanishing points and thus the loops
+ }
+ }
+ }
+}
+
void
VPDragger::reshapeBoxes (NR::Point const &p, Box3D::Axis axes)
{
}
}
+
+/**
+ * Returns true if all boxes that are linked to a VP in the dragger are selected
+ */
+bool
+VPDrag::allBoxesAreSelected (VPDragger *dragger) {
+ GSList *selected_boxes = (GSList *) dragger->parent->selection->itemList();
+ for (GSList *i = dragger->vps; i != NULL; i = i->next) {
+ if (!get_persp_of_VP ((VanishingPoint *) i->data)->all_boxes_occur_in_list (selected_boxes)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+GSList *
+VPDrag::selectedBoxesWithVPinDragger (VPDragger *dragger)
+{
+ GSList *sel_boxes = g_slist_copy ((GSList *) dragger->parent->selection->itemList());
+ for (GSList const *i = sel_boxes; i != NULL; i = i->next) {
+ SP3DBox *box = SP_3DBOX (i->data);
+ if (!dragger->hasBox (box)) {
+ sel_boxes = g_slist_remove (sel_boxes, box);
+ }
+ }
+ return sel_boxes;
+}
+
+
/**
* If there already exists a dragger within MERGE_DIST of p, add the VP to it;
* otherwise create new dragger and add it to draggers list
diff --git a/src/vanishing-point.h b/src/vanishing-point.h
index 58b3b142727c8fd93b8f1b8b28d8547e5879e818..76299541ab7e7a11fc57b60183a595867542ed56 100644 (file)
--- a/src/vanishing-point.h
+++ b/src/vanishing-point.h
#include "line-geometry.h" // TODO: Remove this include as soon as we don't need create_canvas_(point|line) any more.
+class SP3DBox;
+
namespace Box3D {
enum VPState {
private:
};
+class Perspective3D;
class VPDrag;
struct VPDragger {
void addVP(VanishingPoint *vp);
void removeVP(VanishingPoint *vp);
+ /* returns the VP of the dragger that belongs to the given perspective */
+ VanishingPoint *getVPofPerspective (Perspective3D *persp);
+
+ bool hasBox (const SP3DBox *box);
+ guint numberOfBoxes(); // the number of boxes linked to all VPs of the dragger
+
+ bool hasPerspective (const Perspective3D *perps);
+ void mergePerspectives (); // remove duplicate perspectives
void reshapeBoxes(NR::Point const &p, Box3D::Axis axes);
void updateBoxReprs();
void updateDraggers ();
//void updateLines ();
+ inline bool hasEmptySelection() { return this->selection->isEmpty(); }
+ bool allBoxesAreSelected (VPDragger *dragger);
+ GSList * selectedBoxesWithVPinDragger (VPDragger *dragger);
+
+ // FIXME: Should this be private? (It's the case with the corresponding function in gradient-drag.h)
+ // But vp_knot_grabbed_handler
+ void addDragger (VanishingPoint *vp);
+
private:
//void deselect_all();
//void addLine (NR::Point p1, NR::Point p2, guint32 rgba);
- void addDragger (VanishingPoint *vp);
Inkscape::Selection *selection;
sigc::connection sel_changed_connection;