X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-core%2Ftrunk%2Fsrc%2Fmodules%2Fmod_geometry%2Foutline.cpp;h=e84effb2a99d78523f7d56d07e182807fe25130c;hb=4ba22fb51d97f1ecce04dcc5e40569a4354c1bae;hp=7144f024812b29ba76cb556fdf052b94be1381dc;hpb=28f28705612902c15cd0702cc891fba35bf2d2df;p=synfig.git diff --git a/synfig-core/trunk/src/modules/mod_geometry/outline.cpp b/synfig-core/trunk/src/modules/mod_geometry/outline.cpp index 7144f02..e84effb 100644 --- a/synfig-core/trunk/src/modules/mod_geometry/outline.cpp +++ b/synfig-core/trunk/src/modules/mod_geometry/outline.cpp @@ -1,20 +1,22 @@ /* === S Y N F I G ========================================================= */ -/*! \file bline.cpp -** \brief Template +/*! \file outline.cpp +** \brief Implementation of the "Outline" layer ** -** $Id: outline.cpp,v 1.1.1.1 2005/01/04 01:23:10 darco Exp $ +** $Id$ ** ** \legal -** Copyright (c) 2002 Robert B. Quattlebaum Jr. +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007, 2008 Chris Moore ** -** This software and associated documentation -** are CONFIDENTIAL and PROPRIETARY property of -** the above-mentioned copyright holder. +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. ** -** You may not copy, print, publish, or in any -** other way distribute this software without -** a prior written agreement with -** the copyright holder. +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. ** \endlegal */ /* ========================================================================= */ @@ -65,14 +67,14 @@ using namespace etl; SYNFIG_LAYER_INIT(Outline); SYNFIG_LAYER_SET_NAME(Outline,"outline"); -SYNFIG_LAYER_SET_LOCAL_NAME(Outline,_("Outline")); -SYNFIG_LAYER_SET_CATEGORY(Outline,_("Geometry")); +SYNFIG_LAYER_SET_LOCAL_NAME(Outline,N_("Outline")); +SYNFIG_LAYER_SET_CATEGORY(Outline,N_("Geometry")); SYNFIG_LAYER_SET_VERSION(Outline,"0.2"); -SYNFIG_LAYER_SET_CVS_ID(Outline,"$Id: outline.cpp,v 1.1.1.1 2005/01/04 01:23:10 darco Exp $"); +SYNFIG_LAYER_SET_CVS_ID(Outline,"$Id$"); /* === P R O C E D U R E S ================================================= */ -// This function was adapted from what was +// This function was adapted from what was // described on http://www.whisqu.se/per/docs/math28.htm Point line_intersection( const Point& p1, @@ -92,24 +94,24 @@ Point line_intersection( const float x3(p2[0]+t2[0]); const float y3(p2[1]+t2[1]); - + const float near_infinity((float)1e+10); - + float m1,m2; // the slopes of each line - - // compute slopes, note the cludge for infinity, however, this will + + // compute slopes, note the kluge for infinity, however, this will // be close enough - + if ((x1-x0)!=0) m1 = (y1-y0)/(x1-x0); else m1 = near_infinity; - + if ((x3-x2)!=0) m2 = (y3-y2)/(x3-x2); else m2 = near_infinity; - + // compute constants const float& a1(m1); const float& a2(m2); @@ -117,11 +119,11 @@ Point line_intersection( const float b2(-1.0f); const float c1(y0-m1*x0); const float c2(y2-m2*x2); - + // compute the inverse of the determinate const float det_inv(1.0f/(a1*b2 - a2*b1)); - - // use Kramers rule to compute the intersection + + // use Kramers rule to compute the intersection return Point( ((b1*c2 - b2*c1)*det_inv), ((a2*c1 - a1*c2)*det_inv) @@ -142,22 +144,22 @@ Outline::Outline() expand=0; homogeneous_width=true; clear(); - + vector bline_point_list; bline_point_list.push_back(BLinePoint()); bline_point_list.push_back(BLinePoint()); bline_point_list.push_back(BLinePoint()); - bline_point_list[0].set_vertex(Point(0,1)); - bline_point_list[1].set_vertex(Point(0,-1)); + bline_point_list[0].set_vertex(Point(0,1)); + bline_point_list[1].set_vertex(Point(0,-1)); bline_point_list[2].set_vertex(Point(1,0)); - bline_point_list[0].set_tangent(bline_point_list[1].get_vertex()-bline_point_list[2].get_vertex()*0.5f); - bline_point_list[1].set_tangent(bline_point_list[2].get_vertex()-bline_point_list[0].get_vertex()*0.5f); - bline_point_list[2].set_tangent(bline_point_list[0].get_vertex()-bline_point_list[1].get_vertex()*0.5f); - bline_point_list[0].set_width(1.0f); - bline_point_list[1].set_width(1.0f); - bline_point_list[2].set_width(1.0f); + bline_point_list[0].set_tangent(bline_point_list[1].get_vertex()-bline_point_list[2].get_vertex()*0.5f); + bline_point_list[1].set_tangent(bline_point_list[2].get_vertex()-bline_point_list[0].get_vertex()*0.5f); + bline_point_list[2].set_tangent(bline_point_list[0].get_vertex()-bline_point_list[1].get_vertex()*0.5f); + bline_point_list[0].set_width(1.0f); + bline_point_list[1].set_width(1.0f); + bline_point_list[2].set_width(1.0f); bline=bline_point_list; - + needs_sync=true; } @@ -170,13 +172,28 @@ void Outline::sync() { clear(); + + if (!bline.get_list().size()) + { + synfig::warning(string("Outline::sync():")+N_("No vertices in outline " + string("\"") + get_description() + string("\""))); + return; + } + try { #if 1 - + const bool loop(bline.get_loop()); + + ValueNode_BLine::Handle bline_valuenode; + if (bline.get_contained_type() == ValueBase::TYPE_SEGMENT) + { + bline_valuenode = ValueNode_BLine::create(bline); + bline = (*bline_valuenode)(0); + } + const vector bline_(bline.get_list().begin(),bline.get_list().end()); #define bline bline_ - + vector::const_iterator iter, next(bline.begin()); @@ -187,28 +204,49 @@ Outline::sync() vector side_a, side_b; - + if(loop) iter=--bline.end(); else iter=next++; + // iter next + // ---- ---- + // looped nth 1st + // !looped 1st 2nd + + Vector first_tangent=bline.front().get_tangent2(); Vector last_tangent=iter->get_tangent1(); - - for(bool first=!loop;next!=end;iter=next++,first=false) + + // if we are looped and drawing sharp cusps, we'll need a value for the incoming tangent + if (loop && sharp_cusps && last_tangent.is_equal_to(Vector::zero())) + { + hermite curve((iter-1)->get_vertex(), iter->get_vertex(), (iter-1)->get_tangent2(), iter->get_tangent1()); + const derivative< hermite > deriv(curve); + last_tangent=deriv(1.0-CUSP_TANGENT_ADJUST); + } + + // `first' is for making the cusps; don't do that for the first point if we're not looped + for(bool first=!loop; next!=end; iter=next++) { Vector prev_t(iter->get_tangent1()); Vector iter_t(iter->get_tangent2()); Vector next_t(next->get_tangent1()); - + bool split_flag(iter->get_split_tangent_flag()); - + + // if iter.t2 == 0 and next.t1 == 0, this is a straight line if(iter_t.is_equal_to(Vector::zero()) && next_t.is_equal_to(Vector::zero())) { iter_t=next_t=next->get_vertex()-iter->get_vertex(); - split_flag=true; + // split_flag=true; + + // if the two points are on top of each other, ignore this segment + // leave `first' true if was before + if (iter_t.is_equal_to(Vector::zero())) + continue; } - + // Setup the curve hermite curve( iter->get_vertex(), @@ -216,35 +254,38 @@ Outline::sync() iter_t, next_t ); - + const float iter_w((iter->get_width()*width)*0.5f+expand), next_w((next->get_width()*width)*0.5f+expand); const derivative< hermite > deriv(curve); - + + if (first) + first_tangent = deriv(CUSP_TANGENT_ADJUST); + // Make cusps as necessary if(!first && sharp_cusps && split_flag && (!prev_t.is_equal_to(iter_t) || iter_t.is_equal_to(Vector::zero())) && !last_tangent.is_equal_to(Vector::zero())) { Vector curr_tangent(deriv(CUSP_TANGENT_ADJUST)); - + const Vector t1(last_tangent.perp().norm()); const Vector t2(curr_tangent.perp().norm()); - + Real cross(t1*t2.perp()); Real perp((t1-t2).mag()); - if(cross>CUSP_THRESHOLD) + if(cross>CUSP_THRESHOLD) { const Point p1(iter->get_vertex()+t1*iter_w); const Point p2(iter->get_vertex()+t2*iter_w); - + side_a.push_back(line_intersection(p1,last_tangent,p2,curr_tangent)); } else if(cross<-CUSP_THRESHOLD) { const Point p1(iter->get_vertex()-t1*iter_w); const Point p2(iter->get_vertex()-t2*iter_w); - + side_b.push_back(line_intersection(p1,last_tangent,p2,curr_tangent)); } else if(cross>0 && perp>1) @@ -258,16 +299,16 @@ Outline::sync() float amount(max(0.0f,(float)(-cross/CUSP_THRESHOLD))*(SPIKE_AMOUNT-1)+1); side_b.push_back(iter->get_vertex()-(t1+t2).norm()*iter_w*amount); - } + } } - + // Make the outline if(homogeneous_width) { const float length(curve.length()); float dist(0); Point lastpoint; - for(float n=0.0f;n<1.0f;n+=1.0f/SAMPLES) + for(float n=0.0f;n<0.999999f;n+=1.0f/SAMPLES) { const Vector d(deriv(n>CUSP_TANGENT_ADJUST?n:CUSP_TANGENT_ADJUST).perp().norm()); const Vector p(curve(n)); @@ -279,25 +320,27 @@ Outline::sync() side_a.push_back(p+d*w); side_b.push_back(p-d*w); - + lastpoint=p; } } else - for(float n=0.0f;n<1.0f;n+=1.0f/SAMPLES) + for(float n=0.0f;n<0.999999f;n+=1.0f/SAMPLES) { const Vector d(deriv(n>CUSP_TANGENT_ADJUST?n:CUSP_TANGENT_ADJUST).perp().norm()); const Vector p(curve(n)); const float w(((next_w-iter_w)*n+iter_w)); - + side_a.push_back(p+d*w); side_b.push_back(p-d*w); } last_tangent=deriv(1.0-CUSP_TANGENT_ADJUST); side_a.push_back(curve(1.0)+last_tangent.perp().norm()*next_w); side_b.push_back(curve(1.0)-last_tangent.perp().norm()*next_w); + + first=false; } - + if(loop) { reverse(side_b.begin(),side_b.end()); @@ -305,17 +348,17 @@ Outline::sync() add_polygon(side_b); return; } - + // Insert code for adding end tip - if(round_tip[1] && !loop) + if(round_tip[1] && !loop && side_a.size()) { // remove the last point side_a.pop_back(); - + const Point vertex(bline.back().get_vertex()); const Vector tangent(last_tangent.norm()); const float w((bline.back().get_width()*width)*0.5f+expand); - + hermite curve( vertex+tangent.perp()*w, vertex-tangent.perp()*w, @@ -323,26 +366,23 @@ Outline::sync() -tangent*w*ROUND_END_FACTOR ); - for(float n=0.0f;n<1.0f;n+=1.0f/SAMPLES) + for(float n=0.0f;n<0.999999f;n+=1.0f/SAMPLES) side_a.push_back(curve(n)); - - // remove the last point - side_a.pop_back(); } - + for(;!side_b.empty();side_b.pop_back()) side_a.push_back(side_b.back()); // Insert code for adding begin tip - if(round_tip[0] && !loop) + if(round_tip[0] && !loop && side_a.size()) { // remove the last point side_a.pop_back(); - + const Point vertex(bline.front().get_vertex()); - const Vector tangent(bline.front().get_tangent2().norm()); + const Vector tangent(first_tangent.norm()); const float w((bline.front().get_width()*width)*0.5f+expand); - + hermite curve( vertex-tangent.perp()*w, vertex+tangent.perp()*w, @@ -350,18 +390,15 @@ Outline::sync() tangent*w*ROUND_END_FACTOR ); - for(float n=0.0f;n<1.0f;n+=1.0f/SAMPLES) + for(float n=0.0f;n<0.999999f;n+=1.0f/SAMPLES) side_a.push_back(curve(n)); - - // remove the last point - side_a.pop_back(); } - + add_polygon(side_a); - - -#else - + + +#else /* 1 */ + bool loop_; if(bline.get_contained_type()==ValueBase::TYPE_BLINEPOINT) { @@ -374,7 +411,7 @@ Outline::sync() } else loop_=value.get_loop(); - + segment_list=convert_bline_to_segment_list(value); width_list=convert_bline_to_width_list(value); } @@ -392,8 +429,8 @@ Outline::sync() clear(); return; } - - + + // Repair the width list if we need to { Real default_width; @@ -401,12 +438,12 @@ Outline::sync() default_width=0.01; else default_width=width_list.back(); - + while(width_list.size()segment_list.size()+1) width_list.pop_back(); - + } // Repair the zero tangents (if any) @@ -418,7 +455,7 @@ Outline::sync() iter->t1=iter->t2=iter->p2-iter->p1; } } - + vector::iterator iter; vector scaled_width_list; for(iter=width_list.begin();iter!=width_list.end();++iter) @@ -431,10 +468,10 @@ Outline::sync() vector vector_list; Vector last_tangent(segment_list.back().t2); clear(); - + if(!loop_) last_tangent=NO_LOOP_COOKIE; - + { vector::iterator iter; vector::iterator witer; @@ -443,7 +480,7 @@ Outline::sync() witer=scaled_width_list.begin(); iter!=segment_list.end(); ++iter,++witer) - { + { if(iter->t1.mag_squared()<=EPSILON && iter->t2.mag_squared()<=EPSILON) { vector_list.push_back(iter->p1-(iter->p2-iter->p1).perp().norm()*witer[0]); @@ -458,25 +495,25 @@ Outline::sync() curve.p2()=iter->p2; curve.t2()=iter->t2; curve.sync(); - + etl::derivative > deriv(curve); - + // without this if statement, the broken tangents would // have boxed edges if(sharp_cusps && last_tangent!=NO_LOOP_COOKIE && !last_tangent.is_equal_to(iter->t1)) { //Vector curr_tangent(iter->t1); Vector curr_tangent(deriv(CUSP_TANGENT_ADJUST)); - + const Vector t1(last_tangent.perp().norm()); const Vector t2(curr_tangent.perp().norm()); - + Point p1(iter->p1+t1*witer[0]); Point p2(iter->p1+t2*witer[0]); - + Real cross(t1*t2.perp()); - - if(cross>CUSP_THRESHOLD) + + if(cross>CUSP_THRESHOLD) vector_list.push_back(line_intersection(p1,last_tangent,p2,curr_tangent)); else if(cross>0) { @@ -489,18 +526,18 @@ Outline::sync() } //last_tangent=iter->t2; last_tangent=deriv(1.0f-CUSP_TANGENT_ADJUST); - + for(n=0.0f;n<1.0f;n+=1.0f/SAMPLES) vector_list.push_back(curve(n)+deriv(n>CUSP_TANGENT_ADJUST?n:CUSP_TANGENT_ADJUST).perp().norm()*((witer[1]-witer[0])*n+witer[0]) ); vector_list.push_back(curve(1.0)+deriv(1.0-CUSP_TANGENT_ADJUST).perp().norm()*witer[1]); - + } } if(round_tip[1] && !loop_/* && (!sharp_cusps || segment_list.front().p1!=segment_list.back().p2)*/) { // remove the last point vector_list.pop_back(); - + iter--; curve.p1()=iter->p2+Vector(last_tangent[1],-last_tangent[0]).norm()*(*witer); @@ -514,7 +551,7 @@ Outline::sync() vector_list.pop_back(); } } - + if(!loop_) last_tangent=NO_LOOP_COOKIE; else @@ -523,10 +560,10 @@ Outline::sync() vector_list.clear(); last_tangent=segment_list.front().t1; } - + //else // last_tangent=segment_list.back().t2; - + { vector::reverse_iterator iter; vector::reverse_iterator witer; @@ -536,7 +573,7 @@ Outline::sync() !(iter==segment_list.rend()); ++iter,++witer) { - + if(iter->t1.mag_squared()<=EPSILON && iter->t2.mag_squared()<=EPSILON) { vector_list.push_back(iter->p2+(iter->p2-iter->p1).perp().norm()*witer[0]); @@ -551,7 +588,7 @@ Outline::sync() curve.p2()=iter->p2; curve.t2()=iter->t2; curve.sync(); - + etl::derivative > deriv(curve); // without this if statement, the broken tangents would @@ -560,17 +597,17 @@ Outline::sync() { //Vector curr_tangent(iter->t2); Vector curr_tangent(deriv(1.0f-CUSP_TANGENT_ADJUST)); - + const Vector t1(last_tangent.perp().norm()); const Vector t2(curr_tangent.perp().norm()); Point p1(iter->p2-t1*witer[-1]); Point p2(iter->p2-t2*witer[-1]); - + Real cross(t1*t2.perp()); - + //if(last_tangent.perp().norm()*curr_tangent.norm()<-CUSP_THRESHOLD) - if(cross>CUSP_THRESHOLD) + if(cross>CUSP_THRESHOLD) vector_list.push_back(line_intersection(p1,last_tangent,p2,curr_tangent)); else if(cross>0) { @@ -583,7 +620,7 @@ Outline::sync() } //last_tangent=iter->t1; last_tangent=deriv(CUSP_TANGENT_ADJUST); - + for(n=1.0f;n>CUSP_TANGENT_ADJUST;n-=1.0f/SAMPLES) vector_list.push_back(curve(n)-deriv(1-n>CUSP_TANGENT_ADJUST?n:1-CUSP_TANGENT_ADJUST).perp().norm()*((witer[-1]-witer[0])*n+witer[0]) ); vector_list.push_back(curve(0.0f)-deriv(CUSP_TANGENT_ADJUST).perp().norm()*witer[0]); @@ -595,7 +632,7 @@ Outline::sync() vector_list.pop_back(); iter--; witer--; - + curve.p1()=iter->p1+Vector(last_tangent[1],-last_tangent[0]).norm()*(*witer); curve.p2()=iter->p1-(Vector(last_tangent[1],-last_tangent[0]).norm()*(*witer)); curve.t1()=-(curve.t2()=last_tangent/last_tangent.mag()*(*witer)*ROUND_END_FACTOR); @@ -603,7 +640,7 @@ Outline::sync() for(n=1.0;n>0.0;n-=1.0/SAMPLES) vector_list.push_back(curve(n)); - + // remove the last point vector_list.pop_back(); } @@ -622,12 +659,12 @@ Outline::sync() } //synfig::info("BLEHH__________--- x:%f, y:%f",vector_list.front()[0],vector_list.front()[1]); } -#endif - +#endif /* _DEBUG */ + add_polygon(vector_list); -#endif +#endif /* 1 */ } catch (...) { synfig::error("Outline::sync(): Exception thrown"); throw; } } @@ -652,7 +689,7 @@ Outline::set_param(const String & param, const ValueBase &value) { //if(value.get_contained_type()!=ValueBase::TYPE_BLINEPOINT) // return false; - + bline=value; return true; @@ -699,8 +736,8 @@ Outline::set_param(const String & param, const ValueBase &value) //sync(); return true; } - - if( param=="width_list" && value.same_as(width_list)) + + if( param=="width_list" && value.same_type_as(width_list)) { width_list=value; //sync(); @@ -715,7 +752,7 @@ Outline::set_param(const String & param, const ValueBase &value) IMPORT(loopyness); IMPORT(expand); IMPORT(homogeneous_width); - + if(param!="vector_list") return Layer_Polygon::set_param(param,value); @@ -749,7 +786,7 @@ Outline::get_param(const String& param)const EXPORT(sharp_cusps); EXPORT(width); EXPORT(loopyness); - + EXPORT_NAME(); EXPORT_VERSION(); @@ -768,8 +805,8 @@ Outline::get_param_vocab()const ret.push_back(ParamDesc("bline") .set_local_name(_("Vertices")) - .set_origin("offset") - .set_scalar("width") + .set_origin("origin") + .set_hint("width") .set_description(_("A list of BLine Points")) );