lpe-knot.cpp revision 3cc557d7f2d5572ff54d324a0f8c01e704cc5b56
/**
* @file
* LPE knot effect implementation.
*/
/* Authors:
* Jean-Francois Barraud <jf.barraud@gmail.com>
* Abhishek Sharma
*
* Copyright (C) 2007 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "sp-shape.h"
#include "sp-path.h"
#include "live_effects/lpe-knot.h"
#include "style.h"
#include "knot-holder-entity.h"
//#include <2geom/crossing.h>
// for change crossing undo
#include "verbs.h"
#include "document.h"
#include <exception>
namespace Inkscape {
namespace LivePathEffect {
class KnotHolderEntityCrossingSwitcher : public LPEKnotHolderEntity
{
public:
virtual ~KnotHolderEntityCrossingSwitcher() {}
};
// if path is closed and closing segment is not degenerate
}
return retval;
}
//---------------------------------------------------------------------------
//LPEKnot specific Interval manipulation.
//---------------------------------------------------------------------------
//remove an interval from an union of intervals.
//TODO: is it worth moving it to 2Geom?
static
}
}
return ret;
}
//find the time interval during which patha is hidden by pathb near a given crossing.
// Warning: not accurate!
static
using namespace Geom;
for (unsigned i = 0; i < size_nondegenerate(patha); i++){
times_i[k]+=i;
}
}
if ( rk > 0 )
}
}
//---------------------------------------------------------------------------
//LPEKnot specific Crossing Data manipulation.
//---------------------------------------------------------------------------
//Yet another crossing data representation.
// an CrossingPoint stores
// -an intersection point
// -the involved path components
// -for each component, the time at which this crossing occurs + the order of this crossing along the component (when starting from 0).
namespace LPEKnotNS {//just in case...
CrossingPoints::CrossingPoints(std::vector<Geom::Path> const &paths) : std::vector<CrossingPoint>(){
// std::cout<<"\nCrossingPoints creation from path vector\n";
// std::cout<<"--(self int)\n";
// std::cout << paths[i][ii].toSBasis()[Geom::X] <<"\n";
// std::cout << paths[i][ii].toSBasis()[Geom::Y] <<"\n";
}else{
// std::cout<<"--(pair int)\n";
// std::cout << paths[i][ii].toSBasis()[Geom::X] <<"\n";
// std::cout << paths[i][ii].toSBasis()[Geom::Y] <<"\n";
// std::cout<<"with\n";
// std::cout << paths[j][jj].toSBasis()[Geom::X] <<"\n";
// std::cout << paths[j][jj].toSBasis()[Geom::Y] <<"\n";
}
//std::cout<<"intersection "<<i<<"["<<ii<<"]("<<times[k].first<<")= "<<j<<"["<<jj<<"]("<<times[k].second<<")\n";
if (times[k].first == times[k].first && times[k].second == times[k].second ){//is this the way to test NaN?
double zero = 1e-4;
if ( i==j && fabs(times[k].first+ii - times[k].second-jj)<=zero ){//this is just end=start of successive curves in a path.
continue;
}
continue;
}
cp.i = i;
cp.j = j;
}else{
//std::cout<<"intersection "<<i<<"["<<ii<<"](NaN)= "<<j<<"["<<jj<<"](NaN)\n";
}
}
}
}
}
}
for( unsigned k=0; k<size(); k++){
CrossingPoint cp = (*this)[k];
}
unsigned count = 0;
}else{
}
count++;
}
}
}
{
using namespace Geom;
}
}
}
{
using namespace Geom;
for( unsigned n=0; n<size(); n++){
CrossingPoint cp = (*this)[n];
}
return result;
}
//FIXME: rewrite to check success: return bool, put result in arg.
{
for (unsigned k=0; k<size(); k++){
if (
) return (*this)[k];
}
assert(false);//debug purpose...
return CrossingPoint();
}
unsigned
{
double dist=-1;
result = k;
}
}
return result;
}
//TODO: Find a way to warn the user when the topology changes.
//TODO: be smarter at guessing the signs when the topology changed?
void
{
bool topo_changed = false;
for (unsigned n=0; n<size(); n++){
other[n].i == (*this)[n].i &&
other[n].j == (*this)[n].j &&
{
}else{
topo_changed = true;
break;
}
}
if (topo_changed){
//TODO: Find a way to warn the user!!
// std::cout<<"knot topolgy changed!\n";
for (unsigned n=0; n<size(); n++){
}else{
(*this)[n].sign = default_value;
}
}
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//LPEKnot effect.
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// initialise your parameters here:
interruption_width(_("Fi_xed width:"), _("Size of hidden region of lower string"), "interruption_width", &wr, this, 3),
prop_to_stroke_width(_("_In units of stroke width"), _("Consider 'Interruption width' as a ratio of stroke width"), "prop_to_stroke_width", &wr, this, true),
add_stroke_width(_("St_roke width"), _("Add the stroke width to the interruption size"), "add_stroke_width", &wr, this, true),
add_other_stroke_width(_("_Crossing path stroke width"), _("Add crossed stroke width to the interruption size"), "add_other_stroke_width", &wr, this, true),
switcher_size(_("S_witcher size:"), _("Orientation indicator/switcher size"), "switcher_size", &wr, this, 15),
crossing_points_vector(_("Crossing Signs"), _("Crossings signs"), "crossing_points_vector", &wr, this),
gpaths(),gstroke_widths()
{
// register all your parameters here, so Inkscape knows which parameters this effect has:
registerKnotHolderHandle(new KnotHolderEntityCrossingSwitcher(), _("Drag to select a crossing, click to flip it"));
selectedCrossing = 0;
}
{
}
void
//std::cout<<"placing switcher at "<<switcher<<" \n";
}else if (crossing_points.size()>0){
selectedCrossing = 0;
//std::cout<<"placing switcher at "<<switcher<<" \n";
}else{
//std::cout<<"hiding switcher!\n";
//TODO: is there a way to properly hide the helper.
//switcher = Geom::Point(Geom::infinity(),Geom::infinity());
}
}
{
using namespace Geom;
return path_in;
}
//find the relevant path component in gpaths (required to allow groups!)
//Q: do we always recieve the group members in the same order? can we rest on that?
unsigned i0 = 0;
}
if (i0 == gpaths.size() ) {THROW_EXCEPTION("lpe-knot error: group member not recognized");}// this should not happen...
for (unsigned p = 0; p < crossing_points.size(); p++){
unsigned i = crossing_points[p].i;
unsigned j = crossing_points[p].j;
double curveidx, t;
bool i0_is_under = false;
i0_is_under = ( i == i0 );
if (j == i0){
i0_is_under = true;
}
}
if (i0_is_under){
double width = interruption_width;
if ( prop_to_stroke_width.get_value() ) {
width *= gstroke_widths[i];
}
if ( add_stroke_width.get_value() ) {
width += gstroke_widths[i];
}
if ( add_other_stroke_width.get_value() ) {
width += gstroke_widths[j];
}
}else{
}
}
}
}
//If the all component is hidden, continue.
continue;
}
if ( gpaths[i0].closed() && dom.front().min() == 0 && dom.back().max() == size_nondegenerate(gpaths[i0]) ){
continue;
}else{
// std::cout<<"fusing first and last component\n";
beg_comp++;
end_comp--;
//FIXME: STITCH_DISCONTINUOUS should not be necessary (?!?)
}
}
}
}
return path_out;
}
//recursively collect gpaths and stroke widths (stolen from "sp-lpe_item.cpp").
void collectPathsAndWidths (SPLPEItem const *lpeitem, std::vector<Geom::Path> &paths, std::vector<double> &stroke_widths){
if (SP_IS_GROUP(lpeitem)) {
if (SP_IS_LPE_ITEM(subitem)) {
}
}
}
else if (SP_IS_SHAPE(lpeitem)) {
if (SP_IS_PATH(lpeitem)) {
} else {
}
if (c) {
//FIXME: do we have to be more carefull when trying to access stroke width?
}
}
}
}
void
{
using namespace Geom;
// std::cout<<"\nPaths on input:\n";
// for (unsigned i=0; i<gpaths.size(); i++){
// for (unsigned ii=0; ii<gpaths[i].size(); ii++){
// std::cout << gpaths[i][ii].toSBasis()[Geom::X] <<"\n";
// std::cout << gpaths[i][ii].toSBasis()[Geom::Y] <<"\n";
// std::cout<<"--\n";
// }
// }
//std::cout<<"crossing_pts_vect: "<<crossing_points_vector.param_getSVGValue()<<".\n";
//std::cout<<"prop_to_stroke_width: "<<prop_to_stroke_width.param_getSVGValue()<<".\n";
// std::cout<<"\nVectorParam size:"<<crossing_points_vector.data().size()<<"\n";
// std::cout<<"\nOld crdata ("<<old_crdata.size()<<"): \n";
// for (unsigned toto=0; toto<old_crdata.size(); toto++){
// std::cout<<"(";
// std::cout<<old_crdata[toto].i<<",";
// std::cout<<old_crdata[toto].j<<",";
// std::cout<<old_crdata[toto].ni<<",";
// std::cout<<old_crdata[toto].nj<<",";
// std::cout<<old_crdata[toto].ti<<",";
// std::cout<<old_crdata[toto].tj<<",";
// std::cout<<old_crdata[toto].sign<<"),";
// }
//if ( old_crdata.size() > 0 ) std::cout<<"first crossing sign = "<<old_crdata[0].sign<<".\n";
//else std::cout<<"old data is empty!!\n";
// std::cout<<"\nNew crdata ("<<crossing_points.size()<<"): \n";
// for (unsigned toto=0; toto<crossing_points.size(); toto++){
// std::cout<<"(";
// std::cout<<crossing_points[toto].i<<",";
// std::cout<<crossing_points[toto].j<<",";
// std::cout<<crossing_points[toto].ni<<",";
// std::cout<<crossing_points[toto].nj<<",";
// std::cout<<crossing_points[toto].ti<<",";
// std::cout<<crossing_points[toto].tj<<",";
// std::cout<<crossing_points[toto].sign<<"),";
// }
}
static LPEKnot *
{
g_print ("Warning: Effect is not of type LPEKnot!\n");
return NULL;
}
}
void
{
using namespace Geom;
double r = switcher_size*.1;
char const * svgd;
//TODO: use a nice path!
//svgd = "M -10,0 A 10 10 0 1 0 0,-10 l 5,-1 -1,2";
svgd = "m -7.07,7.07 c 3.9,3.91 10.24,3.91 14.14,0 3.91,-3.9 3.91,-10.24 0,-14.14 -3.9,-3.91 -10.24,-3.91 -14.14,0 l 2.83,-4.24 0.7,2.12";
//svgd = "M 10,0 A 10 10 0 1 1 0,-10 l -5,-1 1,2";
svgd = "m 7.07,7.07 c -3.9,3.91 -10.24,3.91 -14.14,0 -3.91,-3.9 -3.91,-10.24 0,-14.14 3.9,-3.91 10.24,-3.91 14.14,0 l -2.83,-4.24 -0.7,2.12";
}else{
//svgd = "M 10,0 A 10 10 0 1 0 -10,0 A 10 10 0 1 0 10,0 ";
svgd = "M 10,0 C 10,5.52 5.52,10 0,10 -5.52,10 -10,5.52 -10,0 c 0,-5.52 4.48,-10 10,-10 5.52,0 10,4.48 10,10 z";
}
}
void
KnotHolderEntityCrossingSwitcher::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint /*state*/)
{
lpe->updateSwitcher();
// FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
}
{
}
void
{
unsigned s = lpe->selectedCrossing;
if (state & GDK_SHIFT_MASK){
}else{
//std::cout<<"crossing set to"<<lpe->crossing_points[s].sign<<".\n";
}
DocumentUndo::done(lpe->getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, /// @todo Is this the right verb?
_("Change knot crossing"));
// FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
// sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
}
}
/* ######################## */
} // namespace LivePathEffect
} // namespace Inkscape
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :