summaryrefslogtreecommitdiffstats
path: root/src/vanishing-point.cpp
diff options
context:
space:
mode:
authorMaximilian Albert <maximilian.albert@gmail.com>2007-08-06 07:37:24 +0000
committercilix42 <cilix42@users.sourceforge.net>2007-08-06 07:37:24 +0000
commitde43f9fc6fc4f6f8e716924c7c6f1242d4b036a3 (patch)
tree8b0b862bd0b0eea74d9e1cdc04c7b833df75c54c /src/vanishing-point.cpp
parentWorkaround for some segfaults: Store perspectives globally instead of in each... (diff)
downloadinkscape-de43f9fc6fc4f6f8e716924c7c6f1242d4b036a3.tar.gz
inkscape-de43f9fc6fc4f6f8e716924c7c6f1242d4b036a3.zip
First stage of draggable vanishing points (no snapping/unsnapping yet)
(bzr r3391)
Diffstat (limited to 'src/vanishing-point.cpp')
-rw-r--r--src/vanishing-point.cpp339
1 files changed, 339 insertions, 0 deletions
diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp
index 5f40936cf..edf769c17 100644
--- a/src/vanishing-point.cpp
+++ b/src/vanishing-point.cpp
@@ -12,9 +12,31 @@
*/
#include "vanishing-point.h"
+#include "desktop-handles.h"
+#include "box3d.h"
namespace Box3D {
+#define VP_KNOT_COLOR_NORMAL 0xffffff00
+#define VP_KNOT_COLOR_SELECTED 0x0000ff00
+
+#define VP_LINE_COLOR_FILL 0x0000ff7f
+#define VP_LINE_COLOR_STROKE_X 0xff00007f
+#define VP_LINE_COLOR_STROKE_Y 0x0000ff7f
+#define VP_LINE_COLOR_STROKE_Z 0xffff007f
+
+// screen pixels between knots when they snap:
+#define SNAP_DIST 5
+
+// absolute distance between gradient points for them to become a single dragger when the drag is created:
+#define MERGE_DIST 0.1
+
+// knot shapes corresponding to GrPointType enum
+SPKnotShapeType vp_knot_shapes [] = {
+ SP_KNOT_SHAPE_SQUARE, // VP_FINITE
+ SP_KNOT_SHAPE_CIRCLE //VP_INFINITE
+};
+
// FIXME: We should always require to have both the point (for finite VPs)
// and the direction (for infinite VPs) set. Otherwise toggling
// shows very unexpected behaviour.
@@ -45,6 +67,8 @@ VanishingPoint::VanishingPoint(VanishingPoint const &rhs) : NR::Point (rhs)
this->v_dir = rhs.v_dir;
}
+VanishingPoint::~VanishingPoint () {}
+
bool VanishingPoint::operator== (VanishingPoint const &other)
{
// Should we compare the parent perspectives, too? Probably not.
@@ -98,6 +122,321 @@ void VanishingPoint::draw(Box3D::Axis const axis)
}
}
+static void
+vp_drag_sel_changed(Inkscape::Selection *selection, gpointer data)
+{
+ VPDrag *drag = (VPDrag *) data;
+ drag->updateDraggers ();
+ //drag->updateLines ();
+}
+
+static void
+vp_drag_sel_modified (Inkscape::Selection *selection, guint flags, gpointer data)
+{
+ VPDrag *drag = (VPDrag *) data;
+ /***
+ if (drag->local_change) {
+ drag->local_change = false;
+ } else {
+ drag->updateDraggers ();
+ }
+ ***/
+ //drag->updateLines ();
+}
+
+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;
+
+ NR::Point p = *ppointer;
+
+ dragger->point = p;
+
+ dragger->reshapeBoxes (p, Box3D::XYZ);
+ //dragger->parent->updateLines ();
+
+ //drag->local_change = false;
+}
+
+static void
+vp_knot_grabbed_handler (SPKnot *knot, unsigned int state, gpointer data)
+{
+ VPDragger *dragger = (VPDragger *) data;
+
+ //sp_canvas_force_full_redraw_after_interruptions(dragger->parent->desktop->canvas, 5);
+}
+
+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);
+
+ dragger->point_original = dragger->point = knot->pos;
+
+ /***
+ VanishingPoint *vp;
+ for (GSList *i = dragger->vps; i != NULL; i = i->next) {
+ vp = (VanishingPoint *) i->data;
+ vp->set_pos (knot->pos);
+ }
+ ***/
+
+ dragger->parent->updateDraggers ();
+ dragger->updateBoxReprs ();
+
+ // TODO: Update box's paths and svg representation
+
+ // TODO: Undo machinery!!
+}
+
+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;
+
+ this->point = p;
+ this->point_original = p;
+
+ // create the knot
+ this->knot = sp_knot_new (parent->desktop, NULL);
+ this->knot->setMode(SP_KNOT_MODE_XOR);
+ this->knot->setFill(VP_KNOT_COLOR_NORMAL, VP_KNOT_COLOR_NORMAL, VP_KNOT_COLOR_NORMAL);
+ this->knot->setStroke(0x000000ff, 0x000000ff, 0x000000ff);
+ sp_knot_update_ctrl(this->knot);
+
+ // move knot to the given point
+ sp_knot_set_position (this->knot, &this->point, SP_KNOT_STATE_NORMAL);
+ sp_knot_show (this->knot);
+
+ // connect knot's signals
+ g_signal_connect (G_OBJECT (this->knot), "moved", G_CALLBACK (vp_knot_moved_handler), this);
+ /***
+ g_signal_connect (G_OBJECT (this->knot), "clicked", G_CALLBACK (vp_knot_clicked_handler), this);
+ ***/
+ g_signal_connect (G_OBJECT (this->knot), "grabbed", G_CALLBACK (vp_knot_grabbed_handler), this);
+ g_signal_connect (G_OBJECT (this->knot), "ungrabbed", G_CALLBACK (vp_knot_ungrabbed_handler), this);
+ /***
+ g_signal_connect (G_OBJECT (this->knot), "doubleclicked", G_CALLBACK (vp_knot_doubleclicked_handler), this);
+ ***/
+
+ // add the initial VP (which may be NULL!)
+ this->addVP (vp);
+ //updateKnotShape();
+}
+
+VPDragger::~VPDragger()
+{
+ // unselect if it was selected
+ //this->parent->setDeselected(this);
+
+ // disconnect signals
+ g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_moved_handler), this);
+ /***
+ g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_clicked_handler), this);
+ ***/
+ g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_grabbed_handler), this);
+ g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_ungrabbed_handler), this);
+ /***
+ g_signal_handlers_disconnect_by_func(G_OBJECT(this->knot), (gpointer) G_CALLBACK (vp_knot_doubleclicked_handler), this);
+ ***/
+
+ /* unref should call destroy */
+ g_object_unref (G_OBJECT (this->knot));
+
+ g_slist_free (this->vps);
+ this->vps = NULL;
+}
+
+/**
+ * Adds a vanishing point to the dragger (also updates the position)
+ */
+void
+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;
+ }
+ vp->set_pos (this->point);
+ this->vps = g_slist_prepend (this->vps, vp);
+
+ //this->updateTip();
+}
+
+void
+VPDragger::removeVP (VanishingPoint *vp)
+{
+ if (vp == NULL) {
+ g_print ("NULL vanishing point will not be removed.\n");
+ return;
+ }
+ g_assert (this->vps != NULL);
+ this->vps = g_slist_remove (this->vps, vp);
+
+ //this->updateTip();
+}
+
+void
+VPDragger::reshapeBoxes (NR::Point const &p, Box3D::Axis axes)
+{
+ Perspective3D *persp;
+ for (GSList const* i = this->vps; i != NULL; i = i->next) {
+ VanishingPoint *vp = (VanishingPoint *) i->data;
+ // TODO: We can extract the VP directly from the box's perspective. Is that vanishing point identical to 'vp'?
+ // Or is there duplicated information? If so, remove it and simplify the whole construction!
+ vp->set_pos(p);
+ persp = get_persp_of_VP (vp);
+ Box3D::Axis axis = persp->get_axis_of_VP (vp);
+ get_persp_of_VP (vp)->reshape_boxes (axis); // FIXME: we should only update the direction of the VP
+ }
+}
+
+void
+VPDragger::updateBoxReprs ()
+{
+ for (GSList *i = this->vps; i != NULL; i = i->next) {
+ Box3D::get_persp_of_VP ((VanishingPoint *) i->data)->update_box_reprs ();
+ }
+}
+
+VPDrag::VPDrag (SPDesktop *desktop)
+{
+ this->desktop = desktop;
+ this->draggers = NULL;
+ this->selection = sp_desktop_selection(desktop);
+
+ this->sel_changed_connection = this->selection->connectChanged(
+ sigc::bind (
+ sigc::ptr_fun(&vp_drag_sel_changed),
+ (gpointer)this )
+
+ );
+ this->sel_modified_connection = this->selection->connectModified(
+ sigc::bind(
+ sigc::ptr_fun(&vp_drag_sel_modified),
+ (gpointer)this )
+ );
+
+ this->updateDraggers ();
+ //this->updateLines ();
+}
+
+VPDrag::~VPDrag()
+{
+ this->sel_changed_connection.disconnect();
+ this->sel_modified_connection.disconnect();
+
+ for (GList *l = this->draggers; l != NULL; l = l->next) {
+ delete ((VPDragger *) l->data);
+ }
+ g_list_free (this->draggers);
+ this->draggers = NULL;
+}
+
+/**
+ * Select the dragger that has the given VP.
+ */
+VPDragger *
+VPDrag::getDraggerFor (VanishingPoint const &vp)
+{
+ for (GList const* i = this->draggers; i != NULL; i = i->next) {
+ VPDragger *dragger = (VPDragger *) i->data;
+ for (GSList const* j = dragger->vps; j != NULL; j = j->next) {
+ VanishingPoint *vp2 = (VanishingPoint *) j->data;
+ g_assert (vp2 != NULL);
+
+ // TODO: Should we compare the pointers or the VPs themselves!?!?!?!
+ //if ((*vp2) == vp) {
+ if (vp2 == &vp) {
+ return (dragger);
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Regenerates the draggers list from the current selection; is called when selection is changed or modified
+ */
+void
+VPDrag::updateDraggers ()
+{
+ /***
+ while (selected) {
+ selected = g_list_remove(selected, selected->data);
+ }
+ ***/
+ // delete old draggers
+ for (GList const* i = this->draggers; i != NULL; i = i->next) {
+ delete ((VPDragger *) i->data);
+ }
+ g_list_free (this->draggers);
+ this->draggers = NULL;
+
+ g_return_if_fail (this->selection != NULL);
+
+ for (GSList const* i = this->selection->itemList(); i != NULL; i = i->next) {
+ SPItem *item = SP_ITEM(i->data);
+ //SPStyle *style = SP_OBJECT_STYLE (item);
+
+ if (!SP_IS_3DBOX (item)) continue;
+ SP3DBox *box = SP_3DBOX (item);
+
+ // FIXME: Get the VPs from the selection!!!!
+ //addDragger (Box3D::Perspective3D::current_perspective->get_vanishing_point(Box3D::X));
+ //addDragger (Box3D::Perspective3D::current_perspective->get_vanishing_point(Box3D::Y));
+ //addDragger (Box3D::Perspective3D::current_perspective->get_vanishing_point(Box3D::Z));
+
+ //Box3D::Perspective3D *persp = box->perspective;
+ Box3D::Perspective3D *persp = Box3D::get_persp_of_box (box);
+ addDragger (persp->get_vanishing_point(Box3D::X));
+ addDragger (persp->get_vanishing_point(Box3D::Y));
+ addDragger (persp->get_vanishing_point(Box3D::Z));
+ }
+}
+
+/**
+ * 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
+ */
+void
+VPDrag::addDragger (VanishingPoint *vp)
+{
+ if (vp == NULL) {
+ g_print ("Warning: The VP in addDragger is already NULL. Aborting.\n)");
+ g_assert (vp != NULL);
+ }
+ NR::Point p = vp->get_pos();
+
+ for (GList *i = this->draggers; i != NULL; i = i->next) {
+ VPDragger *dragger = (VPDragger *) i->data;
+ if (NR::L2 (dragger->point - p) < MERGE_DIST) {
+ // distance is small, merge this draggable into dragger, no need to create new dragger
+ dragger->addVP (vp);
+ //dragger->updateKnotShape();
+ return;
+ }
+ }
+
+ VPDragger *new_dragger = new VPDragger(this, p, vp);
+ // fixme: draggers should be added AFTER the last one: this way tabbing through them will be from begin to end.
+ this->draggers = g_list_append (this->draggers, new_dragger);
+}
+
} // namespace Box3D
/*