diff --git a/src/sp-shape.cpp b/src/sp-shape.cpp
index 3b3e1108b94be13666afe6cf343ebeb7d27eb871..35364692b29b680a2841d79f42c801c945de3858 100644 (file)
--- a/src/sp-shape.cpp
+++ b/src/sp-shape.cpp
*
* Author:
* Lauris Kaplinski <lauris@kaplinski.com>
+ * Abhishek Sharma
*
* Copyright (C) 1999-2002 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
* Copyright (C) 2004 John Cliff
* Copyright (C) 2007-2008 Johan Engelen
+ * Copyright (C) 2010 Jon A. Cruz <jon@joncruz.org>
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <2geom/transforms.h>
#include <2geom/pathvector.h>
#include <2geom/path-intersection.h>
+#include <2geom/exception.h>
#include "helper/geom.h"
#include "helper/geom-nodetype.h"
#define noSHAPE_VERBOSE
-/*static void sp_shape_class_init (SPShapeClass *klass);
-static void sp_shape_init (SPShape *shape);
-static void sp_shape_finalize (GObject *object);
-
-static void sp_shape_build (SPObject * object, SPDocument * document, Inkscape::XML::Node * repr);
-static void sp_shape_release (SPObject *object);
-
-static void sp_shape_set(SPObject *object, unsigned key, gchar const *value);
-static void sp_shape_update (SPObject *object, SPCtx *ctx, unsigned int flags);
-static void sp_shape_modified (SPObject *object, unsigned int flags);
-static Inkscape::XML::Node *sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
-
-static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &transform, unsigned const flags);*/
void sp_shape_print (SPItem * item, SPPrintContext * ctx);
-/*static NRArenaItem *sp_shape_show (SPItem *item, NRArena *arena, unsigned int key, unsigned int flags);
-static void sp_shape_hide (SPItem *item, unsigned int key);
-static void sp_shape_snappoints (SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs);
-
-static void sp_shape_update_marker_view (SPShape *shape, NRArenaItem *ai);
-
-static SPLPEItemClass *parent_class;*/
-SPLPEItemClass * SPShapeClass::parent_class=0;
+SPLPEItemClass * SPShapeClass::parent_class = 0;
/**
* Registers the SPShape class with Gdk and returns its type number.
*/
-GType
-SPShape::getType (void)
+GType SPShape::getType(void)
{
static GType type = 0;
if (!type) {
* Initializes a SPShapeClass object. Establishes the function pointers to the class'
* member routines in the class vtable, and sets pointers to parent classes.
*/
-void
-SPShapeClass::sp_shape_class_init (SPShapeClass *klass)
+void SPShapeClass::sp_shape_class_init(SPShapeClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
SPObjectClass *sp_object_class = SP_OBJECT_CLASS(klass);
/**
* Initializes an SPShape object.
*/
-void
-SPShape::sp_shape_init (SPShape *shape)
+void SPShape::sp_shape_init(SPShape *shape)
{
for ( int i = 0 ; i < SP_MARKER_LOC_QTY ; i++ ) {
new (&shape->release_connect[i]) sigc::connection();
shape->curve = NULL;
}
-void
-SPShape::sp_shape_finalize (GObject *object)
+void SPShape::sp_shape_finalize(GObject *object)
{
SPShape *shape=(SPShape *)object;
*
* \see sp_object_build()
*/
-void
-SPShape::sp_shape_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
+void SPShape::sp_shape_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
{
if (((SPObjectClass *) (SPShapeClass::parent_class))->build) {
(*((SPObjectClass *) (SPShapeClass::parent_class))->build) (object, document, repr);
@@ -194,8 +172,7 @@ SPShape::sp_shape_build (SPObject *object, SPDocument *document, Inkscape::XML::
*
* \see sp_object_release()
*/
-void
-SPShape::sp_shape_release (SPObject *object)
+void SPShape::sp_shape_release(SPObject *object)
{
SPItem *item;
SPShape *shape;
-void
-SPShape::sp_shape_set(SPObject *object, unsigned int key, gchar const *value)
+void SPShape::sp_shape_set(SPObject *object, unsigned int key, gchar const *value)
{
if (((SPObjectClass *) SPShapeClass::parent_class)->set) {
((SPObjectClass *) SPShapeClass::parent_class)->set(object, key, value);
}
}
-Inkscape::XML::Node *
-SPShape::sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags)
+Inkscape::XML::Node * SPShape::sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags)
{
if (((SPObjectClass *)(SPShapeClass::parent_class))->write) {
((SPObjectClass *)(SPShapeClass::parent_class))->write(object, doc, repr, flags);
@@ -248,8 +223,7 @@ SPShape::sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape
* Updates the shape when its attributes have changed. Also establishes
* marker objects to match the style settings.
*/
-void
-SPShape::sp_shape_update (SPObject *object, SPCtx *ctx, unsigned int flags)
+void SPShape::sp_shape_update(SPObject *object, SPCtx *ctx, unsigned int flags)
{
SPItem *item = (SPItem *) object;
SPShape *shape = (SPShape *) object;
* Reference for behaviour of zero-length segments:
* http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes
*/
-Geom::Matrix
-sp_shape_marker_get_transform(Geom::Curve const & c1, Geom::Curve const & c2)
+Geom::Matrix sp_shape_marker_get_transform(Geom::Curve const & c1, Geom::Curve const & c2)
{
Geom::Point p = c1.pointAt(1);
Geom::Curve * c1_reverse = c1.reverse();
return Geom::Rotate(ret_angle) * Geom::Translate(p);
}
-Geom::Matrix
-sp_shape_marker_get_transform_at_start(Geom::Curve const & c)
+
+Geom::Matrix sp_shape_marker_get_transform_at_start(Geom::Curve const & c)
{
Geom::Point p = c.pointAt(0);
Geom::Matrix ret = Geom::Translate(p);
return ret;
}
-Geom::Matrix
-sp_shape_marker_get_transform_at_end(Geom::Curve const & c)
+
+Geom::Matrix sp_shape_marker_get_transform_at_end(Geom::Curve const & c)
{
Geom::Point p = c.pointAt(1);
Geom::Matrix ret = Geom::Translate(p);
*
* @todo figure out what to do when both 'marker' and for instance 'marker-end' are set.
*/
-void
-SPShape::sp_shape_update_marker_view (SPShape *shape, NRArenaItem *ai)
+void SPShape::sp_shape_update_marker_view(SPShape *shape, NRArenaItem *ai)
{
SPStyle *style = ((SPObject *) shape)->style;
// position arguments to sp_marker_show_instance, basically counts the amount of markers.
int counter[4] = {0};
+ if (!shape->curve) return;
Geom::PathVector const & pathv = shape->curve->get_pathvector();
+ if (pathv.empty()) return;
// the first vertex should get a start marker, the last an end marker, and all the others a mid marker
// see bug 456148
/**
* Sets modified flag for all sub-item views.
*/
-void
-SPShape::sp_shape_modified (SPObject *object, unsigned int flags)
+void SPShape::sp_shape_modified(SPObject *object, unsigned int flags)
{
SPShape *shape = SP_SHAPE (object);
@@ -587,7 +560,7 @@ void SPShape::sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const
}
// Union with bboxes of the markers, if any
- if (shape->hasMarkers ()) {
+ if ( shape->hasMarkers() && !shape->curve->get_pathvector().empty() ) {
/** \todo make code prettier! */
Geom::PathVector const & pathv = shape->curve->get_pathvector();
// START marker
if (!shape->curve) return;
+ Geom::PathVector const & pathv = shape->curve->get_pathvector();
+ if (pathv.empty()) return;
+
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
gint add_comments = prefs->getBool("/printing/debug/add-label-comments");
if (add_comments) {
SPStyle* style = SP_OBJECT_STYLE (item);
if (!style->fill.isNone()) {
- sp_print_fill (ctx, shape->curve->get_pathvector(), &i2d, style, &pbox, &dbox, &bbox);
+ sp_print_fill (ctx, pathv, &i2d, style, &pbox, &dbox, &bbox);
}
if (!style->stroke.isNone()) {
- sp_print_stroke (ctx, shape->curve->get_pathvector(), &i2d, style, &pbox, &dbox, &bbox);
+ sp_print_stroke (ctx, pathv, &i2d, style, &pbox, &dbox, &bbox);
}
/** \todo make code prettier */
- Geom::PathVector const & pathv = shape->curve->get_pathvector();
// START marker
for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START
if ( shape->marker[i] ) {
/**
* Sets style, path, and paintbox. Updates marker views, including dimensions.
*/
-NRArenaItem *
-SPShape::sp_shape_show (SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/)
+NRArenaItem * SPShape::sp_shape_show(SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int /*flags*/)
{
SPObject *object = SP_OBJECT(item);
SPShape *shape = SP_SHAPE(item);
@@ -922,8 +896,7 @@ SPShape::sp_shape_show (SPItem *item, NRArena *arena, unsigned int /*key*/, unsi
/**
* Hides/removes marker views from the shape.
*/
-void
-SPShape::sp_shape_hide (SPItem *item, unsigned int key)
+void SPShape::sp_shape_hide(SPItem *item, unsigned int key)
{
SPShape *shape;
SPItemView *v;
* \param shape Shape.
* \return TRUE if the shape has any markers, or FALSE if not.
*/
-int
-SPShape::hasMarkers () const
+int SPShape::hasMarkers() const
{
/* Note, we're ignoring 'marker' settings, which technically should apply for
all three settings. This should be fixed later such that if 'marker' is
* \param type Marker type (e.g. SP_MARKER_LOC_START)
* \return Number of markers that the shape has of this type.
*/
-int
-SPShape::numberOfMarkers (int type)
+int SPShape::numberOfMarkers(int type)
{
Geom::PathVector const & pathv = this->curve->get_pathvector();
if (pathv.size() == 0) {
sp_shape_marker_modified (SPObject */*marker*/, guint /*flags*/, SPItem */*item*/)
{
/* I think mask does update automagically */
- /* g_warning ("Item %s mask %s modified", SP_OBJECT_ID (item), SP_OBJECT_ID (mask)); */
+ /* g_warning ("Item %s mask %s modified", item->getId(), mask->getId()); */
}
/**
/**
* Calls any registered handlers for the set_shape action
*/
-void
-SPShape::setShape ()
+void SPShape::setShape()
{
- //g_return_if_fail (shape != NULL);
- //g_return_if_fail (SP_IS_SHAPE (shape));
-
if (SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (this))->set_shape) {
SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (this))->set_shape (this);
}
* Any existing curve in the shape will be unreferenced first.
* This routine also triggers a request to update the display.
*/
-void
-SPShape::setCurve (SPCurve *curve, unsigned int owner)
+void SPShape::setCurve(SPCurve *curve, unsigned int owner)
{
if (this->curve) {
this->curve = this->curve->unref();
/**
* Return duplicate of curve (if any exists) or NULL if there is no curve
*/
-SPCurve *
-SPShape::getCurve ()
+SPCurve * SPShape::getCurve()
{
if (this->curve) {
return this->curve->copy();
/**
* Same as sp_shape_set_curve but without updating the display
*/
-void
-SPShape::setCurveInsync (SPCurve *curve, unsigned int owner)
+void SPShape::setCurveInsync(SPCurve *curve, unsigned int owner)
{
if (this->curve) {
this->curve = this->curve->unref();
@@ -1210,49 +1174,55 @@ void SPShape::sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::Snap
for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) {
if (snapprefs->getSnapToItemNode()) {
+ // Add the first point of the path
p.push_back(Inkscape::SnapCandidatePoint(path_it->initialPoint() * i2d, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
}
Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve
Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve
- while (curve_it2 != path_it->end_closed())
+ while (curve_it1 != path_it->end_default())
{
- /* Test whether to add the node between curve_it1 and curve_it2.
- * Loop to end_closed (so always including closing segment); the last node to be added
- * is the node between the closing segment and the segment before that, regardless
- * of the path being closed or not. If the path is closed, the final point was already added by
- * adding the initial point. */
-
- Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
-
- bool c1 = snapprefs->getSnapToItemNode() && (nodetype == Geom::NODE_CUSP || nodetype == Geom::NODE_NONE);
- bool c2 = snapprefs->getSnapSmoothNodes() && (nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM);
-
- if (c1 || c2) {
- Inkscape::SnapSourceType sst;
- Inkscape::SnapTargetType stt;
- switch (nodetype) {
- case Geom::NODE_CUSP:
- sst = Inkscape::SNAPSOURCE_NODE_CUSP;
- stt = Inkscape::SNAPTARGET_NODE_CUSP;
- break;
- case Geom::NODE_SMOOTH:
- case Geom::NODE_SYMM:
- sst = Inkscape::SNAPSOURCE_NODE_SMOOTH;
- stt = Inkscape::SNAPTARGET_NODE_SMOOTH;
- break;
- default:
- sst = Inkscape::SNAPSOURCE_UNDEFINED;
- stt = Inkscape::SNAPTARGET_UNDEFINED;
- break;
+ // For each path: consider midpoints of line segments for snapping
+ if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforces strict snapping)
+ if (Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&(*curve_it1))) {
+ p.push_back(Inkscape::SnapCandidatePoint(Geom::middle_point(*line_segment) * i2d, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
}
- p.push_back(Inkscape::SnapCandidatePoint(curve_it1->finalPoint() * i2d, sst, stt));
}
- // Consider midpoints of line segments for snapping
- if (snapprefs->getSnapLineMidpoints()) { // only do this when we're snapping nodes (enforce strict snapping)
- if (Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&(*curve_it1))) {
- p.push_back(Inkscape::SnapCandidatePoint(Geom::middle_point(*line_segment) * i2d, Inkscape::SNAPSOURCE_LINE_MIDPOINT, Inkscape::SNAPTARGET_LINE_MIDPOINT));
+ if (curve_it2 == path_it->end_default()) { // Test will only pass for the last iteration of the while loop
+ if (snapprefs->getSnapToItemNode() && !path_it->closed()) {
+ // Add the last point of the path, but only for open paths
+ // (for closed paths the first and last point will coincide)
+ p.push_back(Inkscape::SnapCandidatePoint((*curve_it1).finalPoint() * i2d, Inkscape::SNAPSOURCE_NODE_CUSP, Inkscape::SNAPTARGET_NODE_CUSP));
+ }
+ } else {
+ /* Test whether to add the node between curve_it1 and curve_it2.
+ * Loop to end_default (so only iterating through the stroked part); */
+
+ Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
+
+ bool c1 = snapprefs->getSnapToItemNode() && (nodetype == Geom::NODE_CUSP || nodetype == Geom::NODE_NONE);
+ bool c2 = snapprefs->getSnapSmoothNodes() && (nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM);
+
+ if (c1 || c2) {
+ Inkscape::SnapSourceType sst;
+ Inkscape::SnapTargetType stt;
+ switch (nodetype) {
+ case Geom::NODE_CUSP:
+ sst = Inkscape::SNAPSOURCE_NODE_CUSP;
+ stt = Inkscape::SNAPTARGET_NODE_CUSP;
+ break;
+ case Geom::NODE_SMOOTH:
+ case Geom::NODE_SYMM:
+ sst = Inkscape::SNAPSOURCE_NODE_SMOOTH;
+ stt = Inkscape::SNAPTARGET_NODE_SMOOTH;
+ break;
+ default:
+ sst = Inkscape::SNAPSOURCE_UNDEFINED;
+ stt = Inkscape::SNAPTARGET_UNDEFINED;
+ break;
+ }
+ p.push_back(Inkscape::SnapCandidatePoint(curve_it1->finalPoint() * i2d, sst, stt));
}
}
@@ -1264,13 +1234,19 @@ void SPShape::sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::Snap
// (using "Method 1" as described in Inkscape::ObjectSnapper::_collectNodes())
if (snapprefs->getSnapIntersectionCS()) {
Geom::Crossings cs;
- cs = self_crossings(*path_it);
- if (cs.size() > 0) { // There might be multiple intersections...
- for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) {
- Geom::Point p_ix = (*path_it).pointAt((*i).ta);
- p.push_back(Inkscape::SnapCandidatePoint(p_ix * i2d, Inkscape::SNAPSOURCE_PATH_INTERSECTION, Inkscape::SNAPTARGET_PATH_INTERSECTION));
+ try {
+ cs = self_crossings(*path_it);
+ if (cs.size() > 0) { // There might be multiple intersections...
+ for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) {
+ Geom::Point p_ix = (*path_it).pointAt((*i).ta);
+ p.push_back(Inkscape::SnapCandidatePoint(p_ix * i2d, Inkscape::SNAPSOURCE_PATH_INTERSECTION, Inkscape::SNAPTARGET_PATH_INTERSECTION));
+ }
}
+ } catch (Geom::RangeError &e) {
+ // do nothing
+ // The exception could be Geom::InfiniteSolutions: then no snappoints should be added
}
+
}
}
@@ -1285,4 +1261,4 @@ void SPShape::sp_shape_snappoints(SPItem const *item, std::vector<Inkscape::Snap
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :