sp-offset.cpp revision 25d6d71c2b9c7c718f8258fcf64b47f42a74cb27
843e19887f64dde75055cf8842fc4db2171eff45johnlev/** \file
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Implementation of <path sodipodi:type="inkscape:offset">.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Authors: (of the sp-spiral.c upon which this file was constructed):
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Mitsuru Oka <oka326@parkcity.ne.jp>
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Lauris Kaplinski <lauris@kaplinski.com>
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Abhishek Sharma
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Copyright (C) 1999-2002 Lauris Kaplinski
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Copyright (C) 2000-2001 Ximian, Inc.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Released under GNU GPL, read the file 'COPYING' for more information
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#ifdef HAVE_CONFIG_H
843e19887f64dde75055cf8842fc4db2171eff45johnlev# include "config.h"
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <cstring>
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee#include <string>
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include "svg/svg.h"
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include "attributes.h"
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include "display/curve.h"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include <glibmm/i18n.h>
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include "livarot/Path.h"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include "livarot/Shape.h"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include "enums.h"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include "preferences.h"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include "sp-text.h"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include "sp-offset.h"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include "sp-use-reference.h"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include "uri.h"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include <libnr/nr-matrix-fns.h>
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#include <2geom/pathvector.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include "xml/repr.h"
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevclass SPDocument;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#define noOFFSET_VERBOSE
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/** \note
843e19887f64dde75055cf8842fc4db2171eff45johnlev * SPOffset is a derivative of SPShape, much like the SPSpiral or SPRect.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The goal is to have a source shape (= originalPath), an offset (= radius)
843e19887f64dde75055cf8842fc4db2171eff45johnlev * and compute the offset of the source by the radius. To get it to work,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * one needs to know what the source is and what the radius is, and how it's
843e19887f64dde75055cf8842fc4db2171eff45johnlev * stored in the xml representation. The object itself is a "path" element,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * to get lots of shape functionality for free. The source is the easy part:
843e19887f64dde75055cf8842fc4db2171eff45johnlev * it's stored in a "inkscape:original" attribute in the path. In case of
843e19887f64dde75055cf8842fc4db2171eff45johnlev * "linked" offset, as they've been dubbed, there is an additional
843e19887f64dde75055cf8842fc4db2171eff45johnlev * "inkscape:href" that contains the id of an element of the svg.
843e19887f64dde75055cf8842fc4db2171eff45johnlev * When built, the object will attach a listener vector to that object and
843e19887f64dde75055cf8842fc4db2171eff45johnlev * rebuild the "inkscape:original" whenever the href'd object changes. This
843e19887f64dde75055cf8842fc4db2171eff45johnlev * is of course grossly inefficient, and also does not react to changes
843e19887f64dde75055cf8842fc4db2171eff45johnlev * to the href'd during context stuff (like changing the shape of a star by
843e19887f64dde75055cf8842fc4db2171eff45johnlev * dragging control points) unless the path of that object is changed during
843e19887f64dde75055cf8842fc4db2171eff45johnlev * the context (seems to be the case for SPEllipse). The computation of the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * offset is done in sp_offset_set_shape(), a function that is called whenever
843e19887f64dde75055cf8842fc4db2171eff45johnlev * a change occurs to the offset (change of source or change of radius).
843e19887f64dde75055cf8842fc4db2171eff45johnlev * just like the sp-star and other, this path derivative can make control
843e19887f64dde75055cf8842fc4db2171eff45johnlev * points, or more precisely one control point, that's enough to define the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * radius (look in object-edit).
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void sp_offset_class_init (SPOffsetClass * klass);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void sp_offset_init (SPOffset * offset);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_finalize(GObject *obj);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_build (SPObject * object, SPDocument * document,
843e19887f64dde75055cf8842fc4db2171eff45johnlev Inkscape::XML::Node * repr);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic Inkscape::XML::Node *sp_offset_write (SPObject * object, Inkscape::XML::Document *doc, Inkscape::XML::Node * repr,
843e19887f64dde75055cf8842fc4db2171eff45johnlev guint flags);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_set (SPObject * object, unsigned int key,
843e19887f64dde75055cf8842fc4db2171eff45johnlev const gchar * value);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_update (SPObject * object, SPCtx * ctx, guint flags);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_release (SPObject * object);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic gchar *sp_offset_description (SPItem * item);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void sp_offset_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void sp_offset_set_shape (SPShape * shape);
5d2eda970e48f8985448151c73e699614ce9f357John Levon
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void refresh_offset_source(SPOffset* offset);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
5d2eda970e48f8985448151c73e699614ce9f357John Levonstatic void sp_offset_start_listening(SPOffset *offset,SPObject* to);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void sp_offset_quit_listening(SPOffset *offset);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void sp_offset_href_changed(SPObject *old_ref, SPObject *ref, SPOffset *offset);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_move_compensate(Geom::Affine const *mp, SPItem *original, SPOffset *self);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_delete_self(SPObject *deleted, SPOffset *self);
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_source_modified (SPObject *iSource, guint flags, SPItem *item);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
5d2eda970e48f8985448151c73e699614ce9f357John Levon// slow= source path->polygon->offset of polygon->polygon->path
843e19887f64dde75055cf8842fc4db2171eff45johnlev// fast= source path->offset of source path->polygon->path
843e19887f64dde75055cf8842fc4db2171eff45johnlev// fast is not mathematically correct, because computing the offset of a single
5d2eda970e48f8985448151c73e699614ce9f357John Levon// cubic bezier patch is not trivial; in particular, there are problems with holes
5d2eda970e48f8985448151c73e699614ce9f357John Levon// reappearing in offset when the radius becomes too large
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic bool use_slow_but_correct_offset_method=false;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev// nothing special here, same for every class in sodipodi/inkscape
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic SPShapeClass *parent_class;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/**
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Register SPOffset class and return its type number.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevGType
843e19887f64dde75055cf8842fc4db2171eff45johnlevsp_offset_get_type (void)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev static GType offset_type = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!offset_type)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab GTypeInfo offset_info = {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab sizeof (SPOffsetClass),
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab NULL, /* base_init */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab NULL, /* base_finalize */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab (GClassInitFunc) sp_offset_class_init,
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab NULL, /* class_finalize */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab NULL, /* class_data */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab sizeof (SPOffset),
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab 16, /* n_preallocs */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab (GInstanceInitFunc) sp_offset_init,
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab NULL, /* value_table */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab };
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset_type =
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab g_type_register_static (SP_TYPE_SHAPE, "SPOffset", &offset_info,
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab (GTypeFlags) 0);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab return offset_type;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab/**
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * SPOffset vtable initialization.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabsp_offset_class_init(SPOffsetClass *klass)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab{
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab GObjectClass *gobject_class = (GObjectClass *) klass;
843e19887f64dde75055cf8842fc4db2171eff45johnlev SPObjectClass *sp_object_class = (SPObjectClass *) klass;
843e19887f64dde75055cf8842fc4db2171eff45johnlev SPItemClass *item_class = (SPItemClass *) klass;
843e19887f64dde75055cf8842fc4db2171eff45johnlev SPShapeClass *shape_class = (SPShapeClass *) klass;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev parent_class = (SPShapeClass *) g_type_class_ref (SP_TYPE_SHAPE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev gobject_class->finalize = sp_offset_finalize;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev sp_object_class->build = sp_offset_build;
843e19887f64dde75055cf8842fc4db2171eff45johnlev sp_object_class->write = sp_offset_write;
843e19887f64dde75055cf8842fc4db2171eff45johnlev sp_object_class->set = sp_offset_set;
843e19887f64dde75055cf8842fc4db2171eff45johnlev sp_object_class->update = sp_offset_update;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab sp_object_class->release = sp_offset_release;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab item_class->description = sp_offset_description;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab item_class->snappoints = sp_offset_snappoints;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab shape_class->set_shape = sp_offset_set_shape;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab/**
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * Callback for SPOffset object initialization.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevsp_offset_init(SPOffset *offset)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->rad = 1.0;
5d2eda970e48f8985448151c73e699614ce9f357John Levon offset->original = NULL;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->originalPath = NULL;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->knotSet = false;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->sourceDirty=false;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->isUpdating=false;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // init various connections
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->sourceHref = NULL;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->sourceRepr = NULL;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->sourceObject = NULL;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab new (&offset->_modified_connection) sigc::connection();
843e19887f64dde75055cf8842fc4db2171eff45johnlev new (&offset->_delete_connection) sigc::connection();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab new (&offset->_changed_connection) sigc::connection();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab new (&offset->_transformed_connection) sigc::connection();
843e19887f64dde75055cf8842fc4db2171eff45johnlev // set up the uri reference
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->sourceRef = new SPUseReference(offset);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->_changed_connection = offset->sourceRef->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_offset_href_changed), offset));
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee}
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee/**
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * Callback for SPOffset finalization.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevsp_offset_finalize(GObject *obj)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev SPOffset *offset = (SPOffset *) obj;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab delete offset->sourceRef;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_modified_connection.disconnect();
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_modified_connection.~connection();
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_delete_connection.disconnect();
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_delete_connection.~connection();
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_changed_connection.disconnect();
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_changed_connection.~connection();
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_transformed_connection.disconnect();
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_transformed_connection.~connection();
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/**
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Virtual build: set offset attributes from corresponding repr.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevsp_offset_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (((SPObjectClass *) parent_class)->build)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((SPObjectClass *) parent_class)->build (object, document, repr);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev //XML Tree being used directly here while it shouldn't be.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (object->getRepr()->attribute("inkscape:radius")) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab object->readAttr( "inkscape:radius" );
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab } else {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab //XML Tree being used directly here (as object->getRepr)
843e19887f64dde75055cf8842fc4db2171eff45johnlev //in all the below lines in the block while it shouldn't be.
843e19887f64dde75055cf8842fc4db2171eff45johnlev gchar const *oldA = object->getRepr()->attribute("sodipodi:radius");
843e19887f64dde75055cf8842fc4db2171eff45johnlev object->getRepr()->setAttribute("inkscape:radius",oldA);
843e19887f64dde75055cf8842fc4db2171eff45johnlev object->getRepr()->setAttribute("sodipodi:radius",NULL);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab object->readAttr( "inkscape:radius" );
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (object->getRepr()->attribute("inkscape:original")) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab object->readAttr( "inkscape:original" );
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev gchar const *oldA = object->getRepr()->attribute("sodipodi:original");
843e19887f64dde75055cf8842fc4db2171eff45johnlev object->getRepr()->setAttribute("inkscape:original",oldA);
843e19887f64dde75055cf8842fc4db2171eff45johnlev object->getRepr()->setAttribute("sodipodi:original",NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev object->readAttr( "inkscape:original" );
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (object->getRepr()->attribute("xlink:href")) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev object->readAttr( "xlink:href" );
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev gchar const *oldA = object->getRepr()->attribute("inkscape:href");
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (oldA) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev size_t lA = strlen(oldA);
843e19887f64dde75055cf8842fc4db2171eff45johnlev char *nA=(char*)malloc((1+lA+1)*sizeof(char));
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab memcpy(nA+1,oldA,lA*sizeof(char));
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab nA[0]='#';
843e19887f64dde75055cf8842fc4db2171eff45johnlev nA[lA+1]=0;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab object->getRepr()->setAttribute("xlink:href",nA);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab free(nA);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab object->getRepr()->setAttribute("inkscape:href",NULL);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
843e19887f64dde75055cf8842fc4db2171eff45johnlev object->readAttr( "xlink:href" );
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
843e19887f64dde75055cf8842fc4db2171eff45johnlev/**
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * Virtual write: write offset attributes to corresponding repr.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic Inkscape::XML::Node *
843e19887f64dde75055cf8842fc4db2171eff45johnlevsp_offset_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab SPOffset *offset = SP_OFFSET (object);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab repr = xml_doc->createElement("svg:path");
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (flags & SP_OBJECT_WRITE_EXT) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab /** \todo
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * Fixme: we may replace these attributes by
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * inkscape:offset="cx cy exp revo rad arg t0"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab repr->setAttribute("sodipodi:type", "inkscape:offset");
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab sp_repr_set_svg_double(repr, "inkscape:radius", offset->rad);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab repr->setAttribute("inkscape:original", offset->original);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab repr->setAttribute("inkscape:href", offset->sourceHref);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // Make sure the object has curve
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab SPCurve *curve = SP_SHAPE (offset)->getCurve();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (curve == NULL) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab sp_offset_set_shape (SP_SHAPE (offset));
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // write that curve to "d"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab char *d = sp_svg_write_path (((SPShape *) offset)->curve->get_pathvector());
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab repr->setAttribute("d", d);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab g_free (d);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (((SPObjectClass *) (parent_class))->write)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab ((SPObjectClass *) (parent_class))->write (object, xml_doc, repr,
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab flags | SP_SHAPE_WRITE_PATH);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab return repr;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab/**
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * Virtual release callback.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybeesp_offset_release(SPObject *object)
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee{
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee SPOffset *offset = (SPOffset *) object;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee if (offset->original) free (offset->original);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee if (offset->originalPath) delete ((Path *) offset->originalPath);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee offset->original = NULL;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee offset->originalPath = NULL;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee sp_offset_quit_listening(offset);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->_changed_connection.disconnect();
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee g_free(offset->sourceHref);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee offset->sourceHref = NULL;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee offset->sourceRef->detach();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (((SPObjectClass *) parent_class)->release) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab ((SPObjectClass *) parent_class)->release (object);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab/**
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * Set callback: the function that is called whenever a change is made to
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * the description of the object.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabsp_offset_set(SPObject *object, unsigned key, gchar const *value)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab{
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab SPOffset *offset = SP_OFFSET (object);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( offset->sourceDirty ) refresh_offset_source(offset);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* fixme: we should really collect updates */
843e19887f64dde75055cf8842fc4db2171eff45johnlev switch (key)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev case SP_ATTR_INKSCAPE_ORIGINAL:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case SP_ATTR_SODIPODI_ORIGINAL:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (value == NULL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (offset->original) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev free (offset->original);
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete ((Path *) offset->originalPath);
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->original = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->originalPath = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->original = strdup (value);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::PathVector pv = sp_svg_read_pathv(offset->original);
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->originalPath = new Path;
843e19887f64dde75055cf8842fc4db2171eff45johnlev reinterpret_cast<Path *>(offset->originalPath)->LoadPathVector(pv);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->knotSet = false;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( offset->isUpdating == false ) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab case SP_ATTR_INKSCAPE_RADIUS:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case SP_ATTR_SODIPODI_RADIUS:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!sp_svg_length_read_computed_absolute (value, &offset->rad)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (fabs (offset->rad) < 0.01)
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->rad = (offset->rad < 0) ? -0.01 : 0.01;
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->knotSet = false; // knotset=false because it's not set from the context
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( offset->isUpdating == false ) object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev case SP_ATTR_INKSCAPE_HREF:
843e19887f64dde75055cf8842fc4db2171eff45johnlev case SP_ATTR_XLINK_HREF:
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( value == NULL ) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab sp_offset_quit_listening(offset);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( offset->sourceHref ) g_free(offset->sourceHref);
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->sourceHref = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->sourceRef->detach();
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( offset->sourceHref && ( strcmp(value, offset->sourceHref) == 0 ) ) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( offset->sourceHref ) g_free(offset->sourceHref);
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->sourceHref = g_strdup(value);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab try {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->sourceRef->attach(Inkscape::URI(value));
843e19887f64dde75055cf8842fc4db2171eff45johnlev } catch (Inkscape::BadURIException &e) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev g_warning("%s", e.what());
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->sourceRef->detach();
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab break;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab default:
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (((SPObjectClass *) parent_class)->set)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((SPObjectClass *) parent_class)->set (object, key, value);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/**
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * Update callback: the object has changed, recompute its shape.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabsp_offset_update(SPObject *object, SPCtx *ctx, guint flags)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev SPOffset* offset = SP_OFFSET(object);
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->isUpdating=true; // prevent sp_offset_set from requesting updates
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( offset->sourceDirty ) refresh_offset_source(offset);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (flags &
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
843e19887f64dde75055cf8842fc4db2171eff45johnlev SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((SPShape *) object)->setShape ();
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->isUpdating=false;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (((SPObjectClass *) parent_class)->update)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab ((SPObjectClass *) parent_class)->update (object, ctx, flags);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab/**
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * Returns a textual description of object.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic gchar *
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabsp_offset_description(SPItem *item)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab{
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab SPOffset *offset = SP_OFFSET (item);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if ( offset->sourceHref ) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // TRANSLATORS COMMENT: %s is either "outset" or "inset" depending on sign
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab return g_strdup_printf(_("<b>Linked offset</b>, %s by %f pt"),
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab (offset->rad >= 0)? _("outset") : _("inset"), fabs (offset->rad));
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab } else {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // TRANSLATORS COMMENT: %s is either "outset" or "inset" depending on sign
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab return g_strdup_printf(_("<b>Dynamic offset</b>, %s by %f pt"),
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab (offset->rad >= 0)? _("outset") : _("inset"), fabs (offset->rad));
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab/**
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * Compute and set shape's offset.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabsp_offset_set_shape(SPShape *shape)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab{
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab SPOffset *offset = SP_OFFSET (shape);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if ( offset->originalPath == NULL ) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // oops : no path?! (the offset object should do harakiri)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab return;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#ifdef OFFSET_VERBOSE
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab g_print ("rad=%g\n", offset->rad);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab#endif
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // au boulot
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if ( fabs(offset->rad) < 0.01 ) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // grosso modo: 0
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // just put the source shape as the offseted one, no one will notice
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // it's also useless to compute the offset with a 0 radius
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab //XML Tree being used directly here while it shouldn't be.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab const char *res_d = shape->getRepr()->attribute("inkscape:original");
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if ( res_d ) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab Geom::PathVector pv = sp_svg_read_pathv(res_d);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab SPCurve *c = new SPCurve(pv);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab g_assert(c != NULL);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab ((SPShape *) offset)->setCurveInsync (c, TRUE);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab c->unref();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
5d2eda970e48f8985448151c73e699614ce9f357John Levon return;
5d2eda970e48f8985448151c73e699614ce9f357John Levon }
5d2eda970e48f8985448151c73e699614ce9f357John Levon
5d2eda970e48f8985448151c73e699614ce9f357John Levon // extra paraniac careful check. the preceding if () should take care of this case
5d2eda970e48f8985448151c73e699614ce9f357John Levon if (fabs (offset->rad) < 0.01)
5d2eda970e48f8985448151c73e699614ce9f357John Levon offset->rad = (offset->rad < 0) ? -0.01 : 0.01;
5d2eda970e48f8985448151c73e699614ce9f357John Levon
5d2eda970e48f8985448151c73e699614ce9f357John Levon Path *orig = new Path;
5d2eda970e48f8985448151c73e699614ce9f357John Levon orig->Copy ((Path *) offset->originalPath);
5d2eda970e48f8985448151c73e699614ce9f357John Levon
5d2eda970e48f8985448151c73e699614ce9f357John Levon if ( use_slow_but_correct_offset_method == false ) {
5d2eda970e48f8985448151c73e699614ce9f357John Levon // version par outline
5d2eda970e48f8985448151c73e699614ce9f357John Levon Shape *theShape = new Shape;
5d2eda970e48f8985448151c73e699614ce9f357John Levon Shape *theRes = new Shape;
5d2eda970e48f8985448151c73e699614ce9f357John Levon Path *originaux[1];
5d2eda970e48f8985448151c73e699614ce9f357John Levon Path *res = new Path;
5d2eda970e48f8985448151c73e699614ce9f357John Levon res->SetBackData (false);
5d2eda970e48f8985448151c73e699614ce9f357John Levon
5d2eda970e48f8985448151c73e699614ce9f357John Levon // and now: offset
5d2eda970e48f8985448151c73e699614ce9f357John Levon float o_width;
5d2eda970e48f8985448151c73e699614ce9f357John Levon if (offset->rad >= 0)
5d2eda970e48f8985448151c73e699614ce9f357John Levon {
5d2eda970e48f8985448151c73e699614ce9f357John Levon o_width = offset->rad;
5d2eda970e48f8985448151c73e699614ce9f357John Levon orig->OutsideOutline (res, o_width, join_round, butt_straight, 20.0);
5d2eda970e48f8985448151c73e699614ce9f357John Levon }
5d2eda970e48f8985448151c73e699614ce9f357John Levon else
5d2eda970e48f8985448151c73e699614ce9f357John Levon {
5d2eda970e48f8985448151c73e699614ce9f357John Levon o_width = -offset->rad;
5d2eda970e48f8985448151c73e699614ce9f357John Levon orig->OutsideOutline (res, -o_width, join_round, butt_straight, 20.0);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee }
5d2eda970e48f8985448151c73e699614ce9f357John Levon
5d2eda970e48f8985448151c73e699614ce9f357John Levon if (o_width >= 1.0)
5d2eda970e48f8985448151c73e699614ce9f357John Levon {
5d2eda970e48f8985448151c73e699614ce9f357John Levon // res->ConvertForOffset (1.0, orig, offset->rad);
5d2eda970e48f8985448151c73e699614ce9f357John Levon res->ConvertWithBackData (1.0);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee }
5d2eda970e48f8985448151c73e699614ce9f357John Levon else
5d2eda970e48f8985448151c73e699614ce9f357John Levon {
5d2eda970e48f8985448151c73e699614ce9f357John Levon // res->ConvertForOffset (o_width, orig, offset->rad);
5d2eda970e48f8985448151c73e699614ce9f357John Levon res->ConvertWithBackData (o_width);
5d2eda970e48f8985448151c73e699614ce9f357John Levon }
5d2eda970e48f8985448151c73e699614ce9f357John Levon res->Fill (theShape, 0);
5d2eda970e48f8985448151c73e699614ce9f357John Levon theRes->ConvertToShape (theShape, fill_positive);
5d2eda970e48f8985448151c73e699614ce9f357John Levon originaux[0] = res;
5d2eda970e48f8985448151c73e699614ce9f357John Levon
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee theRes->ConvertToForme (orig, 1, originaux);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee
5d2eda970e48f8985448151c73e699614ce9f357John Levon SPItem *item = shape;
5d2eda970e48f8985448151c73e699614ce9f357John Levon Geom::OptRect bbox = item->getBboxDesktop ();
5d2eda970e48f8985448151c73e699614ce9f357John Levon if ( bbox ) {
5d2eda970e48f8985448151c73e699614ce9f357John Levon gdouble size = L2(bbox->dimensions());
5d2eda970e48f8985448151c73e699614ce9f357John Levon gdouble const exp = item->transform.descrim();
5d2eda970e48f8985448151c73e699614ce9f357John Levon if (exp != 0)
5d2eda970e48f8985448151c73e699614ce9f357John Levon size /= exp;
843e19887f64dde75055cf8842fc4db2171eff45johnlev orig->Coalesce (size * 0.001);
843e19887f64dde75055cf8842fc4db2171eff45johnlev //g_print ("coa %g exp %g item %p\n", size * 0.001, exp, item);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev // if (o_width >= 1.0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev // {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // orig->Coalesce (0.1); // small treshhold, since we only want to get rid of small segments
843e19887f64dde75055cf8842fc4db2171eff45johnlev // the curve should already be computed by the Outline() function
843e19887f64dde75055cf8842fc4db2171eff45johnlev // orig->ConvertEvenLines (1.0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev // orig->Simplify (0.5);
843e19887f64dde75055cf8842fc4db2171eff45johnlev // }
843e19887f64dde75055cf8842fc4db2171eff45johnlev // else
843e19887f64dde75055cf8842fc4db2171eff45johnlev // {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // orig->Coalesce (0.1*o_width);
843e19887f64dde75055cf8842fc4db2171eff45johnlev // orig->ConvertEvenLines (o_width);
843e19887f64dde75055cf8842fc4db2171eff45johnlev // orig->Simplify (0.5 * o_width);
843e19887f64dde75055cf8842fc4db2171eff45johnlev // }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete theShape;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab delete theRes;
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete res;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // version par makeoffset
843e19887f64dde75055cf8842fc4db2171eff45johnlev Shape *theShape = new Shape;
843e19887f64dde75055cf8842fc4db2171eff45johnlev Shape *theRes = new Shape;
5d2eda970e48f8985448151c73e699614ce9f357John Levon
5d2eda970e48f8985448151c73e699614ce9f357John Levon
5d2eda970e48f8985448151c73e699614ce9f357John Levon // and now: offset
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee float o_width;
5d2eda970e48f8985448151c73e699614ce9f357John Levon if (offset->rad >= 0)
5d2eda970e48f8985448151c73e699614ce9f357John Levon {
5d2eda970e48f8985448151c73e699614ce9f357John Levon o_width = offset->rad;
5d2eda970e48f8985448151c73e699614ce9f357John Levon }
5d2eda970e48f8985448151c73e699614ce9f357John Levon else
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev o_width = -offset->rad;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev // one has to have a measure of the details
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (o_width >= 1.0)
5d2eda970e48f8985448151c73e699614ce9f357John Levon {
843e19887f64dde75055cf8842fc4db2171eff45johnlev orig->ConvertWithBackData (0.5);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev orig->ConvertWithBackData (0.5*o_width);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev orig->Fill (theShape, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev theRes->ConvertToShape (theShape, fill_positive);
843e19887f64dde75055cf8842fc4db2171eff45johnlev Path *originaux[1];
843e19887f64dde75055cf8842fc4db2171eff45johnlev originaux[0]=orig;
843e19887f64dde75055cf8842fc4db2171eff45johnlev Path *res = new Path;
843e19887f64dde75055cf8842fc4db2171eff45johnlev theRes->ConvertToForme (res, 1, originaux);
843e19887f64dde75055cf8842fc4db2171eff45johnlev int nbPart=0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev Path** parts=res->SubPaths(nbPart,true);
843e19887f64dde75055cf8842fc4db2171eff45johnlev char *holes=(char*)malloc(nbPart*sizeof(char));
843e19887f64dde75055cf8842fc4db2171eff45johnlev // we offset contours separately, because we can.
843e19887f64dde75055cf8842fc4db2171eff45johnlev // this way, we avoid doing a unique big ConvertToShape when dealing with big shapes with lots of holes
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab {
843e19887f64dde75055cf8842fc4db2171eff45johnlev Shape* onePart=new Shape;
843e19887f64dde75055cf8842fc4db2171eff45johnlev Shape* oneCleanPart=new Shape;
843e19887f64dde75055cf8842fc4db2171eff45johnlev theShape->Reset();
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (int i=0;i<nbPart;i++) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev double partSurf=parts[i]->Surface();
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->Convert(1.0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // raffiner si besoin
843e19887f64dde75055cf8842fc4db2171eff45johnlev double bL,bT,bR,bB;
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->PolylineBoundingBox(bL,bT,bR,bB);
843e19887f64dde75055cf8842fc4db2171eff45johnlev double mesure=((bR-bL)+(bB-bT))*0.5;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( mesure < 10.0 ) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->Convert(0.02*mesure);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( partSurf < 0 ) { // inverse par rapport a la realite
843e19887f64dde75055cf8842fc4db2171eff45johnlev // plein
843e19887f64dde75055cf8842fc4db2171eff45johnlev holes[i]=0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->Fill(oneCleanPart,0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev onePart->ConvertToShape(oneCleanPart,fill_positive); // there aren't intersections in that one, but maybe duplicate points and null edges
843e19887f64dde75055cf8842fc4db2171eff45johnlev oneCleanPart->MakeOffset(onePart,offset->rad,join_round,20.0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev onePart->ConvertToShape(oneCleanPart,fill_positive);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev onePart->CalcBBox();
843e19887f64dde75055cf8842fc4db2171eff45johnlev double typicalSize=0.5*((onePart->rightX-onePart->leftX)+(onePart->bottomY-onePart->topY));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( typicalSize < 0.05 ) typicalSize=0.05;
843e19887f64dde75055cf8842fc4db2171eff45johnlev typicalSize*=0.01;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( typicalSize > 1.0 ) typicalSize=1.0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev onePart->ConvertToForme (parts[i]);
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->ConvertEvenLines (typicalSize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->Simplify (typicalSize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev double nPartSurf=parts[i]->Surface();
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( nPartSurf >= 0 ) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // inversion de la surface -> disparait
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete parts[i];
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]=NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev/* int firstP=theShape->nbPt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (int j=0;j<onePart->nbPt;j++) theShape->AddPoint(onePart->pts[j].x);
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (int j=0;j<onePart->nbAr;j++) theShape->AddEdge(firstP+onePart->aretes[j].st,firstP+onePart->aretes[j].en);*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // trou
843e19887f64dde75055cf8842fc4db2171eff45johnlev holes[i]=1;
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->Fill(oneCleanPart,0,false,true,true);
843e19887f64dde75055cf8842fc4db2171eff45johnlev onePart->ConvertToShape(oneCleanPart,fill_positive);
843e19887f64dde75055cf8842fc4db2171eff45johnlev oneCleanPart->MakeOffset(onePart,-offset->rad,join_round,20.0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev onePart->ConvertToShape(oneCleanPart,fill_positive);
843e19887f64dde75055cf8842fc4db2171eff45johnlev// for (int j=0;j<onePart->nbAr;j++) onePart->Inverse(j); // pas oublier de reinverser
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev onePart->CalcBBox();
843e19887f64dde75055cf8842fc4db2171eff45johnlev double typicalSize=0.5*((onePart->rightX-onePart->leftX)+(onePart->bottomY-onePart->topY));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( typicalSize < 0.05 ) typicalSize=0.05;
843e19887f64dde75055cf8842fc4db2171eff45johnlev typicalSize*=0.01;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( typicalSize > 1.0 ) typicalSize=1.0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev onePart->ConvertToForme (parts[i]);
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->ConvertEvenLines (typicalSize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->Simplify (typicalSize);
843e19887f64dde75055cf8842fc4db2171eff45johnlev double nPartSurf=parts[i]->Surface();
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( nPartSurf >= 0 ) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // inversion de la surface -> disparait
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete parts[i];
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]=NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* int firstP=theShape->nbPt;
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (int j=0;j<onePart->nbPt;j++) theShape->AddPoint(onePart->pts[j].x);
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (int j=0;j<onePart->nbAr;j++) theShape->AddEdge(firstP+onePart->aretes[j].en,firstP+onePart->aretes[j].st);*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev// delete parts[i];
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev// theShape->MakeOffset(theRes,offset->rad,join_round,20.0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete onePart;
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete oneCleanPart;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( nbPart > 1 ) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev theShape->Reset();
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (int i=0;i<nbPart;i++) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( parts[i] ) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->ConvertWithBackData(1.0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( holes[i] ) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->Fill(theShape,i,true,true,true);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev parts[i]->Fill(theShape,i,true,true,false);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev theRes->ConvertToShape (theShape, fill_positive);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab theRes->ConvertToForme (orig,nbPart,parts);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab for (int i=0;i<nbPart;i++) if ( parts[i] ) delete parts[i];
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab } else if ( nbPart == 1 ) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab orig->Copy(parts[0]);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab for (int i=0;i<nbPart;i++) if ( parts[i] ) delete parts[i];
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab } else {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab orig->Reset();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab// theRes->ConvertToShape (theShape, fill_positive);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab// theRes->ConvertToForme (orig);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab/* if (o_width >= 1.0) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev orig->ConvertEvenLines (1.0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev orig->Simplify (1.0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev orig->ConvertEvenLines (1.0*o_width);
843e19887f64dde75055cf8842fc4db2171eff45johnlev orig->Simplify (1.0 * o_width);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }*/
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( parts ) free(parts);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( holes ) free(holes);
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete res;
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete theShape;
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete theRes;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab {
843e19887f64dde75055cf8842fc4db2171eff45johnlev char *res_d = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (orig->descr_cmd.size() <= 1)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // Aie.... nothing left.
843e19887f64dde75055cf8842fc4db2171eff45johnlev res_d = strdup ("M 0 0 L 0 0 z");
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab //printf("%s\n",res_d);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev res_d = orig->svg_dump_path ();
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete orig;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::PathVector pv = sp_svg_read_pathv(res_d);
843e19887f64dde75055cf8842fc4db2171eff45johnlev SPCurve *c = new SPCurve(pv);
843e19887f64dde75055cf8842fc4db2171eff45johnlev g_assert(c != NULL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((SPShape *) offset)->setCurveInsync (c, TRUE);
843e19887f64dde75055cf8842fc4db2171eff45johnlev c->unref();
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev free (res_d);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/**
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Virtual snappoints function.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_snappoints(SPItem const *item, std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape::SnapPreferences const *snapprefs)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (((SPItemClass *) parent_class)->snappoints) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((SPItemClass *) parent_class)->snappoints (item, p, snapprefs);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev// utilitaires pour les poignees
843e19887f64dde75055cf8842fc4db2171eff45johnlev// used to get the distance to the shape: distance to polygon give the fabs(radius), we still need
843e19887f64dde75055cf8842fc4db2171eff45johnlev// the sign. for edges, it's easy to determine which side the point is on, for points of the polygon
843e19887f64dde75055cf8842fc4db2171eff45johnlev// it's trickier: we need to identify which angle the point is in; to that effect, we take each
843e19887f64dde75055cf8842fc4db2171eff45johnlev// successive clockwise angle (A,C) and check if the vector B given by the point is in the angle or
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab// outside.
843e19887f64dde75055cf8842fc4db2171eff45johnlev// another method would be to use the Winding() function to test whether the point is inside or outside
843e19887f64dde75055cf8842fc4db2171eff45johnlev// the polygon (it would be wiser to do so, in fact, but i like being stupid)
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/**
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
5d2eda970e48f8985448151c73e699614ce9f357John Levon * \todo
5d2eda970e48f8985448151c73e699614ce9f357John Levon * FIXME: This can be done using linear operations, more stably and
843e19887f64dde75055cf8842fc4db2171eff45johnlev * faster. method: transform A and C into B's space, A should be
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * negative and B should be positive in the orthogonal component. I
843e19887f64dde75055cf8842fc4db2171eff45johnlev * think this is equivalent to
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * dot(A, rot90(B))*dot(C, rot90(B)) == -1.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab * -- njh
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab */
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabbool
843e19887f64dde75055cf8842fc4db2171eff45johnlevvectors_are_clockwise (Geom::Point A, Geom::Point B, Geom::Point C)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev using Geom::rot90;
843e19887f64dde75055cf8842fc4db2171eff45johnlev double ab_s = dot(A, rot90(B));
5d2eda970e48f8985448151c73e699614ce9f357John Levon double ab_c = dot(A, B);
5d2eda970e48f8985448151c73e699614ce9f357John Levon double bc_s = dot(B, rot90(C));
843e19887f64dde75055cf8842fc4db2171eff45johnlev double bc_c = dot(B, C);
5d2eda970e48f8985448151c73e699614ce9f357John Levon double ca_s = dot(C, rot90(A));
5d2eda970e48f8985448151c73e699614ce9f357John Levon double ca_c = dot(C, A);
5d2eda970e48f8985448151c73e699614ce9f357John Levon
5d2eda970e48f8985448151c73e699614ce9f357John Levon double ab_a = acos (ab_c);
5d2eda970e48f8985448151c73e699614ce9f357John Levon if (ab_c <= -1.0)
5d2eda970e48f8985448151c73e699614ce9f357John Levon ab_a = M_PI;
5d2eda970e48f8985448151c73e699614ce9f357John Levon if (ab_c >= 1.0)
5d2eda970e48f8985448151c73e699614ce9f357John Levon ab_a = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ab_s < 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ab_a = 2 * M_PI - ab_a;
843e19887f64dde75055cf8842fc4db2171eff45johnlev double bc_a = acos (bc_c);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (bc_c <= -1.0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev bc_a = M_PI;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (bc_c >= 1.0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev bc_a = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (bc_s < 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev bc_a = 2 * M_PI - bc_a;
843e19887f64dde75055cf8842fc4db2171eff45johnlev double ca_a = acos (ca_c);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ca_c <= -1.0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ca_a = M_PI;
5d2eda970e48f8985448151c73e699614ce9f357John Levon if (ca_c >= 1.0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ca_a = 0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ca_s < 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ca_a = 2 * M_PI - ca_a;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev double lim = 2 * M_PI - ca_a;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ab_a < lim)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return true;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return false;
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
5d2eda970e48f8985448151c73e699614ce9f357John Levon
5d2eda970e48f8985448151c73e699614ce9f357John Levon/**
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Distance to the original path; that function is called from object-edit
5d2eda970e48f8985448151c73e699614ce9f357John Levon * to set the radius when the control knot moves.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * The sign of the result is the radius we're going to offset the shape with,
843e19887f64dde75055cf8842fc4db2171eff45johnlev * so result > 0 ==outset and result < 0 ==inset. thus result<0 means
843e19887f64dde75055cf8842fc4db2171eff45johnlev * 'px inside source'.
5d2eda970e48f8985448151c73e699614ce9f357John Levon */
5d2eda970e48f8985448151c73e699614ce9f357John Levondouble
5d2eda970e48f8985448151c73e699614ce9f357John Levonsp_offset_distance_to_original (SPOffset * offset, Geom::Point px)
5d2eda970e48f8985448151c73e699614ce9f357John Levon{
5d2eda970e48f8985448151c73e699614ce9f357John Levon if (offset == NULL || offset->originalPath == NULL
5d2eda970e48f8985448151c73e699614ce9f357John Levon || ((Path *) offset->originalPath)->descr_cmd.size() <= 1)
5d2eda970e48f8985448151c73e699614ce9f357John Levon return 1.0;
5d2eda970e48f8985448151c73e699614ce9f357John Levon double dist = 1.0;
5d2eda970e48f8985448151c73e699614ce9f357John Levon Shape *theShape = new Shape;
5d2eda970e48f8985448151c73e699614ce9f357John Levon Shape *theRes = new Shape;
5d2eda970e48f8985448151c73e699614ce9f357John Levon
5d2eda970e48f8985448151c73e699614ce9f357John Levon /** \todo
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Awfully damn stupid method: uncross the source path EACH TIME you
843e19887f64dde75055cf8842fc4db2171eff45johnlev * need to compute the distance. The good way to do this would be to
843e19887f64dde75055cf8842fc4db2171eff45johnlev * store the uncrossed source path somewhere, and delete it when the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * context is finished. Hopefully this part is much faster than actually
843e19887f64dde75055cf8842fc4db2171eff45johnlev * computing the offset (which happen just after), so the time spent in
843e19887f64dde75055cf8842fc4db2171eff45johnlev * this function should end up being negligible with respect to the
843e19887f64dde75055cf8842fc4db2171eff45johnlev * delay of one context.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev // move
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((Path *) offset->originalPath)->Convert (1.0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev ((Path *) offset->originalPath)->Fill (theShape, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev theRes->ConvertToShape (theShape, fill_oddEven);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (theRes->numberOfEdges() <= 1)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev double ptDist = -1.0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bool ptSet = false;
843e19887f64dde75055cf8842fc4db2171eff45johnlev double arDist = -1.0;
843e19887f64dde75055cf8842fc4db2171eff45johnlev bool arSet = false;
843e19887f64dde75055cf8842fc4db2171eff45johnlev // first get the minimum distance to the points
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (int i = 0; i < theRes->numberOfPoints(); i++)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (theRes->getPoint(i).totalDegree() > 0)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Point nx = theRes->getPoint(i).x;
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Point nxpx = px-nx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev double ndist = sqrt (dot(nxpx,nxpx));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ptSet == false || fabs (ndist) < fabs (ptDist))
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // we have a new minimum distance
843e19887f64dde75055cf8842fc4db2171eff45johnlev // now we need to wheck if px is inside or outside (for the sign)
843e19887f64dde75055cf8842fc4db2171eff45johnlev nx = px - to_2geom(theRes->getPoint(i).x);
843e19887f64dde75055cf8842fc4db2171eff45johnlev double nlen = sqrt (dot(nx , nx));
843e19887f64dde75055cf8842fc4db2171eff45johnlev nx /= nlen;
843e19887f64dde75055cf8842fc4db2171eff45johnlev int pb, cb, fb;
843e19887f64dde75055cf8842fc4db2171eff45johnlev fb = theRes->getPoint(i).incidentEdge[LAST];
843e19887f64dde75055cf8842fc4db2171eff45johnlev pb = theRes->getPoint(i).incidentEdge[LAST];
843e19887f64dde75055cf8842fc4db2171eff45johnlev cb = theRes->getPoint(i).incidentEdge[FIRST];
843e19887f64dde75055cf8842fc4db2171eff45johnlev do
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // one angle
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Point prx, nex;
843e19887f64dde75055cf8842fc4db2171eff45johnlev prx = theRes->getEdge(pb).dx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev nlen = sqrt (dot(prx, prx));
843e19887f64dde75055cf8842fc4db2171eff45johnlev prx /= nlen;
843e19887f64dde75055cf8842fc4db2171eff45johnlev nex = theRes->getEdge(cb).dx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev nlen = sqrt (dot(nex , nex));
843e19887f64dde75055cf8842fc4db2171eff45johnlev nex /= nlen;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (theRes->getEdge(pb).en == i)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev prx = -prx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (theRes->getEdge(cb).en == i)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev nex = -nex;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (vectors_are_clockwise (nex, nx, prx))
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // we're in that angle. set the sign, and exit that loop
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (theRes->getEdge(cb).st == i)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptDist = -ndist;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptSet = true;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptDist = ndist;
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptSet = true;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev break;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev pb = cb;
843e19887f64dde75055cf8842fc4db2171eff45johnlev cb = theRes->NextAt (i, cb);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev while (cb >= 0 && pb >= 0 && pb != fb);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev // loop over the edges to try to improve the distance
843e19887f64dde75055cf8842fc4db2171eff45johnlev for (int i = 0; i < theRes->numberOfEdges(); i++)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Point sx = theRes->getPoint(theRes->getEdge(i).st).x;
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Point ex = theRes->getPoint(theRes->getEdge(i).en).x;
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Point nx = ex - sx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev double len = sqrt (dot(nx,nx));
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (len > 0.0001)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Point pxsx=px-sx;
843e19887f64dde75055cf8842fc4db2171eff45johnlev double ab = dot(nx,pxsx);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ab > 0 && ab < len * len)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // we're in the zone of influence of the segment
843e19887f64dde75055cf8842fc4db2171eff45johnlev double ndist = (cross(pxsx,nx)) / len;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (arSet == false || fabs (ndist) < fabs (arDist))
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev arDist = ndist;
843e19887f64dde75055cf8842fc4db2171eff45johnlev arSet = true;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (arSet || ptSet)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (arSet == false)
843e19887f64dde75055cf8842fc4db2171eff45johnlev arDist = ptDist;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (ptSet == false)
843e19887f64dde75055cf8842fc4db2171eff45johnlev ptDist = arDist;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (fabs (ptDist) < fabs (arDist))
843e19887f64dde75055cf8842fc4db2171eff45johnlev dist = ptDist;
843e19887f64dde75055cf8842fc4db2171eff45johnlev else
843e19887f64dde75055cf8842fc4db2171eff45johnlev dist = arDist;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete theShape;
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete theRes;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev return dist;
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev/**
843e19887f64dde75055cf8842fc4db2171eff45johnlev * Computes a point on the offset; used to set a "seed" position for
843e19887f64dde75055cf8842fc4db2171eff45johnlev * the control knot.
843e19887f64dde75055cf8842fc4db2171eff45johnlev *
843e19887f64dde75055cf8842fc4db2171eff45johnlev * \return the topmost point on the offset.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlevvoid
843e19887f64dde75055cf8842fc4db2171eff45johnlevsp_offset_top_point (SPOffset * offset, Geom::Point *px)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev (*px) = Geom::Point(0, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (offset == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (offset->knotSet)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev (*px) = offset->knot;
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev SPCurve *curve = SP_SHAPE (offset)->getCurve();
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (curve == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev sp_offset_set_shape (SP_SHAPE (offset));
843e19887f64dde75055cf8842fc4db2171eff45johnlev curve = SP_SHAPE (offset)->getCurve();
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (curve == NULL)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (curve->is_empty())
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev curve->unref();
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev Path *finalPath = new Path;
843e19887f64dde75055cf8842fc4db2171eff45johnlev finalPath->LoadPathVector(curve->get_pathvector());
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev Shape *theShape = new Shape;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev finalPath->Convert (1.0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev finalPath->Fill (theShape, 0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (theShape->hasPoints())
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
843e19887f64dde75055cf8842fc4db2171eff45johnlev theShape->SortPoints ();
843e19887f64dde75055cf8842fc4db2171eff45johnlev *px = theShape->getPoint(0).x;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete theShape;
843e19887f64dde75055cf8842fc4db2171eff45johnlev delete finalPath;
843e19887f64dde75055cf8842fc4db2171eff45johnlev curve->unref();
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev// the listening functions
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_start_listening(SPOffset *offset,SPObject* to)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( to == NULL ) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->sourceObject = to;
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->sourceRepr = to->getRepr();
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_delete_connection = to->connectDelete(sigc::bind(sigc::ptr_fun(&sp_offset_delete_self), offset));
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_transformed_connection = SP_ITEM(to)->connectTransformed(sigc::bind(sigc::ptr_fun(&sp_offset_move_compensate), offset));
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_modified_connection = to->connectModified(sigc::bind<2>(sigc::ptr_fun(&sp_offset_source_modified), offset));
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void sp_offset_quit_listening(SPOffset *offset)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev if ( offset->sourceObject == NULL )
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_modified_connection.disconnect();
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_delete_connection.disconnect();
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->_transformed_connection.disconnect();
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->sourceRepr = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->sourceObject = NULL;
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevsp_offset_href_changed(SPObject */*old_ref*/, SPObject */*ref*/, SPOffset *offset)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev sp_offset_quit_listening(offset);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (offset->sourceRef) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev SPItem *refobj = offset->sourceRef->getObject();
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (refobj) sp_offset_start_listening(offset,refobj);
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->sourceDirty=true;
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevsp_offset_move_compensate(Geom::Affine const *mp, SPItem */*original*/, SPOffset *self)
843e19887f64dde75055cf8842fc4db2171eff45johnlev{
843e19887f64dde75055cf8842fc4db2171eff45johnlev Inkscape::Preferences *prefs = Inkscape::Preferences::get();
843e19887f64dde75055cf8842fc4db2171eff45johnlev guint mode = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_PARALLEL);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev SPItem *item = SP_ITEM(self);
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Affine m(*mp);
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!(m.isTranslation()) || mode == SP_CLONE_COMPENSATION_NONE) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev self->sourceDirty=true;
843e19887f64dde75055cf8842fc4db2171eff45johnlev item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
843e19887f64dde75055cf8842fc4db2171eff45johnlev return;
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev // calculate the compensation matrix and the advertized movement matrix
843e19887f64dde75055cf8842fc4db2171eff45johnlev item->readAttr("transform");
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Affine t = self->transform;
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Affine offset_move = t.inverse() * m * t;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev Geom::Affine advertized_move;
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (mode == SP_CLONE_COMPENSATION_PARALLEL) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset_move = offset_move.inverse() * m;
843e19887f64dde75055cf8842fc4db2171eff45johnlev advertized_move = m;
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else if (mode == SP_CLONE_COMPENSATION_UNMOVED) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset_move = offset_move.inverse();
843e19887f64dde75055cf8842fc4db2171eff45johnlev advertized_move.setIdentity();
843e19887f64dde75055cf8842fc4db2171eff45johnlev } else {
843e19887f64dde75055cf8842fc4db2171eff45johnlev g_assert_not_reached();
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab self->sourceDirty=true;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // commit the compensation
843e19887f64dde75055cf8842fc4db2171eff45johnlev item->transform *= offset_move;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee item->doWriteTransform(item->getRepr(), item->transform, &advertized_move);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
843e19887f64dde75055cf8842fc4db2171eff45johnlevstatic void
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabsp_offset_delete_self(SPObject */*deleted*/, SPOffset *offset)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab{
843e19887f64dde75055cf8842fc4db2171eff45johnlev Inkscape::Preferences *prefs = Inkscape::Preferences::get();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab guint const mode = prefs->getInt("/options/cloneorphans/value", SP_CLONE_ORPHANS_UNLINK);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (mode == SP_CLONE_ORPHANS_UNLINK) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev // leave it be. just forget about the source
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab sp_offset_quit_listening(offset);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if ( offset->sourceHref ) g_free(offset->sourceHref);
843e19887f64dde75055cf8842fc4db2171eff45johnlev offset->sourceHref = NULL;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->sourceRef->detach();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab } else if (mode == SP_CLONE_ORPHANS_DELETE) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->deleteObject();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
843e19887f64dde75055cf8842fc4db2171eff45johnlev}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabstatic void
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabsp_offset_source_modified (SPObject */*iSource*/, guint flags, SPItem *item)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab{
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab SPOffset *offset = SP_OFFSET(item);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->sourceDirty=true;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG)) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee}
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybeestatic void
843e19887f64dde75055cf8842fc4db2171eff45johnlevrefresh_offset_source(SPOffset* offset)
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee{
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if ( offset == NULL ) return;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->sourceDirty=false;
843e19887f64dde75055cf8842fc4db2171eff45johnlev
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee // le mauvais cas: pas d'attribut d => il faut verifier que c'est une SPShape puis prendre le contour
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee // The bad case: no d attribute. Must check that it's an SPShape and then take the outline.
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee SPObject *refobj=offset->sourceObject;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee if ( refobj == NULL ) return;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee SPItem *item = SP_ITEM (refobj);
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee SPCurve *curve=NULL;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (!SP_IS_SHAPE (item) && !SP_IS_TEXT (item)) return;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (SP_IS_SHAPE (item)) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab curve = SP_SHAPE (item)->getCurve ();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (curve == NULL)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab return;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (SP_IS_TEXT (item)) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab curve = SP_TEXT (item)->getNormalizedBpath ();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (curve == NULL)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab return;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab Path *orig = new Path;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab orig->LoadPathVector(curve->get_pathvector());
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab curve->unref();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (!item->transform.isIdentity()) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab gchar const *t_attr = item->getRepr()->attribute("transform");
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (t_attr) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab Geom::Affine t;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (sp_svg_transform_read(t_attr, &t)) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab orig->Transform(t);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // Finish up.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab SPCSSAttr *css;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab const gchar *val;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab Shape *theShape = new Shape;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee Shape *theRes = new Shape;
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee orig->ConvertWithBackData (1.0);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab orig->Fill (theShape, 0);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab css = sp_repr_css_attr (offset->sourceRepr , "style");
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab val = sp_repr_css_property (css, "fill-rule", NULL);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (val && strcmp (val, "nonzero") == 0)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab theRes->ConvertToShape (theShape, fill_nonZero);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab else if (val && strcmp (val, "evenodd") == 0)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab {
843e19887f64dde75055cf8842fc4db2171eff45johnlev theRes->ConvertToShape (theShape, fill_oddEven);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab else
843e19887f64dde75055cf8842fc4db2171eff45johnlev {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab theRes->ConvertToShape (theShape, fill_nonZero);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab Path *originaux[1];
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab originaux[0] = orig;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab Path *res = new Path;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab theRes->ConvertToForme (res, 1, originaux);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab delete theShape;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab delete theRes;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab char *res_d = res->svg_dump_path ();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab delete res;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab delete orig;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab // TODO fix:
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab //XML Tree being used diectly here while it shouldn't be.
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab offset->getRepr()->setAttribute("inkscape:original", res_d);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab free (res_d);
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabSPItem *
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rabsp_offset_get_source (SPOffset *offset)
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab{
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (offset && offset->sourceRef) {
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab SPItem *refobj = offset->sourceRef->getObject();
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab if (SP_IS_ITEM (refobj))
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (SPItem *) refobj;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab }
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab return NULL;
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab}
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab/*
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab Local Variables:
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab mode:c++
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab c-file-style:"stroustrup"
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab indent-tabs-mode:nil
349b53dd4e695e3d833b5380540385145b2d3ae8Stuart Maybee fill-column:99
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab End:
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab*/
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
a576ab5b6e08c47732b3dedca9eaa8a8cbb85720rab