diff --git a/src/sp-offset.cpp b/src/sp-offset.cpp
index a9730653c247e4ac11f3118113197c9bc2aea9c9..556778676cd2ada7055f69738aa946ef919bc5f2 100644 (file)
--- a/src/sp-offset.cpp
+++ b/src/sp-offset.cpp
# include "config.h"
#endif
+#include <cstring>
+#include <string>
#include "svg/svg.h"
#include "attributes.h"
#include "livarot/Shape.h"
#include "enums.h"
-#include "prefs-utils.h"
+#include "preferences.h"
#include "sp-text.h"
#include "sp-offset.h"
#include "sp-use-reference.h"
#include "uri.h"
-#include "libnr/n-art-bpath.h"
#include <libnr/nr-matrix-fns.h>
+#include <2geom/pathvector.h>
#include "xml/repr.h"
/** \note
* SPOffset is a derivative of SPShape, much like the SPSpiral or SPRect.
- * The goal is to have a source shape (= originalPath), an offset (= radius)
- * and compute the offset of the source by the radius. To get it to work,
- * one needs to know what the source is and what the radius is, and how it's
- * stored in the xml representation. The object itself is a "path" element,
- * to get lots of shape functionality for free. The source is the easy part:
- * it's stored in a "inkscape:original" attribute in the path. In case of
+ * The goal is to have a source shape (= originalPath), an offset (= radius)
+ * and compute the offset of the source by the radius. To get it to work,
+ * one needs to know what the source is and what the radius is, and how it's
+ * stored in the xml representation. The object itself is a "path" element,
+ * to get lots of shape functionality for free. The source is the easy part:
+ * it's stored in a "inkscape:original" attribute in the path. In case of
* "linked" offset, as they've been dubbed, there is an additional
- * "inkscape:href" that contains the id of an element of the svg.
- * When built, the object will attach a listener vector to that object and
- * rebuild the "inkscape:original" whenever the href'd object changes. This
- * is of course grossly inefficient, and also does not react to changes
- * to the href'd during context stuff (like changing the shape of a star by
- * dragging control points) unless the path of that object is changed during
- * the context (seems to be the case for SPEllipse). The computation of the
- * offset is done in sp_offset_set_shape(), a function that is called whenever
+ * "inkscape:href" that contains the id of an element of the svg.
+ * When built, the object will attach a listener vector to that object and
+ * rebuild the "inkscape:original" whenever the href'd object changes. This
+ * is of course grossly inefficient, and also does not react to changes
+ * to the href'd during context stuff (like changing the shape of a star by
+ * dragging control points) unless the path of that object is changed during
+ * the context (seems to be the case for SPEllipse). The computation of the
+ * offset is done in sp_offset_set_shape(), a function that is called whenever
* a change occurs to the offset (change of source or change of radius).
- * just like the sp-star and other, this path derivative can make control
- * points, or more precisely one control point, that's enough to define the
+ * just like the sp-star and other, this path derivative can make control
+ * points, or more precisely one control point, that's enough to define the
* radius (look in object-edit).
*/
static void sp_offset_build (SPObject * object, SPDocument * document,
Inkscape::XML::Node * repr);
-static Inkscape::XML::Node *sp_offset_write (SPObject * object, Inkscape::XML::Node * repr,
+static Inkscape::XML::Node *sp_offset_write (SPObject * object, Inkscape::XML::Document *doc, Inkscape::XML::Node * repr,
guint flags);
static void sp_offset_set (SPObject * object, unsigned int key,
const gchar * value);
static void sp_offset_release (SPObject * object);
static gchar *sp_offset_description (SPItem * item);
-static void sp_offset_snappoints(SPItem const *item, SnapPointsIter p);
+static void sp_offset_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs);
static void sp_offset_set_shape (SPShape * shape);
-Path *bpath_to_liv_path (NArtBpath * bpath);
-
static void refresh_offset_source(SPOffset* offset);
static void sp_offset_start_listening(SPOffset *offset,SPObject* to);
static void sp_offset_quit_listening(SPOffset *offset);
static void sp_offset_href_changed(SPObject *old_ref, SPObject *ref, SPOffset *offset);
-static void sp_offset_move_compensate(NR::Matrix const *mp, SPItem *original, SPOffset *self);
+static void sp_offset_move_compensate(Geom::Matrix const *mp, SPItem *original, SPOffset *self);
static void sp_offset_delete_self(SPObject *deleted, SPOffset *self);
static void sp_offset_source_modified (SPObject *iSource, guint flags, SPItem *item);
offset->sourceHref = NULL;
offset->sourceRepr = NULL;
offset->sourceObject = NULL;
+ new (&offset->_modified_connection) sigc::connection();
new (&offset->_delete_connection) sigc::connection();
new (&offset->_changed_connection) sigc::connection();
new (&offset->_transformed_connection) sigc::connection();
SPOffset *offset = (SPOffset *) obj;
delete offset->sourceRef;
+
+ offset->_modified_connection.disconnect();
+ offset->_modified_connection.~connection();
+ offset->_delete_connection.disconnect();
offset->_delete_connection.~connection();
+ offset->_changed_connection.disconnect();
offset->_changed_connection.~connection();
+ offset->_transformed_connection.disconnect();
offset->_transformed_connection.~connection();
}
@@ -209,19 +216,19 @@ sp_offset_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
{
if (((SPObjectClass *) parent_class)->build)
((SPObjectClass *) parent_class)->build (object, document, repr);
-
+
if (object->repr->attribute("inkscape:radius")) {
sp_object_read_attr (object, "inkscape:radius");
} else {
gchar const *oldA = object->repr->attribute("sodipodi:radius");
object->repr->setAttribute("inkscape:radius",oldA);
object->repr->setAttribute("sodipodi:radius",NULL);
-
+
sp_object_read_attr (object, "inkscape:radius");
}
if (object->repr->attribute("inkscape:original")) {
sp_object_read_attr (object, "inkscape:original");
- } else {
+ } else {
gchar const *oldA = object->repr->attribute("sodipodi:original");
object->repr->setAttribute("inkscape:original",oldA);
object->repr->setAttribute("sodipodi:original",NULL);
@@ -234,7 +241,7 @@ sp_offset_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
gchar const *oldA = object->repr->attribute("inkscape:href");
if (oldA) {
size_t lA = strlen(oldA);
- char *nA=(char*)malloc((lA+1)*sizeof(char));
+ char *nA=(char*)malloc((1+lA+1)*sizeof(char));
memcpy(nA+1,oldA,lA*sizeof(char));
nA[0]='#';
nA[lA+1]=0;
@@ -250,12 +257,12 @@ sp_offset_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
* Virtual write: write offset attributes to corresponding repr.
*/
static Inkscape::XML::Node *
-sp_offset_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
+sp_offset_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
{
SPOffset *offset = SP_OFFSET (object);
if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
- repr = sp_repr_new ("svg:path");
+ repr = xml_doc->createElement("svg:path");
}
if (flags & SP_OBJECT_WRITE_EXT) {
}
// write that curve to "d"
- char *d = sp_svg_write_path (((SPShape *) offset)->curve->bpath);
+ char *d = sp_svg_write_path (((SPShape *) offset)->curve->get_pathvector());
repr->setAttribute("d", d);
g_free (d);
if (((SPObjectClass *) (parent_class))->write)
- ((SPObjectClass *) (parent_class))->write (object, repr,
+ ((SPObjectClass *) (parent_class))->write (object, xml_doc, repr,
flags | SP_SHAPE_WRITE_PATH);
return repr;
}
/**
- * Set callback: the function that is called whenever a change is made to
+ * Set callback: the function that is called whenever a change is made to
* the description of the object.
*/
static void
offset->original = NULL;
offset->originalPath = NULL;
}
- NArtBpath *bpath;
- SPCurve *curve;
offset->original = strdup (value);
- bpath = sp_svg_read_path (offset->original);
- curve = sp_curve_new_from_bpath (bpath); // curve se chargera de detruire bpath
- g_assert (curve != NULL);
- offset->originalPath = bpath_to_liv_path (curve->bpath);
- sp_curve_unref (curve);
+ Geom::PathVector pv = sp_svg_read_pathv(offset->original);
+ offset->originalPath = new Path;
+ reinterpret_cast<Path *>(offset->originalPath)->LoadPathVector(pv);
offset->knotSet = false;
if ( offset->isUpdating == false ) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
}
-/**
- * Converts an NArtBpath (like the one stored in a SPCurve) into a
- * livarot Path. Duplicate of splivarot.
- */
-Path *
-bpath_to_liv_path(NArtBpath *bpath)
-{
- if (bpath == NULL)
- return NULL;
-
- Path *dest = new Path;
- dest->SetBackData (false);
- {
- int i;
- bool closed = false;
- float lastX = 0.0;
- float lastY = 0.0;
-
- for (i = 0; bpath[i].code != NR_END; i++)
- {
- switch (bpath[i].code)
- {
- case NR_LINETO:
- lastX = bpath[i].x3;
- lastY = bpath[i].y3;
- {
- NR::Point tmp(lastX,lastY);
- dest->LineTo (tmp);
- }
- break;
-
- case NR_CURVETO:
- {
- NR::Point tmp(bpath[i].x3, bpath[i].y3);
- NR::Point tms;
- tms[0]=3 * (bpath[i].x1 - lastX);
- tms[1]=3 * (bpath[i].y1 - lastY);
- NR::Point tme;
- tme[0]=3 * (bpath[i].x3 - bpath[i].x2);
- tme[1]= 3 * (bpath[i].y3 - bpath[i].y2);
- dest->CubicTo (tmp,tms,tme);
- }
- lastX = bpath[i].x3;
- lastY = bpath[i].y3;
- break;
-
- case NR_MOVETO_OPEN:
- case NR_MOVETO:
- if (closed)
- dest->Close ();
- closed = (bpath[i].code == NR_MOVETO);
- lastX = bpath[i].x3;
- lastY = bpath[i].y3;
- {
- NR::Point tmp(lastX,lastY);
- dest->MoveTo(tmp);
- }
- break;
- default:
- break;
- }
- }
- if (closed)
- dest->Close ();
- }
-
- return dest;
-}
-
/**
* Compute and set shape's offset.
*/
const char *res_d = SP_OBJECT(shape)->repr->attribute("inkscape:original");
if ( res_d ) {
- NArtBpath *bpath = sp_svg_read_path (res_d);
- SPCurve *c = sp_curve_new_from_bpath (bpath);
+ Geom::PathVector pv = sp_svg_read_pathv(res_d);
+ SPCurve *c = new SPCurve(pv);
g_assert(c != NULL);
sp_shape_set_curve_insync ((SPShape *) offset, c, TRUE);
- sp_curve_unref (c);
+ c->unref();
}
return;
}
Path *originaux[1];
Path *res = new Path;
res->SetBackData (false);
-
+
// and now: offset
float o_width;
if (offset->rad >= 0)
theRes->ConvertToForme (orig, 1, originaux);
SPItem *item = shape;
- NR::Rect bbox = sp_item_bbox_desktop (item);
- if (!bbox.isEmpty()) {
- gdouble size = L2(bbox.dimensions());
- gdouble const exp = NR::expansion(item->transform);
+ Geom::OptRect bbox = sp_item_bbox_desktop (item);
+ if ( bbox ) {
+ gdouble size = L2(bbox->dimensions());
+ gdouble const exp = item->transform.descrim();
if (exp != 0)
size /= exp;
orig->Coalesce (size * 0.001);
// version par makeoffset
Shape *theShape = new Shape;
Shape *theRes = new Shape;
-
-
+
+
// and now: offset
float o_width;
if (offset->rad >= 0)
{
o_width = -offset->rad;
}
-
+
// one has to have a measure of the details
if (o_width >= 1.0)
{
}
delete orig;
- NArtBpath *bpath = sp_svg_read_path (res_d);
- SPCurve *c = sp_curve_new_from_bpath (bpath);
+ Geom::PathVector pv = sp_svg_read_pathv(res_d);
+ SPCurve *c = new SPCurve(pv);
g_assert(c != NULL);
sp_shape_set_curve_insync ((SPShape *) offset, c, TRUE);
- sp_curve_unref (c);
+ c->unref();
free (res_d);
}
/**
* Virtual snappoints function.
*/
-static void sp_offset_snappoints(SPItem const *item, SnapPointsIter p)
+static void sp_offset_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs)
{
if (((SPItemClass *) parent_class)->snappoints) {
- ((SPItemClass *) parent_class)->snappoints (item, p);
+ ((SPItemClass *) parent_class)->snappoints (item, p, snapprefs);
}
}
// utilitaires pour les poignees
// used to get the distance to the shape: distance to polygon give the fabs(radius), we still need
// the sign. for edges, it's easy to determine which side the point is on, for points of the polygon
-// it's trickier: we need to identify which angle the point is in; to that effect, we take each
+// it's trickier: we need to identify which angle the point is in; to that effect, we take each
// successive clockwise angle (A,C) and check if the vector B given by the point is in the angle or
// outside.
-// another method would be to use the Winding() function to test whether the point is inside or outside
+// another method would be to use the Winding() function to test whether the point is inside or outside
// the polygon (it would be wiser to do so, in fact, but i like being stupid)
-/**
+/**
*
* \todo
* FIXME: This can be done using linear operations, more stably and
* faster. method: transform A and C into B's space, A should be
* negative and B should be positive in the orthogonal component. I
- * think this is equivalent to
- * dot(A, rot90(B))*dot(C, rot90(B)) == -1.
- * -- njh
+ * think this is equivalent to
+ * dot(A, rot90(B))*dot(C, rot90(B)) == -1.
+ * -- njh
*/
bool
-vectors_are_clockwise (NR::Point A, NR::Point B, NR::Point C)
+vectors_are_clockwise (Geom::Point A, Geom::Point B, Geom::Point C)
{
- using NR::rot90;
+ using Geom::rot90;
double ab_s = dot(A, rot90(B));
double ab_c = dot(A, B);
double bc_s = dot(B, rot90(C));
return false;
}
-/**
- * Distance to the original path; that function is called from object-edit
+/**
+ * Distance to the original path; that function is called from object-edit
* to set the radius when the control knot moves.
*
- * The sign of the result is the radius we're going to offset the shape with,
- * so result > 0 ==outset and result < 0 ==inset. thus result<0 means
+ * The sign of the result is the radius we're going to offset the shape with,
+ * so result > 0 ==outset and result < 0 ==inset. thus result<0 means
* 'px inside source'.
*/
double
-sp_offset_distance_to_original (SPOffset * offset, NR::Point px)
+sp_offset_distance_to_original (SPOffset * offset, Geom::Point px)
{
if (offset == NULL || offset->originalPath == NULL
|| ((Path *) offset->originalPath)->descr_cmd.size() <= 1)
double dist = 1.0;
Shape *theShape = new Shape;
Shape *theRes = new Shape;
-
- /** \todo
- * Awfully damn stupid method: uncross the source path EACH TIME you
- * need to compute the distance. The good way to do this would be to
+
+ /** \todo
+ * Awfully damn stupid method: uncross the source path EACH TIME you
+ * need to compute the distance. The good way to do this would be to
* store the uncrossed source path somewhere, and delete it when the
- * context is finished. Hopefully this part is much faster than actually
- * computing the offset (which happen just after), so the time spent in
- * this function should end up being negligible with respect to the
+ * context is finished. Hopefully this part is much faster than actually
+ * computing the offset (which happen just after), so the time spent in
+ * this function should end up being negligible with respect to the
* delay of one context.
*/
// move
{
if (theRes->getPoint(i).totalDegree() > 0)
{
- NR::Point nx = theRes->getPoint(i).x;
- NR::Point nxpx = px-nx;
+ Geom::Point nx = theRes->getPoint(i).x;
+ Geom::Point nxpx = px-nx;
double ndist = sqrt (dot(nxpx,nxpx));
if (ptSet == false || fabs (ndist) < fabs (ptDist))
{
// we have a new minimum distance
// now we need to wheck if px is inside or outside (for the sign)
- nx = px - theRes->getPoint(i).x;
+ nx = px - to_2geom(theRes->getPoint(i).x);
double nlen = sqrt (dot(nx , nx));
nx /= nlen;
int pb, cb, fb;
do
{
// one angle
- NR::Point prx, nex;
+ Geom::Point prx, nex;
prx = theRes->getEdge(pb).dx;
nlen = sqrt (dot(prx, prx));
prx /= nlen;
}
while (cb >= 0 && pb >= 0 && pb != fb);
}
- }
+ }
}
// loop over the edges to try to improve the distance
for (int i = 0; i < theRes->numberOfEdges(); i++)
{
- NR::Point sx = theRes->getPoint(theRes->getEdge(i).st).x;
- NR::Point ex = theRes->getPoint(theRes->getEdge(i).en).x;
- NR::Point nx = ex - sx;
+ Geom::Point sx = theRes->getPoint(theRes->getEdge(i).st).x;
+ Geom::Point ex = theRes->getPoint(theRes->getEdge(i).en).x;
+ Geom::Point nx = ex - sx;
double len = sqrt (dot(nx,nx));
if (len > 0.0001)
- {
- NR::Point pxsx=px-sx;
+ {
+ Geom::Point pxsx=px-sx;
double ab = dot(nx,pxsx);
if (ab > 0 && ab < len * len)
{
arSet = true;
}
}
- }
+ }
}
if (arSet || ptSet)
{
return dist;
}
-/**
- * Computes a point on the offset; used to set a "seed" position for
+/**
+ * Computes a point on the offset; used to set a "seed" position for
* the control knot.
*
* \return the topmost point on the offset.
*/
void
-sp_offset_top_point (SPOffset * offset, NR::Point *px)
+sp_offset_top_point (SPOffset * offset, Geom::Point *px)
{
- (*px) = NR::Point(0, 0);
+ (*px) = Geom::Point(0, 0);
if (offset == NULL)
return;
if (curve == NULL)
return;
}
-
- Path *finalPath = bpath_to_liv_path (curve->bpath);
- if (finalPath == NULL)
+ if (curve->is_empty())
{
- sp_curve_unref (curve);
+ curve->unref();
return;
}
+ Path *finalPath = new Path;
+ finalPath->LoadPathVector(curve->get_pathvector());
+
Shape *theShape = new Shape;
finalPath->Convert (1.0);
delete theShape;
delete finalPath;
- sp_curve_unref (curve);
+ curve->unref();
}
// the listening functions
offset->_delete_connection = SP_OBJECT(to)->connectDelete(sigc::bind(sigc::ptr_fun(&sp_offset_delete_self), offset));
offset->_transformed_connection = SP_ITEM(to)->connectTransformed(sigc::bind(sigc::ptr_fun(&sp_offset_move_compensate), offset));
- offset->_modified_connection = g_signal_connect (G_OBJECT (to), "modified", G_CALLBACK (sp_offset_source_modified), offset);
+ offset->_modified_connection = SP_OBJECT(to)->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_offset_source_modified), offset));
}
static void sp_offset_quit_listening(SPOffset *offset)
if ( offset->sourceObject == NULL )
return;
- g_signal_handler_disconnect (offset->sourceObject, offset->_modified_connection);
+ offset->_modified_connection.disconnect();
offset->_delete_connection.disconnect();
offset->_transformed_connection.disconnect();
@@ -1086,23 +1021,24 @@ sp_offset_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPOffset *offse
}
static void
-sp_offset_move_compensate(NR::Matrix const *mp, SPItem *original, SPOffset *self)
+sp_offset_move_compensate(Geom::Matrix const *mp, SPItem */*original*/, SPOffset *self)
{
- guint mode = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_PARALLEL);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ guint mode = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_PARALLEL);
if (mode == SP_CLONE_COMPENSATION_NONE) return;
- NR::Matrix m(*mp);
- if (!(m.is_translation())) return;
+ Geom::Matrix m(*mp);
+ if (!(m.isTranslation())) return;
// calculate the compensation matrix and the advertized movement matrix
SPItem *item = SP_ITEM(self);
- NR::Matrix compensate;
- NR::Matrix advertized_move;
+ Geom::Matrix compensate;
+ Geom::Matrix advertized_move;
if (mode == SP_CLONE_COMPENSATION_UNMOVED) {
- compensate = NR::identity();
- advertized_move.set_identity();
+ compensate = Geom::identity();
+ advertized_move.setIdentity();
} else if (mode == SP_CLONE_COMPENSATION_PARALLEL) {
compensate = m;
advertized_move = m;
@@ -1120,7 +1056,8 @@ sp_offset_move_compensate(NR::Matrix const *mp, SPItem *original, SPOffset *self
static void
sp_offset_delete_self(SPObject */*deleted*/, SPOffset *offset)
{
- guint const mode = prefs_get_int_attribute("options.cloneorphans", "value", SP_CLONE_ORPHANS_UNLINK);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ guint const mode = prefs->getInt("/options/cloneorphans/value", SP_CLONE_ORPHANS_UNLINK);
if (mode == SP_CLONE_ORPHANS_UNLINK) {
// leave it be. just forget about the source
}
static void
-sp_offset_source_modified (SPObject *iSource, guint flags, SPItem *item)
+sp_offset_source_modified (SPObject */*iSource*/, guint /*flags*/, SPItem *item)
{
SPOffset *offset = SP_OFFSET(item);
offset->sourceDirty=true;
sp_shape_set_shape ((SPShape *) offset);
}
-static void
+static void
refresh_offset_source(SPOffset* offset)
{
if ( offset == NULL ) return;
offset->sourceDirty=false;
- Path *orig = NULL;
// le mauvais cas: pas d'attribut d => il faut verifier que c'est une SPShape puis prendre le contour
// The bad case: no d attribute. Must check that it's an SPShape and then take the outline.
if (SP_IS_TEXT (item)) {
curve = SP_TEXT (item)->getNormalizedBpath ();
if (curve == NULL)
- return;
+ return;
}
- orig = bpath_to_liv_path (curve->bpath);
- sp_curve_unref (curve);
+ Path *orig = new Path;
+ orig->LoadPathVector(curve->get_pathvector());
+ curve->unref();
// Finish up.
{
theRes->ConvertToShape (theShape, fill_nonZero);
}
-
+
Path *originaux[1];
originaux[0] = orig;
Path *res = new Path;
theRes->ConvertToForme (res, 1, originaux);
-
+
delete theShape;
delete theRes;
-
+
char *res_d = res->svg_dump_path ();
delete res;
delete orig;
-
+
SP_OBJECT (offset)->repr->setAttribute("inkscape:original", res_d);
-
+
free (res_d);
}
}