/*
* 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>
* Abhishek Sharma
* Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2005-2007 authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "vanishing-point.h"
#include "desktop.h"
#include "display/sp-canvas-item.h"
#include "display/sp-ctrlline.h"
#include "ui/tools/tool-base.h"
#include "perspective-line.h"
#include "ui/shape-editor.h"
#include "snap.h"
#include "sp-namedview.h"
#include "ui/control-manager.h"
#include "document-undo.h"
#include "verbs.h"
using Inkscape::CTLINE_PRIMARY;
using Inkscape::CTLINE_SECONDARY;
using Inkscape::CTLINE_TERTIARY;
using Inkscape::CTRL_TYPE_ANCHOR;
using Inkscape::ControlManager;
using Inkscape::CtrlLineType;
using Inkscape::DocumentUndo;
namespace Box3D {
// screen pixels between knots when they snap:
// absolute distance between gradient points for them to become a single dragger when the drag is created:
// knot shapes corresponding to GrPointType enum
SP_KNOT_SHAPE_SQUARE, // VP_FINITE
SP_KNOT_SHAPE_CIRCLE //VP_INFINITE
};
static void
{
drag->updateDraggers();
drag->updateLines();
drag->updateBoxReprs();
}
static void
{
drag->updateLines ();
//drag->updateBoxReprs();
drag->updateDraggers ();
}
static bool
{
return true;
}
}
return false;
}
static void
{
// FIXME: take from prefs
/*
* We use dragging_started to indicate if we have already checked for the need to split Draggers up.
* This only has the purpose of avoiding costly checks in the routine below.
*/
/* with Shift; if there is more than one box linked to this VP
we need to split it and create a new perspective */
for (std::set<VanishingPoint*, less_ptr>::iterator vp = sel_vps.begin(); vp != sel_vps.end(); ++vp) {
// for each VP that has selected boxes:
// we create a new perspective ...
Persp3D *new_persp = persp3d_create_xml_element (dragger->parent->document, old_persp->perspective_impl);
/* ... unlink the boxes from the old one and
FIXME: We need to unlink the _un_selected boxes of each VP so that
the correct boxes are kept with the VP being moved */
/* if a box in the VP is unselected, move it to the
newly created perspective so that it doesn't get dragged **/
}
}
}
// FIXME: Do we need to create a new dragger as well?
dragger->updateZOrders ();
_("Split vanishing points"));
return;
}
}
if (!(state & GDK_SHIFT_MASK)) {
// without Shift; see if we need to snap to another dragger
for (std::vector<VPDragger *>::const_iterator di = dragger->parent->draggers.begin(); di != dragger->parent->draggers.end(); ++di) {
// this would result in degenerate boxes, which we disallow for the time being
continue;
}
// update positions ... (this is needed so that the perspectives are detected as identical)
// FIXME: This is called a bit too often, isn't it?
}
// ... join lists of VPs ...
// ... delete old dragger ...
drag->draggers.erase(std::remove(drag->draggers.begin(), drag->draggers.end(), dragger),drag->draggers.end());
delete dragger;
// ... and merge any duplicate perspectives
// TODO: Update the new merged dragger
d_new->updateZOrders ();
drag->updateLines ();
// 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.
_("Merge vanishing points"));
return;
}
}
}
// We didn't hit the return statement above, so we didn't snap to another dragger. Therefore we'll now try a regular snap
// Regardless of the status of the SHIFT key, we will try to snap; Here SHIFT does not disable snapping, as the shift key
// has a different purpose in this context (see above)
Inkscape::SnappedPoint s = m.freeSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_OTHER_HANDLE));
m.unSetup();
if (s.getSnapped()) {
p = s.getPoint();
}
dragger->parent->updateBoxHandles (); // FIXME: Only update the handles of boxes on this dragger (not on all)
dragger->updateZOrders();
drag->updateLines();
dragger->dragging_started = true;
}
static void
{
}
static void
{
dragger->dragging_started = false;
(*i).updateBoxReprs();
(*i).updatePerspRepr();
}
// TODO: Update box's paths and svg representation
// TODO: Undo machinery!!
_("3D box: Move vanishing point"));
}
// FIXME: Rename to something more meaningful!
void
}
}
}
return sel_boxes;
}
point(p),
point_original(p),
dragging_started(false),
vps()
{
// create the knot
this->knot->updateCtrl();
// move knot to the given point
// connect knot's signals
this->_moved_connection = this->knot->moved_signal.connect(sigc::bind(sigc::ptr_fun(vp_knot_moved_handler), this));
this->_grabbed_connection = this->knot->grabbed_signal.connect(sigc::bind(sigc::ptr_fun(vp_knot_grabbed_handler), this));
this->_ungrabbed_connection = this->knot->ungrabbed_signal.connect(sigc::bind(sigc::ptr_fun(vp_knot_ungrabbed_handler), this));
// add the initial VP (which may be NULL!)
}
}
{
// disconnect signals
this->_moved_connection.disconnect();
this->_grabbed_connection.disconnect();
this->_ungrabbed_connection.disconnect();
/* unref should call destroy */
knot_unref(this->knot);
}
/**
Updates the statusbar tip of the dragger knot, based on its draggables
*/
void
{
}
this->knot->tip = g_strdup_printf (ngettext("<b>Finite</b> vanishing point shared by <b>%d</b> box",
"<b>Finite</b> vanishing point shared by <b>%d</b> boxes; drag with <b>Shift</b> to separate selected box(es)",
num),
num);
} else {
// This won't make sense any more when infinite VPs are not shown on the canvas,
// but currently we update the status message anyway
this->knot->tip = g_strdup_printf (ngettext("<b>Infinite</b> vanishing point shared by <b>%d</b> box",
"<b>Infinite</b> vanishing point shared by <b>%d</b> boxes; drag with <b>Shift</b> to separate selected box(es)",
num),
num);
}
} else {
char *desc2 = g_strdup_printf (ngettext("shared by <b>%d</b> box; drag with <b>Shift</b> to separate selected box(es)",
"shared by <b>%d</b> boxes; drag with <b>Shift</b> to separate selected box(es)",
num),
num);
}
}
/**
* Adds a vanishing point to the dragger (also updates the position if necessary);
* the perspective is stored separately, too, for efficiency in updating boxes.
*/
void
{
// don't add infinite VPs; don't add the same VP twice
return;
}
if (update_pos) {
}
this->updateTip();
}
void
{
}
this->updateTip();
}
return &(*vp);
}
}
return NULL;
}
// FIXME: Should we take the selection from the parent VPDrag? I guess it shouldn't make a difference.
if (box) {
if (vp) {
}
}
}
return sel_vps;
}
{
}
return num;
}
bool
{
return true;
}
}
return false;
}
void
{
persp1 = (*i).get_perspective();
persp2 = (*j).get_perspective();
/* don't merge a perspective with itself */
continue;
}
/* if perspectives coincide but are not the same, merge them */
}
}
}
}
void
{
(*i).updateBoxDisplays();
}
}
void
{
}
}
void
{
persp3d_update_z_orders((*i).get_perspective());
}
}
void
}
}
{
this->show_lines = true;
this->front_or_rear_lines = 0x1;
this->dragging = false;
(gpointer)this )
);
(gpointer)this )
);
this->updateDraggers ();
this->updateLines ();
}
{
this->sel_changed_connection.disconnect();
this->sel_modified_connection.disconnect();
for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
delete (*i);
}
for (std::vector<SPCtrlLine *>::const_iterator i = this->lines.begin(); i != this->lines.end(); ++i) {
}
}
/**
* Select the dragger that has the given VP.
*/
{
for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
// TODO: Should we compare the pointers or the VPs themselves!?!?!?!
if (*j == vp) {
return (dragger);
}
}
}
return NULL;
}
void
{
g_print ("=== VPDrag info: =================================\n");
for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
(*i)->printVPs();
g_print ("========\n");
}
g_print ("=================================================\n");
}
/**
* Regenerates the draggers list from the current selection; is called when selection is changed or modified
*/
void
{
if (this->dragging)
return;
// delete old draggers
for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
delete (*i);
}
if (box) {
for (int i = 0; i < 3; ++i) {
addDragger (vp);
}
}
}
}
/**
Regenerates the lines list from the current selection; is called on each move
of a dragger, so that lines are always in sync with the actual perspective
*/
void
{
// delete old lines
for (std::vector<SPCtrlLine *>::const_iterator i = this->lines.begin(); i != this->lines.end(); ++i) {
}
// do nothing if perspective lines are currently disabled
if (this->show_lines == 0) return;
if (box) {
}
}
}
void
{
// FIXME: Is there a way to update the knots without accessing the
// (previously) statically linked function KnotHolder::update_knots?
return; // no selection
// Currently we only show handles if a single box is selected
return;
}
}
}
void
{
for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
(*i).updateBoxReprs();
}
}
}
void
{
for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
(*i).updateBoxDisplays();
}
}
}
/**
* Depending on the value of all_lines, draw the front and/or rear perspective lines starting from the given corners.
*/
void VPDrag::drawLinesForFace(const SPBox3D *box, Proj::Axis axis) //, guint corner1, guint corner2, guint corner3, guint corner4)
{
switch (axis) {
// TODO: Make color selectable by user
case Proj::X:
break;
case Proj::Y:
break;
case Proj::Z:
break;
default:
}
// draw perspective lines for finite VPs
if (this->front_or_rear_lines & 0x1) {
// draw 'front' perspective lines
}
if (this->front_or_rear_lines & 0x2) {
// draw 'rear' perspective lines
}
} else {
// draw perspective lines for infinite VPs
// some perspective lines s are outside the canvas; currently we don't draw any of them
return;
}
if (this->front_or_rear_lines & 0x1) {
// draw 'front' perspective lines
}
if (this->front_or_rear_lines & 0x2) {
// draw 'rear' perspective lines
}
}
}
/**
* 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
* We also store the corresponding perspective in case it is not already present.
*/
void
{
// don't create draggers for infinite vanishing points
return;
}
for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
// distance is small, merge this draggable into dragger, no need to create new dragger
return;
}
}
// fixme: draggers should be added AFTER the last one: this way tabbing through them will be from begin to end.
}
void
{
// iterate over all VP in all draggers and replace persp2 with persp1
for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
if ((*j).get_perspective() == persp2) {
(*j).set_perspective(persp1);
}
}
}
}
{
SPCtrlLine *line = ControlManager::getManager().createControlLine(SP_ACTIVE_DESKTOP->getControls(), p1, p2, type);
}
} // namespace Box3D
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :