123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492 |
- /* The GIMP -- an image manipulation program
- * Copyright (C) 1995 Spencer Kimball and Peter Mattis
- *
- * This program 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.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include "config.h"
- #include <string.h>
- #include <gtk/gtk.h>
- #include "apptypes.h"
- #include "appenv.h"
- #include "cursorutil.h"
- #include "draw_core.h"
- #include "edit_selection.h"
- #include "errors.h"
- #include "gdisplay.h"
- #include "gimage_mask.h"
- #include "rect_select.h"
- #include "bezier_select.h"
- #include "bezier_selectP.h"
- #include "paths_dialogP.h"
- #include "selection_options.h"
- #include "undo.h"
- #include "libgimp/gimpmath.h"
- #include "libgimp/gimpintl.h"
- /* Bezier extensions made by Raphael FRANCOIS (fraph@ibm.net)
- BEZIER_EXTENDS VER 1.0
- - work as the cut/copy/paste named functions.
- - allow to add/remove/replace bezier curves
- - allow to modify the control/anchor points even if the selection is made
- - allow to add/remove control/anchor points on a curve
- - allow to update a previous saved curve
- - cannot operate on open or multiple curves simultaneously
- */
- #define BEZIER_DRAW_CURVE 1
- #define BEZIER_DRAW_CURRENT 2
- #define BEZIER_DRAW_HANDLES 4
- #define BEZIER_DRAW_ALL (BEZIER_DRAW_CURVE | BEZIER_DRAW_HANDLES)
- #define BEZIER_WIDTH 8
- #define BEZIER_HALFWIDTH 4
- #define SUPERSAMPLE 3
- #define SUPERSAMPLE2 9
- #define NO 0
- #define YES 1
- /* the bezier select structures */
- typedef double BezierMatrix[4][4];
- /* The named paste dialog */
- typedef struct _PasteNamedDlg PasteNamedDlg;
- struct _PasteNamedDlg
- {
- GtkWidget *shell;
- GtkWidget *list;
- GDisplay *gdisp;
- };
- /* The named buffer structure... */
- typedef struct _named_buffer BezierNamedBuffer;
- struct _named_buffer
- {
- BezierSelect *sel;
- char * name;
- };
- typedef struct {
- CountCurves curve_count; /* Must be the first element */
- gdouble *stroke_points;
- gint num_stroke_points; /* num of valid points */
- gint len_stroke_points; /* allocated length */
- void *next_curve; /* Next curve in list -- we draw all curves
- * separately.
- */
- } BezierRenderPnts;
- typedef struct {
- CountCurves curve_count; /* Must be the first element */
- gboolean firstpnt;
- gdouble curdist;
- gdouble dist;
- gdouble *gradient;
- gint *x;
- gint *y;
- gdouble lastx;
- gdouble lasty;
- gboolean found;
- } BezierDistance;
- typedef struct {
- CountCurves curve_count; /* Must be the first element */
- gint x;
- gint y;
- gint halfwidth;
- gint found;
- } BezierCheckPnts;
- /* the bezier selection tool options */
- static SelectionOptions *bezier_options = NULL;
- /* local variables */
- static BezierMatrix basis =
- {
- { -1, 3, -3, 1 },
- { 3, -6, 3, 0 },
- { -3, 3, 0, 0 },
- { 1, 0, 0, 0 },
- };
- /*
- static BezierMatrix basis =
- {
- { -1/6.0, 3/6.0, -3/6.0, 1/6.0 },
- { 3/6.0, -6/6.0, 3/6.0, 0 },
- { -3/6.0, 0, 3/6.0, 0 },
- { 1/6.0, 4/6.0, 1, 0 },
- };
- */
- /* The named buffer list */
- GSList *bezier_named_buffers = NULL;
- /* Global Static Variable to maintain informations about the "contexte" */
- static BezierSelect * curSel;
- static Tool * curTool;
- static GDisplay * curGdisp;
- static DrawCore * curCore;
- static int ModeEdit = EXTEND_NEW;
- /* local function prototypes */
- static void bezier_select_button_press (Tool *, GdkEventButton *, gpointer);
- static void bezier_select_button_release (Tool *, GdkEventButton *, gpointer);
- static void bezier_select_motion (Tool *, GdkEventMotion *, gpointer);
- static void bezier_select_control (Tool *, ToolAction, gpointer);
- static void bezier_select_cursor_update (Tool *, GdkEventMotion *, gpointer);
- static void bezier_select_draw (Tool *);
- static void bezier_offset_point (BezierPoint *, int, int);
- static int bezier_check_point (BezierPoint *, int, int, int);
- static void bezier_draw_handles (BezierSelect *, gint);
- static void bezier_draw_current (BezierSelect *);
- static void bezier_draw_point (BezierSelect *, BezierPoint *, int);
- static void bezier_draw_line (BezierSelect *, BezierPoint *, BezierPoint *);
- static void bezier_draw_segment (BezierSelect *, BezierPoint *, int, int, BezierPointsFunc,gpointer);
- static void bezier_draw_segment_points (BezierSelect *, GdkPoint *, int, gpointer);
- static void bezier_compose (BezierMatrix, BezierMatrix, BezierMatrix);
- static void bezier_convert (BezierSelect *, GDisplay *, int, int);
- static void bezier_convert_points (BezierSelect *, GdkPoint *, int, gpointer);
- static void bezier_convert_line (GSList **, int, int, int, int);
- static GSList * bezier_insert_in_list (GSList *, int);
- static int test_add_point_on_segment (BezierSelect *, BezierPoint *, int, int, int, int, int);
- static void bezier_to_sel_internal (BezierSelect *, Tool *, GDisplay *, gint, gint);
- static void bezier_stack_points (BezierSelect *, GdkPoint *, int, gpointer);
- static gboolean stroke_interpolatable (int, int, int, int, gdouble);
- static void bezier_stack_points_aux (GdkPoint *, int, int, gdouble, BezierRenderPnts *);
- static gint count_points_on_curve(BezierPoint *);
- /* functions */
- static void
- bezier_select_options_reset ()
- {
- selection_options_reset (bezier_options);
- }
- Tool*
- tools_new_bezier_select ()
- {
- Tool * tool;
- BezierSelect * private;
- /* The tool options */
- if (! bezier_options)
- {
- bezier_options =
- selection_options_new (BEZIER_SELECT, bezier_select_options_reset);
- tools_register (BEZIER_SELECT, (ToolOptions *) bezier_options);
- }
- tool = tools_new_tool (BEZIER_SELECT);
- private = g_new0 (BezierSelect, 1);
- private->num_points = 0;
- private->mask = NULL;
- private->core = draw_core_new (bezier_select_draw);
- bezier_select_reset (private);
- tool->scroll_lock = TRUE; /* Disallow scrolling */
- tool->preserve = FALSE; /* Don't preserve on drawable change */
- tool->private = (void *) private;
- tool->button_press_func = bezier_select_button_press;
- tool->button_release_func = bezier_select_button_release;
- tool->motion_func = bezier_select_motion;
- tool->cursor_update_func = bezier_select_cursor_update;
- tool->control_func = bezier_select_control;
- curCore = private->core;
- curSel = private;
- curTool = tool;
- paths_new_bezier_select_tool ();
- return tool;
- }
- void
- tools_free_bezier_select (Tool *tool)
- {
- BezierSelect * bezier_sel;
- bezier_sel = tool->private;
- if (tool->state == ACTIVE)
- draw_core_stop (bezier_sel->core, tool);
- draw_core_free (bezier_sel->core);
- bezier_select_reset (bezier_sel);
- g_free (bezier_sel);
- }
- int
- bezier_select_load (void *gdisp_ptr,
- BezierPoint *pts,
- int num_pts,
- int closed)
- {
- GDisplay * gdisp;
- Tool * tool;
- BezierSelect * bezier_sel;
- gdisp = (GDisplay *) gdisp_ptr;
- /* select the bezier tool */
- gimp_context_set_tool (gimp_context_get_user (), BEZIER_SELECT);
- tool = active_tool;
- tool->state = ACTIVE;
- tool->gdisp_ptr = gdisp_ptr;
- bezier_sel = (BezierSelect *) tool->private;
- bezier_sel->points = pts;
- bezier_sel->last_point = pts->prev;
- bezier_sel->num_points = num_pts;
- bezier_sel->closed = closed;
- bezier_sel->state = BEZIER_EDIT;
- bezier_sel->draw = BEZIER_DRAW_ALL;
- bezier_convert (bezier_sel, tool->gdisp_ptr, SUBDIVIDE, NO);
- draw_core_start (bezier_sel->core, gdisp->canvas->window, tool);
- return 1;
- }
- static BezierPoint *
- valid_curve_segment(BezierPoint *points)
- {
- /* Valid curve segment is made up of four points */
- if(points &&
- points->next &&
- points->next->next &&
- points->next->next->next )
- return(points);
- return (NULL);
- }
- static BezierPoint *
- next_anchor(BezierPoint *points,BezierPoint **next_curve)
- {
- int loop;
- *next_curve = NULL;
-
- if(!points)
- return (NULL);
- for(loop = 0; loop < 3; loop++)
- {
- points = points->next;
- if (!points)
- return (NULL);
- if(points->next_curve)
- {
- *next_curve = points->next_curve;
- }
- }
- return valid_curve_segment(points);
- }
- void
- bezier_draw_curve (BezierSelect *bezier_sel,
- BezierPointsFunc func,
- gint coord,
- gpointer udata)
- {
- BezierPoint * points;
- BezierPoint * start_pt;
- BezierPoint * next_curve;
- CountCurves * cnt = (CountCurves *)udata;
- gint point_counts = 0;
- /* printSel(bezier_sel); */
- if(cnt)
- cnt->count = 0;
- points = bezier_sel->points;
- start_pt = bezier_sel->points;
- if(bezier_sel->num_points >= 4)
- {
- do {
- point_counts = count_points_on_curve(points);
- if (point_counts >= 4)
- {
- do {
- bezier_draw_segment (bezier_sel, points,
- SUBDIVIDE, coord,
- func,
- udata);
-
- points = next_anchor (points, &next_curve);
- /* g_print ("next_anchor = %p\n",points); */
- } while (points != start_pt && points);
- if(cnt)
- cnt->count++;
- start_pt = next_curve;
- points = next_curve;
- }
- else
- break; /* must be last curve since only this one is allowed < 4
- * points.
- */
- } while (next_curve);
- }
- }
- void
- bezier_select_reset (BezierSelect *bezier_sel)
- {
- BezierPoint * points;
- BezierPoint * start_pt;
- BezierPoint * temp_pt;
- BezierPoint * next_curve;
- if (bezier_sel->num_points > 0)
- {
- points = bezier_sel->points;
- start_pt = bezier_sel->points;
- do {
- do {
- temp_pt = points;
- next_curve = points->next_curve;
- points = points->next;
- if(points != start_pt && next_curve)
- {
- g_warning("Curve points out of sync");
- }
- g_free (temp_pt);
- } while (points != start_pt && points);
- points = next_curve;
- start_pt = next_curve;
- } while (next_curve);
- }
- if (bezier_sel->mask)
- channel_delete (bezier_sel->mask);
- bezier_sel->state = BEZIER_START; /* we are starting the curve */
- bezier_sel->draw = BEZIER_DRAW_ALL; /* draw everything by default */
- bezier_sel->closed = 0; /* the curve is initally open */
- bezier_sel->points = NULL; /* initially there are no points */
- bezier_sel->cur_anchor = NULL;
- bezier_sel->cur_control = NULL;
- bezier_sel->last_point = NULL;
- bezier_sel->num_points = 0; /* intially there are no points */
- bezier_sel->mask = NULL; /* empty mask */
- bezier_sel->scanlines = NULL;
- }
- void
- bezier_select_free (BezierSelect *bezier_sel)
- {
- bezier_select_reset (bezier_sel);
- g_free (bezier_sel);
- }
- /* Find the curve that points to this curve. This makes to_check point
- * the start of a curve.
- */
- static BezierPoint *
- check_for_next_curve(BezierSelect *bezier_sel,
- BezierPoint *to_check)
- {
- BezierPoint *points = bezier_sel->points;
- gint num_points = bezier_sel->num_points;
- while (points && num_points)
- {
- if(points->next_curve == to_check)
- return (points);
- if(points->next_curve)
- points = points->next_curve;
- else
- points = points->next;
- num_points--;
- }
- return (NULL);
- }
- static gint
- count_points_on_curve(BezierPoint *points)
- {
- BezierPoint *start = points;
- gint count = 0;
-
- while(points && points->next != start)
- {
- points = points->next;
- count++;
- }
- return (count);
- }
- /* Find the start of the last open curve, if curve already closed
- * this is an error..
- */
- static BezierPoint *
- find_start_open_curve(BezierSelect *bsel)
- {
- BezierPoint *start_pnt = NULL;
- BezierPoint *this_pnt = bsel->last_point;
- /* Could be one of the first points */
- if(!bsel->last_point)
- {
- return NULL;
- }
- if(bsel->closed)
- {
- g_message(_("Bezier path already closed."));
- return NULL;
- }
- /* Step backwards until the prev point is null.
- * in this case this is the start of the open curve.
- * The start_pnt stuff is to stop us going around forever.
- * If we even have a closed curve then we are in seroius
- * trouble.
- */
- while(this_pnt->prev && start_pnt != this_pnt)
- {
- if(!start_pnt)
- start_pnt = this_pnt;
- this_pnt = this_pnt->prev;
- }
- /* Must be an anchor to be the start */
- if(start_pnt == this_pnt || this_pnt->type != BEZIER_ANCHOR)
- {
- g_message(_("Corrupt curve"));
- return NULL;
- }
- /* g_print ("Returned start pnt of curve %p is %p\n",bsel->last_point,this_pnt); */
- return (this_pnt);
- }
- /* Delete a whole curve. Watch out for special cases.
- * start_pnt must always be the start point if the curve to delete.
- */
- static void
- delete_whole_curve(BezierSelect *bezier_sel,
- BezierPoint *start_pnt)
- {
- BezierPoint *tmppnt;
- BezierPoint *next_curve = NULL; /* Next curve this one
- * points at (if any)
- */
- BezierPoint *prev_curve; /* Does a curve point to this one? */
- gint cnt_pnts = 0; /* Count how many pnts deleted */
- gint reset_last = FALSE;
- /* shift and del means delete whole curve */
- /* Three cases, this is first curve, middle curve
- * or end curve.
- */
-
- /* Does this curve have another chained on the end?
- * or is this curve pointed to another one?
- */
- /* g_print ("delete_whole_curve::\n"); */
- tmppnt = start_pnt;
- do {
- if(tmppnt->next_curve)
- {
- next_curve = tmppnt->next_curve;
- break;
- }
- tmppnt = tmppnt->next;
- } while (tmppnt != start_pnt && tmppnt);
- prev_curve = check_for_next_curve(bezier_sel,start_pnt);
-
- /* First curve ?*/
- if(bezier_sel->points == start_pnt)
- bezier_sel->points = next_curve;
- else
- {
- /* better have a previous curve else how did we get here? */
- prev_curve->next_curve = next_curve;
- }
-
- /* start_pnt points to the curve we should free .. ignoring the next_curve */
- tmppnt = start_pnt;
- do {
- BezierPoint *fpnt;
- fpnt = tmppnt;
- tmppnt = tmppnt->next;
- if(fpnt == bezier_sel->last_point)
- reset_last = TRUE;
- g_free (fpnt);
- cnt_pnts++;
- } while (tmppnt != start_pnt && tmppnt);
- bezier_sel->num_points -= cnt_pnts;
-
- /* if deleted curve was unclosed then must have been the last curve
- * and thus this curve becomes closed.
- */
- if(!tmppnt && bezier_sel->num_points > 0)
- {
- bezier_sel->closed = 1;
- bezier_sel->state = BEZIER_EDIT;
- }
- if(bezier_sel->num_points <= 0)
- {
- bezier_select_reset(bezier_sel);
- }
- bezier_sel->cur_anchor = NULL;
- bezier_sel->cur_control = NULL;
- /* The last point could have been on this curve as well... */
- if(reset_last)
- {
- BezierPoint *points = bezier_sel->points;
- BezierPoint *l_pnt = NULL;
- gint num_points = bezier_sel->num_points;
-
- while (points && num_points)
- {
- l_pnt = points;
- if(points->next_curve)
- points = points->next_curve;
- else
- points = points->next;
- num_points--;
- }
- bezier_sel->last_point = l_pnt;
- }
- }
- static gint
- bezier_edit_point_on_curve(int x,
- int y,
- int halfwidth,
- GDisplay *gdisp,
- BezierSelect *bezier_sel,
- Tool *tool,
- GdkEventButton *bevent)
- {
- gint grab_pointer = 0;
- BezierPoint *next_curve;
- BezierPoint *points = bezier_sel->points;
- BezierPoint *start_pt = bezier_sel->points;
- BezierPoint *last_curve = NULL;
- gint point_counts = 0;
- /* find if the button press occurred on a point */
- do {
- point_counts = count_points_on_curve(points);
- do {
- if (bezier_check_point (points, x, y, halfwidth))
- {
- BezierPoint *finded=points;
- BezierPoint *start_op;
- BezierPoint *end_op;
-
- if (ModeEdit== EXTEND_REMOVE)
- {
- if((bevent->state & GDK_SHIFT_MASK) || (point_counts <= 7))
- {
- /* Case 1: GDK_SHIFT_MASK - The user explicitly wishes the present
- curve to go away.
- Case 2: The current implementation cannot cope with less than
- 7 points ie: 2 anchors points and 4 controls: the minimal closed curve.
- Since the user wishes less than this implementation minimum,
- we take this for an implicit wish that the entire curve go away.
- G'bye dear curve.
- */
- delete_whole_curve(bezier_sel,start_pt);
- return (1);
- }
- else if(!finded->prev || !finded->prev->prev)
- {
- /* This is the first point on the curve */
- /* Clear current anchor and control */
- bezier_sel->cur_anchor = NULL;
- bezier_sel->cur_control = NULL;
- /* Where are we? reset to first point... */
- /*if(last_curve == NULL)*/
- if(start_pt == bezier_sel->points)
- {
- finded = bezier_sel->points;
- bezier_sel->points = finded->next->next->next;
- bezier_sel->points->prev = NULL;
- }
- else
- {
- finded = last_curve->next_curve;
- last_curve->next_curve = finded->next->next->next;
- last_curve->next_curve->prev = NULL;
- }
-
- bezier_sel->num_points -= 3;
-
- g_free( finded->next->next );
- g_free( finded->next );
- g_free( finded );
- }
- else if(!bezier_sel->closed &&
- (finded == bezier_sel->last_point ||
- finded == bezier_sel->last_point->prev ||
- finded == bezier_sel->last_point->prev->prev))
- {
- /* This is the last point on the curve */
- /* Clear current anchor and control */
- /* Where are we? reset to last point... */
- finded = bezier_sel->last_point->prev;
- bezier_sel->last_point = finded->prev->prev;
- bezier_sel->last_point->next = NULL;
-
- bezier_sel->cur_anchor = NULL;
- bezier_sel->cur_control = NULL;
-
- bezier_sel->num_points -= 3;
-
- g_free( finded->prev );
- g_free( finded->next );
- g_free( finded );
- }
- else
- {
- if ( finded->type == BEZIER_CONTROL )
- {
- if (finded->next->type == BEZIER_CONTROL)
- finded = finded->prev;
- else
- finded = finded->next;
- }
-
- start_op = finded->prev->prev;
- end_op = finded->next->next;
- /* we can use next_curve here since we are going to
- * drop out the bottom anyways.
- */
- next_curve =
- check_for_next_curve(bezier_sel,finded);
- if(next_curve)
- {
- /* Deleteing first point of next curve*/
- next_curve->next_curve = finded->prev->prev->prev;
- }
- else /* Can't be both first and a next curve!*/
- {
- if (bezier_sel->points == finded)
- {
- /* g_print ("Deleting first point %p\n",finded); */
- bezier_sel->points = finded->prev->prev->prev;
- }
- }
- /* Make sure the chain of curves is preserved */
- if(finded->prev->next_curve)
- {
- /* g_print ("Moving curve on next_curve %p\n",finded->prev->next_curve); */
- /* last point on closed multi-path */
- finded->prev->prev->prev->prev->next_curve = finded->prev->next_curve;
- }
-
- if(bezier_sel->last_point == finded->prev)
- {
- /* g_print ("Deleting last point %p\n",finded->prev); */
- bezier_sel->last_point = bezier_sel->last_point->prev->prev->prev;
- }
- start_op->next = end_op;
- end_op->prev = start_op;
- /* if ( (bezier_sel->last_point == finded) || */
- /* (bezier_sel->last_point == finded->next) || */
- /* (bezier_sel->last_point == finded->prev)) */
- /* { */
- /* bezier_sel->last_point = start_op->prev->prev; */
- /* bezier_sel->points = start_op->prev; */
- /* } */
-
- bezier_sel->num_points -= 3;
-
- g_free( finded->prev );
- g_free( finded->next );
- g_free( finded );
- /* Clear current anchor and control */
- bezier_sel->cur_anchor = NULL;
- bezier_sel->cur_control = NULL;
- }
- }
- else
- {
- /* set the current anchor and control points */
- switch (points->type)
- {
- case BEZIER_ANCHOR:
- bezier_sel->cur_anchor = points;
- bezier_sel->cur_control = bezier_sel->cur_anchor->next;
- break;
- case BEZIER_CONTROL:
- bezier_sel->cur_control = points;
- if (bezier_sel->cur_control->next &&
- bezier_sel->cur_control->next->type == BEZIER_ANCHOR)
- bezier_sel->cur_anchor = bezier_sel->cur_control->next;
- else
- bezier_sel->cur_anchor = bezier_sel->cur_control->prev;
- break;
- }
- }
- return(1);
- }
- next_curve = points->next_curve;
- if(next_curve)
- last_curve = points;
- points = points->next;
- } while (points != start_pt && points);
- start_pt = next_curve;
- points = next_curve;
- } while (next_curve);
-
- return grab_pointer;
- }
- static gint
- bezier_add_point_on_segment(int x,
- int y,
- int halfwidth,
- GDisplay *gdisp,
- BezierSelect *bezier_sel,
- Tool *tool)
- {
- BezierPoint *points = bezier_sel->points;
- BezierPoint *start_pt = bezier_sel->points;
- BezierPoint *next_curve;
- do {
- do {
- if (test_add_point_on_segment (bezier_sel,
- points,
- SUBDIVIDE,
- IMAGE_COORDS,
- x, y,
- halfwidth))
- {
- return 1;
- }
-
- points = points->next;
-
- if(!points)
- return 0;
-
- points = points->next;
-
- if(!points)
- return 0;
-
- next_curve = points->next_curve;
- points = points->next;
- } while (points != start_pt && points);
- start_pt = next_curve;
- points = next_curve;
- } while (next_curve);
- return 0;
- }
- static void
- bezier_start_new_segment(BezierSelect *bezier_sel,gint x,gint y)
- {
- /* Must be closed to do this! */
- if(!bezier_sel->closed)
- return;
- bezier_sel->closed = 0; /* End is no longer closed !*/
- bezier_sel->state = BEZIER_ADD;
- bezier_add_point (bezier_sel, BEZIER_MOVE, (gdouble)x, (gdouble)y);
- bezier_add_point (bezier_sel, BEZIER_CONTROL, (gdouble)x, (gdouble)y);
- }
- static void
- bezier_select_button_press (Tool *tool,
- GdkEventButton *bevent,
- gpointer gdisp_ptr)
- {
- GDisplay *gdisp;
- BezierSelect *bezier_sel;
- BezierPoint *points;
- BezierPoint *start_pt;
- BezierPoint *curve_start;
- int grab_pointer;
- int op, replace;
- int x, y;
- int halfwidth, dummy;
- gdisp = (GDisplay *) gdisp_ptr;
- tool->drawable = gimage_active_drawable (gdisp->gimage);
- bezier_sel = tool->private;
- grab_pointer = 0;
- if (bezier_options->extend)
- {
- tool->gdisp_ptr = gdisp_ptr;
- }
- else
- {
- /* If the tool was being used in another image...reset it */
- if (tool->state == ACTIVE && gdisp_ptr != tool->gdisp_ptr) {
- draw_core_stop(bezier_sel->core, tool);
- bezier_select_reset (bezier_sel);
- }
- }
- gdisplay_untransform_coords (gdisp, bevent->x, bevent->y, &x, &y, TRUE, 0);
- /* get halfwidth in image coord */
- gdisplay_untransform_coords (gdisp, bevent->x + BEZIER_HALFWIDTH, 0, &halfwidth, &dummy, TRUE, 0);
- halfwidth -= x;
- curTool = active_tool;
- curSel = curTool->private;
- curGdisp = (GDisplay *) gdisp_ptr;
- active_tool->gdisp_ptr = gdisp_ptr;
- curCore = bezier_sel->core;
- switch (bezier_sel->state)
- {
- case BEZIER_START:
- if(ModeEdit != EXTEND_NEW)
- break;
- grab_pointer = 1;
- tool->state = ACTIVE;
- tool->gdisp_ptr = gdisp_ptr;
- /* if (bevent->state & GDK_MOD1_MASK) */
- /* { */
- /* init_edit_selection (tool, gdisp_ptr, bevent, EDIT_MASK_TRANSLATE); */
- /* break; */
- /* } */
- /* else if (!(bevent->state & GDK_SHIFT_MASK) && !(bevent->state & GDK_CONTROL_MASK)) */
- /* if (! (layer_is_floating_sel (gimage_get_active_layer (gdisp->gimage))) && */
- /* gdisplay_mask_value (gdisp, bevent->x, bevent->y) > HALF_WAY) */
- /* { */
- /* init_edit_selection (tool, gdisp_ptr, bevent, EDIT_MASK_TO_LAYER_TRANSLATE); */
- /* break; */
- /* } */
- bezier_sel->state = BEZIER_ADD;
- /*bezier_sel->draw = BEZIER_DRAW_CURVE; | BEZIER_DRAW_HANDLES;*/
- bezier_sel->draw = BEZIER_DRAW_CURRENT;
- bezier_add_point (bezier_sel, BEZIER_ANCHOR, (gdouble)x, (gdouble)y);
- bezier_add_point (bezier_sel, BEZIER_CONTROL, (gdouble)x, (gdouble)y);
- draw_core_start (bezier_sel->core, gdisp->canvas->window, tool);
- break;
- case BEZIER_ADD:
- grab_pointer = 1;
- if(ModeEdit == EXTEND_EDIT)
- {
- /* erase the handles */
- if(bezier_sel->closed)
- bezier_sel->draw = BEZIER_DRAW_ALL;
- else
- bezier_sel->draw = BEZIER_DRAW_CURVE;
- draw_core_pause (bezier_sel->core, tool);
- /* unset the current anchor and control */
- bezier_sel->cur_anchor = NULL;
- bezier_sel->cur_control = NULL;
- grab_pointer = bezier_edit_point_on_curve(x,y,halfwidth,gdisp,bezier_sel,tool,bevent);
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_resume (bezier_sel->core, tool);
- if (grab_pointer)
- gdk_pointer_grab (gdisp->canvas->window, FALSE,
- GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
- NULL, NULL, bevent->time);
- else
- {
- paths_dialog_set_default_op();
- /* recursive call */
- bezier_select_button_press(tool,bevent,gdisp_ptr);
- }
- return;
- }
- if(ModeEdit == EXTEND_REMOVE)
- {
- /* if(bezier_sel->num_points < 6) */
- /* return; */
- /* erase the handles */
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_pause (bezier_sel->core, tool);
- /* unset the current anchor and control */
- bezier_sel->cur_anchor = NULL;
- bezier_sel->cur_control = NULL;
- /*kkk*/
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_resume (bezier_sel->core, tool);
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_pause (bezier_sel->core, tool);
- /*kkk*/
- grab_pointer = bezier_edit_point_on_curve(x,y,halfwidth,gdisp,bezier_sel,tool,bevent);
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_resume (bezier_sel->core, tool);
- if(bezier_sel->num_points == 0)
- {
- draw_core_pause(bezier_sel->core, tool);
- paths_dialog_set_default_op();
- }
- if(!grab_pointer)
- {
- paths_dialog_set_default_op();
- /* recursive call */
- bezier_select_button_press(tool,bevent,gdisp_ptr);
- }
- return;
- }
- if(ModeEdit == EXTEND_ADD)
- {
- if(bezier_sel->num_points < 5)
- return;
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_pause (bezier_sel->core, tool);
- grab_pointer = bezier_add_point_on_segment(x,y,halfwidth,gdisp,bezier_sel,tool);
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_resume (bezier_sel->core, tool);
- if (grab_pointer)
- gdk_pointer_grab (gdisp->canvas->window, FALSE,
- GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
- NULL, NULL, bevent->time);
- else
- {
- paths_dialog_set_default_op();
- /* recursive call */
- bezier_select_button_press(tool,bevent,gdisp_ptr);
- }
- return;
- }
- if(bezier_sel->cur_anchor)
- {
- if (bezier_check_point (bezier_sel->cur_anchor, x, y, halfwidth))
- {
- break;
- }
-
- if (bezier_sel->cur_anchor->next &&
- bezier_check_point (bezier_sel->cur_anchor->next, x, y, halfwidth))
- {
- bezier_sel->cur_control = bezier_sel->cur_anchor->next;
- break;
- }
- if (bezier_sel->cur_anchor->prev &&
- bezier_check_point (bezier_sel->cur_anchor->prev, x, y, halfwidth))
- {
- bezier_sel->cur_control = bezier_sel->cur_anchor->prev;
- break;
- }
- }
- curve_start = find_start_open_curve(bezier_sel);
- if (curve_start && bezier_check_point (curve_start, x, y, halfwidth))
- {
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_pause (bezier_sel->core, tool);
- bezier_add_point (bezier_sel, BEZIER_CONTROL, (gdouble)x, (gdouble)y);
- bezier_sel->last_point->next = curve_start;
- curve_start->prev = bezier_sel->last_point;
- bezier_sel->cur_anchor = curve_start;
- bezier_sel->cur_control = curve_start->next;
- bezier_sel->closed = 1;
- bezier_sel->state = BEZIER_EDIT;
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_resume (bezier_sel->core, tool);
- }
- else
- {
- if(bezier_sel->cur_anchor)
- bezier_sel->cur_anchor->pointflags = 1;
- bezier_sel->draw = BEZIER_DRAW_HANDLES;
- draw_core_pause (bezier_sel->core, tool);
- bezier_add_point (bezier_sel, BEZIER_CONTROL, (gdouble)x, (gdouble)y);
- bezier_add_point (bezier_sel, BEZIER_ANCHOR, (gdouble)x, (gdouble)y);
- bezier_add_point (bezier_sel, BEZIER_CONTROL, (gdouble)x, (gdouble)y);
- bezier_sel->draw = BEZIER_DRAW_CURRENT | BEZIER_DRAW_HANDLES;
- draw_core_resume (bezier_sel->core, tool);
- }
- break;
- case BEZIER_EDIT:
- if (!bezier_sel->closed)
- gimp_fatal_error ("bezier_select_button_press(): Tried to edit on open bezier curve in edit selection");
- /* erase the handles */
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_pause (bezier_sel->core, tool);
- /* unset the current anchor and control */
- bezier_sel->cur_anchor = NULL;
- bezier_sel->cur_control = NULL;
- points = bezier_sel->points;
- start_pt = bezier_sel->points;
- if (ModeEdit == EXTEND_ADD)
- {
- if (bezier_sel->closed)
- {
- grab_pointer = bezier_add_point_on_segment(x,y,halfwidth,gdisp,bezier_sel,tool);
- }
- }
- else
- {
- grab_pointer = bezier_edit_point_on_curve(x,y,halfwidth,gdisp,bezier_sel,tool,bevent);
- if(grab_pointer && bezier_sel->num_points == 0)
- {
- draw_core_pause(bezier_sel->core, tool);
- paths_dialog_set_default_op();
- }
- }
- if (!grab_pointer && channel_value (bezier_sel->mask, x, y))
- {
- replace = 0;
- if ((bevent->state & GDK_SHIFT_MASK) && !(bevent->state & GDK_CONTROL_MASK))
- op = ADD;
- else if ((bevent->state & GDK_CONTROL_MASK) && !(bevent->state & GDK_SHIFT_MASK))
- op = SUB;
- else if ((bevent->state & GDK_CONTROL_MASK) && (bevent->state & GDK_SHIFT_MASK))
- op = INTERSECT;
- else
- {
- op = ADD;
- replace = 1;
- }
- bezier_to_sel_internal(bezier_sel,tool,gdisp,op,replace);
- draw_core_resume (bezier_sel->core, tool);
- }
- else
- {
- /* draw the handles */
- if(!grab_pointer)
- {
- paths_dialog_set_default_op();
- bezier_start_new_segment(bezier_sel,x,y);
- }
- bezier_sel->draw = BEZIER_DRAW_ALL;
- draw_core_resume (bezier_sel->core, tool);
- }
- break;
- }
- if (grab_pointer)
- gdk_pointer_grab (gdisp->canvas->window, FALSE,
- GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
- NULL, NULL, bevent->time);
- /* Don't bother doing this if we don't have any points */
- if(bezier_sel->num_points > 0)
- paths_first_button_press(bezier_sel,gdisp);
- }
- static void
- bezier_select_button_release (Tool *tool,
- GdkEventButton *bevent,
- gpointer gdisp_ptr)
- {
- GDisplay * gdisp;
- BezierSelect *bezier_sel;
- gdisp = tool->gdisp_ptr;
- bezier_sel = tool->private;
- bezier_sel->state &= ~(BEZIER_DRAG);
- gdk_pointer_ungrab (bevent->time);
- gdk_flush ();
- if (bezier_sel->closed)
- bezier_convert (bezier_sel, tool->gdisp_ptr, SUBDIVIDE, NO);
- /* Here ?*/
- paths_newpoint_current(bezier_sel,gdisp);
- }
- /* unused
- static void
- bez_copy_points(BezierSelect *tobez,
- BezierSelect *frombez)
- {
- BezierPoint *pts;
- gint i;
- BezierPoint *bpnt = NULL;
- int need_move = 0;
- pts = (BezierPoint *) frombez->points;
- for (i=0; i< frombez->num_points; i++)
- {
- if(need_move)
- {
- bezier_add_point( tobez, BEZIER_MOVE, pts->x, pts->y);
- need_move = 0;
- }
- else
- bezier_add_point( tobez, pts->type, pts->x, pts->y);
- if(pts == frombez->cur_anchor)
- tobez->cur_anchor = tobez->last_point;
- else if(pts == frombez->cur_control)
- tobez->cur_control = tobez->last_point;
- if(bpnt == NULL)
- bpnt = tobez->last_point;
- if(pts->next_curve)
- {
- tobez->last_point->next = bpnt;
- bpnt->prev = tobez->last_point;
- bpnt = NULL;
- need_move = 1;
- pts = pts->next_curve;
- }
- else
- {
- pts = pts->next;
- }
- }
-
- if ( frombez->closed )
- {
- tobez->last_point->next = bpnt;
- bpnt->prev = tobez->last_point;
- tobez->closed = 1;
- }
- }
- */
- static void
- bezier_select_motion (Tool *tool,
- GdkEventMotion *mevent,
- gpointer gdisp_ptr)
- {
- static int lastx, lasty;
- GDisplay * gdisp;
- BezierSelect * bezier_sel;
- BezierPoint * anchor;
- BezierPoint * opposite_control;
- int offsetx;
- int offsety;
- int x, y;
- if (tool->state != ACTIVE)
- return;
- gdisp = gdisp_ptr;
- bezier_sel = tool->private;
- if (!bezier_sel->cur_anchor || !bezier_sel->cur_control)
- return;
- if (mevent->state & GDK_MOD1_MASK)
- {
- bezier_sel->draw = BEZIER_DRAW_ALL;
- }
- else
- {
- bezier_sel->draw = BEZIER_DRAW_CURRENT | BEZIER_DRAW_HANDLES;
- }
- draw_core_pause (bezier_sel->core, tool);
- gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
- /* If this is the first point then change the state and "remember" the point.
- */
- if (!(bezier_sel->state & BEZIER_DRAG))
- {
- bezier_sel->state |= BEZIER_DRAG;
- lastx = x;
- lasty = y;
- }
- /* The Alt key is down... Move all the points of the bezier curve */
- if (mevent->state & GDK_MOD1_MASK)
- {
- BezierPoint *tmp = bezier_sel->points;
- gint num_points = bezier_sel->num_points;
- offsetx = x - lastx;
- offsety = y - lasty;
- if(mevent->state & GDK_SHIFT_MASK)
- {
- /* Only move this curve */
- BezierPoint *start_pt = bezier_sel->cur_anchor;
- /* g_print ("moving only one curve\n"); */
- tmp = start_pt;
-
- do {
- bezier_offset_point (tmp, offsetx, offsety);
- tmp = tmp->next;
- } while (tmp != start_pt && tmp);
- /* Check if need to go backwards because curve is open */
- if(!tmp && bezier_sel->cur_anchor->prev)
- {
- BezierPoint *start_pt = bezier_sel->cur_anchor->prev;
- tmp = start_pt;
-
- do {
- bezier_offset_point (tmp, offsetx, offsety);
- tmp = tmp->prev;
- } while (tmp != start_pt && tmp);
- }
- }
- else
- {
- while (tmp && num_points)
- {
- bezier_offset_point (tmp, offsetx, offsety);
- if(tmp->next_curve)
- tmp = tmp->next_curve;
- else
- tmp = tmp->next;
- num_points--;
- }
- }
- }
- else
- if (mevent->state & GDK_CONTROL_MASK)
- {
- /* the control key is down ... move the current anchor point */
- /* we must also move the neighboring control points appropriately */
- offsetx = x - lastx;
- offsety = y - lasty;
- bezier_offset_point (bezier_sel->cur_anchor, offsetx, offsety);
- bezier_offset_point (bezier_sel->cur_anchor->next, offsetx, offsety);
- bezier_offset_point (bezier_sel->cur_anchor->prev, offsetx, offsety);
- }
- else
- {
- /* the control key is not down ... we move the current control point */
- offsetx = x - bezier_sel->cur_control->x;
- offsety = y - bezier_sel->cur_control->y;
- bezier_offset_point (bezier_sel->cur_control, offsetx, offsety);
- /* if the shift key is not down then we align the opposite control */
- /* point...ie the opposite control point acts like a mirror of the */
- /* current control point */
- if (!(mevent->state & GDK_SHIFT_MASK))
- {
- anchor = NULL;
- opposite_control = NULL;
- if (bezier_sel->cur_control->next)
- {
- if (bezier_sel->cur_control->next->type == BEZIER_ANCHOR)
- {
- anchor = bezier_sel->cur_control->next;
- opposite_control = anchor->next;
- }
- }
- if (bezier_sel->cur_control->prev)
- {
- if (bezier_sel->cur_control->prev->type == BEZIER_ANCHOR)
- {
- anchor = bezier_sel->cur_control->prev;
- opposite_control = anchor->prev;
- }
- }
- if (!anchor)
- gimp_fatal_error ("bezier_select_motion(): Encountered orphaned bezier control point");
- if (opposite_control)
- {
- offsetx = bezier_sel->cur_control->x - anchor->x;
- offsety = bezier_sel->cur_control->y - anchor->y;
- opposite_control->x = anchor->x - offsetx;
- opposite_control->y = anchor->y - offsety;
- }
- }
- }
- /* As we're moving all the control points of the curve,
- we have to redraw all !!!
- */
- if ( mevent->state & GDK_MOD1_MASK)
- bezier_sel->draw = BEZIER_DRAW_ALL;
- else
- bezier_sel->draw = BEZIER_DRAW_CURRENT | BEZIER_DRAW_HANDLES;
- draw_core_resume (bezier_sel->core, tool);
- lastx = x;
- lasty = y;
- }
- /* returns 0 if not on control point, else BEZIER_ANCHOR or BEZIER_CONTROL */
- static gint
- bezier_on_control_point(GDisplay *gdisp,
- BezierSelect *bezier_sel,
- gint x,
- gint y,
- gint halfwidth)
- {
- BezierPoint * points;
- gint num_points;
- /* transform the points from image space to screen space */
- points = bezier_sel->points;
- num_points = bezier_sel->num_points;
- while (points && num_points)
- {
- if(bezier_check_point(points,x,y,halfwidth))
- return points->type;
- if(points->next_curve)
- points = points->next_curve;
- else
- points = points->next;
- num_points--;
- }
- return FALSE;
- }
- static void
- bezier_check_points (BezierSelect *bezier_sel,
- GdkPoint *points,
- int npoints,
- gpointer udata)
- {
- gint loop;
- int l, r, t, b;
- BezierCheckPnts *chkpnts = udata;
- gint halfwidth = chkpnts->halfwidth;
- /* Quick exit if already found */
- if(chkpnts->found)
- return;
- for(loop = 0 ; loop < npoints; loop++)
- {
- l = points[loop].x - halfwidth;
- r = points[loop].x + halfwidth;
- t = points[loop].y - halfwidth;
- b = points[loop].y + halfwidth;
- /* g_print ("x,y = [%d,%d] halfwidth %d l,r,t,d [%d,%d,%d,%d]\n", */
- /* points[loop].x, */
- /* points[loop].y, */
- /* halfwidth, */
- /* l,r,t,b); */
- if ((chkpnts->x >= l) &&
- (chkpnts->x <= r) &&
- (chkpnts->y >= t) &&
- (chkpnts->y <= b))
- {
- chkpnts->found = TRUE;
- }
- }
- }
- static gboolean
- points_in_box(BezierPoint *points,
- gint x,
- gint y)
- {
- /* below code adapted from Wm. Randolph Franklin <wrf@ecse.rpi.edu>
- */
- int i, j, c = 0;
- double yp[4],xp[4];
- for (i = 0; i < 4; i++)
- {
- xp[i] = points->x;
- yp[i] = points->y;
- points = points->next;
- }
- /* Check if straight line ..below don't work if it is! */
- if((xp[0] == xp[1] && yp[0] == yp[1]) ||
- (xp[2] == xp[3] && yp[0] == yp[1]))
- return TRUE;
- for (i = 0, j = 3; i < 4; j = i++) {
- if ((((yp[i]<=y) && (y<yp[j])) ||
- ((yp[j]<=y) && (y<yp[i]))) &&
- (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
- c = !c;
- }
- return c;
- }
- static gint
- bezier_point_on_curve (GDisplay *gdisp,
- BezierSelect *bezier_sel,
- gint x,
- gint y,
- gint halfwidth)
- {
- BezierCheckPnts chkpnts;
- BezierPoint * points;
- BezierPoint * start_pt;
- BezierPoint * next_curve;
- CountCurves * cnt = (CountCurves *)&chkpnts;
- gint point_counts = 0;
- chkpnts.x = x;
- chkpnts.y = y;
- chkpnts.halfwidth = halfwidth;
- chkpnts.found = FALSE;
- if (cnt)
- cnt->count = 0;
- points = bezier_sel->points;
- start_pt = bezier_sel->points;
- if (bezier_sel->num_points >= 4)
- {
- do
- {
- point_counts = count_points_on_curve(points);
- if (point_counts >= 4)
- {
- do
- {
- if (points_in_box (points, x, y))
- {
- bezier_draw_segment (bezier_sel, points,
- SUBDIVIDE, IMAGE_COORDS,
- bezier_check_points,
- &chkpnts);
- }
- points = next_anchor (points, &next_curve);
- /* g_print ("next_anchor = %p\n",points); */
- }
- while (points != start_pt && points);
- if (cnt)
- cnt->count++;
- start_pt = next_curve;
- points = next_curve;
- }
- else
- break; /* must be last curve since only this one is allowed < 4
- * points.
- */
- }
- while (next_curve);
- }
- return chkpnts.found;
- }
- static void
- bezier_select_cursor_update (Tool *tool,
- GdkEventMotion *mevent,
- gpointer gdisp_ptr)
- {
- GDisplay *gdisp;
- BezierSelect * bezier_sel;
- gboolean on_curve;
- gboolean on_control_pnt;
- gboolean in_selection_area;
- gint halfwidth,dummy;
- gint x,y;
- gdisp = (GDisplay *) gdisp_ptr;
- bezier_sel = tool->private;
- if (gdisp != tool->gdisp_ptr || bezier_sel->core->draw_state == INVISIBLE)
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_NONE,
- FALSE);
- return;
- }
- gdisplay_untransform_coords (gdisp, mevent->x, mevent->y, &x, &y, TRUE, 0);
- /* get halfwidth in image coord */
- gdisplay_untransform_coords (gdisp, mevent->x + BEZIER_HALFWIDTH, 0,
- &halfwidth, &dummy, TRUE, 0);
- halfwidth -= x;
- on_control_pnt = bezier_on_control_point (gdisp, bezier_sel, x, y, halfwidth);
- on_curve = bezier_point_on_curve (gdisp, bezier_sel, x, y, halfwidth);
- if (bezier_sel->mask && bezier_sel->closed &&
- channel_value(bezier_sel->mask, x, y) &&
- !on_control_pnt &&
- (!on_curve || ModeEdit != EXTEND_ADD))
- {
- in_selection_area = TRUE;
- if ((mevent->state & GDK_SHIFT_MASK) &&
- !(mevent->state & GDK_CONTROL_MASK))
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- RECT_SELECT,
- CURSOR_MODIFIER_PLUS,
- FALSE);
- }
- else if ((mevent->state & GDK_CONTROL_MASK) &&
- !(mevent->state & GDK_SHIFT_MASK))
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- RECT_SELECT,
- CURSOR_MODIFIER_MINUS,
- FALSE);
- }
- else if ((mevent->state & GDK_CONTROL_MASK) &&
- (mevent->state & GDK_SHIFT_MASK))
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- RECT_SELECT,
- CURSOR_MODIFIER_INTERSECT,
- FALSE);
- }
- else
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- RECT_SELECT,
- CURSOR_MODIFIER_NONE,
- FALSE);
- }
- return;
- }
- if (mevent->state & GDK_MOD1_MASK)
- {
- /* Moving curve */
- if (mevent->state & GDK_SHIFT_MASK)
- {
- /* moving on 1 curve */
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_MOVE,
- FALSE);
- }
- else
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_MOVE,
- FALSE);
- }
- }
- else
- {
- switch (ModeEdit)
- {
- case EXTEND_NEW:
- if (on_control_pnt && bezier_sel->closed)
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_CONTROL,
- FALSE);
- /* g_print ("add to curve cursor\n"); */
- }
- else if (on_curve)
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_NONE,
- FALSE);
- /* g_print ("edit control point cursor\n"); */
- }
- else
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_NONE,
- FALSE);
- }
- break;
- case EXTEND_ADD:
- if (on_curve)
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_PLUS,
- FALSE);
- /* g_print ("add to curve cursor\n"); */
- }
- else
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_NONE,
- FALSE);
- /* g_print ("default no action cursor\n"); */
- }
- break;
- case EXTEND_EDIT:
- if (on_control_pnt)
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_CONTROL,
- FALSE);
- /* g_print ("edit control point cursor\n"); */
- }
- else
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_NONE,
- FALSE);
- /* g_print ("default no action cursor\n"); */
- }
- break;
- case EXTEND_REMOVE:
- if (on_control_pnt && mevent->state & GDK_SHIFT_MASK)
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_MINUS,
- FALSE);
- /* g_print ("delete whole curve cursor\n"); */
- }
- else if (on_control_pnt)
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_MINUS,
- FALSE);
- /* g_print ("remove point cursor\n"); */
- }
- else
- {
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_NONE,
- FALSE);
- /* g_print ("default no action cursor\n"); */
- }
- break;
- default:
- g_print ("In default\n");
- gdisplay_install_tool_cursor (gdisp, GIMP_MOUSE_CURSOR,
- BEZIER_SELECT,
- CURSOR_MODIFIER_NONE,
- FALSE);
- break;
- }
- }
- }
- static void
- bezier_select_control (Tool *tool,
- ToolAction action,
- gpointer gdisp_ptr)
- {
- BezierSelect * bezier_sel;
- bezier_sel = tool->private;
- switch (action)
- {
- case PAUSE :
- draw_core_pause (bezier_sel->core, tool);
- break;
- case RESUME :
- draw_core_resume (bezier_sel->core, tool);
- break;
- case HALT :
- draw_core_stop (bezier_sel->core, tool);
- bezier_select_reset (bezier_sel);
- break;
- default:
- break;
- }
- }
- void
- bezier_draw(GDisplay * gdisp,BezierSelect * bezier_sel)
- {
- BezierPoint * points;
- int num_points;
- int draw_curve;
- int draw_handles;
- int draw_current;
- if (!bezier_sel->draw)
- return;
- draw_curve = bezier_sel->draw & BEZIER_DRAW_CURVE;
- draw_current = bezier_sel->draw & BEZIER_DRAW_CURRENT;
- draw_handles = bezier_sel->draw & BEZIER_DRAW_HANDLES;
- /* reset to the default drawing state of drawing the curve and handles */
- bezier_sel->draw = BEZIER_DRAW_ALL;
- /* transform the points from image space to screen space */
- points = bezier_sel->points;
- num_points = bezier_sel->num_points;
- while (points && num_points)
- {
- gdisplay_transform_coords (gdisp, points->x, points->y,
- &points->sx, &points->sy, 0);
- if(points->next_curve)
- points = points->next_curve;
- else
- points = points->next;
- num_points--;
- }
- if (draw_curve)
- {
- bezier_draw_curve (bezier_sel,bezier_draw_segment_points,SCREEN_COORDS,NULL);
- bezier_draw_handles (bezier_sel,1);
- }
- else if (draw_current)
- {
- bezier_draw_current (bezier_sel);
- bezier_draw_handles (bezier_sel,0);
- }
- else if (draw_handles)
- {
- bezier_draw_handles (bezier_sel,0);
- }
- }
- static void
- bezier_select_draw (Tool *tool)
- {
- GDisplay * gdisp;
- BezierSelect * bezier_sel;
- gdisp = tool->gdisp_ptr;
- bezier_sel = tool->private;
- bezier_draw(gdisp,bezier_sel);
- }
- void
- bezier_add_point (BezierSelect *bezier_sel,
- int type,
- gdouble x,
- gdouble y)
- {
- BezierPoint *newpt;
- newpt = g_new0 (BezierPoint,1);
- newpt->type = type;
- newpt->x = x;
- newpt->y = y;
- newpt->next = NULL;
- newpt->prev = NULL;
- newpt->next_curve = NULL;
- if(type == BEZIER_MOVE &&
- bezier_sel->last_point)
- {
- /* g_print ("Adding move point\n"); */
- newpt->type = BEZIER_ANCHOR;
- bezier_sel->last_point->next_curve = newpt;
- bezier_sel->last_point = newpt;
- bezier_sel->cur_anchor = newpt;
- }
- else
- {
- if(type == BEZIER_MOVE)
- {
- newpt->type = BEZIER_ANCHOR;
- /* g_print ("Adding MOVE point to null curve\n"); */
- }
- if (bezier_sel->last_point)
- {
- bezier_sel->last_point->next = newpt;
- newpt->prev = bezier_sel->last_point;
- bezier_sel->last_point = newpt;
- }
- else
- {
- bezier_sel->points = newpt;
- bezier_sel->last_point = newpt;
- }
-
- switch (type)
- {
- case BEZIER_ANCHOR:
- bezier_sel->cur_anchor = newpt;
- break;
- case BEZIER_CONTROL:
- bezier_sel->cur_control = newpt;
- break;
- }
- }
- bezier_sel->num_points += 1;
- }
- static void
- bezier_offset_point (BezierPoint *pt,
- int x,
- int y)
- {
- if (pt)
- {
- pt->x += x;
- pt->y += y;
- }
- }
- static int
- bezier_check_point (BezierPoint *pt,
- int x,
- int y,
- int halfwidth)
- {
- int l, r, t, b;
- if (pt)
- {
- l = pt->x - halfwidth;
- r = pt->x + halfwidth;
- t = pt->y - halfwidth;
- b = pt->y + halfwidth;
- return ((x >= l) && (x <= r) && (y >= t) && (y <= b));
- }
- return 0;
- }
- static void
- bezier_draw_handles (BezierSelect *bezier_sel,gint doAll)
- {
- BezierPoint * points;
- int num_points;
- points = bezier_sel->points;
- num_points = bezier_sel->num_points;
- if (num_points <= 0)
- return;
- while (num_points && num_points > 0)
- {
- if (points == bezier_sel->cur_anchor)
- {
- /* g_print ("bezier_draw_handles:: found cur_anchor %p\n",points); */
- bezier_draw_point (bezier_sel, points, 0);
- bezier_draw_point (bezier_sel, points->next, 0);
- bezier_draw_point (bezier_sel, points->prev, 0);
- bezier_draw_line (bezier_sel, points, points->next);
- bezier_draw_line (bezier_sel, points, points->prev);
- }
- else
- {
- /* g_print ("bezier_draw_handles:: not found cur_anchor %p\n",points); */
- if(doAll || points->pointflags == 1)
- {
- bezier_draw_point (bezier_sel, points, 1);
- points->pointflags = 0;
- }
- }
- if(points)
- {
- if(points->next_curve)
- points = points->next_curve;
- else
- points = points->next;
- }
- if(points)
- {
- if(points->next_curve)
- points = points->next_curve;
- else
- points = points->next;
- }
- if(points)
- {
- if(points->next_curve)
- points = points->next_curve;
- else
- points = points->next;
- }
- num_points -= 3;
- }
- }
- static void
- bezier_draw_current (BezierSelect *bezier_sel)
- {
- BezierPoint * points;
- points = bezier_sel->cur_anchor;
- if (points) points = points->prev;
- if (points) points = points->prev;
- if (points) points = points->prev;
- if (points)
- bezier_draw_segment (bezier_sel, points,
- SUBDIVIDE, SCREEN_COORDS,
- bezier_draw_segment_points,
- NULL);
- if (points != bezier_sel->cur_anchor)
- {
- points = bezier_sel->cur_anchor;
- if (points) points = points->next;
- if (points) points = points->next;
- if (points) points = points->next;
- if (points)
- bezier_draw_segment (bezier_sel, bezier_sel->cur_anchor,
- SUBDIVIDE, SCREEN_COORDS,
- bezier_draw_segment_points,
- NULL);
- }
- }
- static void
- bezier_draw_point (BezierSelect *bezier_sel,
- BezierPoint *pt,
- int fill)
- {
- if (pt)
- {
- switch (pt->type)
- {
- case BEZIER_ANCHOR:
- if (fill)
- {
- gdk_draw_arc (bezier_sel->core->win, bezier_sel->core->gc, 1,
- pt->sx - BEZIER_HALFWIDTH, pt->sy - BEZIER_HALFWIDTH,
- BEZIER_WIDTH, BEZIER_WIDTH, 0, 23040);
- }
- else
- {
- gdk_draw_arc (bezier_sel->core->win, bezier_sel->core->gc, 0,
- pt->sx - BEZIER_HALFWIDTH, pt->sy - BEZIER_HALFWIDTH,
- BEZIER_WIDTH, BEZIER_WIDTH, 0, 23040);
- }
- break;
- case BEZIER_CONTROL:
- if (fill)
- {
- gdk_draw_rectangle (bezier_sel->core->win, bezier_sel->core->gc, 1,
- pt->sx - BEZIER_HALFWIDTH, pt->sy - BEZIER_HALFWIDTH,
- BEZIER_WIDTH, BEZIER_WIDTH);
- }
- else
- {
- gdk_draw_rectangle (bezier_sel->core->win, bezier_sel->core->gc, 0,
- pt->sx - BEZIER_HALFWIDTH, pt->sy - BEZIER_HALFWIDTH,
- BEZIER_WIDTH, BEZIER_WIDTH);
- }
- break;
- }
- }
- }
- static void
- bezier_draw_line (BezierSelect *bezier_sel,
- BezierPoint *pt1,
- BezierPoint *pt2)
- {
- if (pt1 && pt2)
- {
- gdk_draw_line (bezier_sel->core->win,
- bezier_sel->core->gc,
- pt1->sx, pt1->sy, pt2->sx, pt2->sy);
- }
- }
- static void
- bezier_draw_segment (BezierSelect *bezier_sel,
- BezierPoint *points,
- int subdivisions,
- int space,
- BezierPointsFunc points_func,
- gpointer udata)
- {
- static GdkPoint gdk_points[256];
- static int npoints = 256;
- BezierMatrix geometry;
- BezierMatrix tmp1, tmp2;
- BezierMatrix deltas;
- double x, dx, dx2, dx3;
- double y, dy, dy2, dy3;
- double d, d2, d3;
- int lastx, lasty;
- int newx, newy;
- int index;
- int i;
- /* construct the geometry matrix from the segment */
- /* assumes that a valid segment containing 4 points is passed in */
- for (i = 0; i < 4; i++)
- {
- if (!points)
- gimp_fatal_error ("bezier_draw_segment(): Bad bezier segment");
- switch (space)
- {
- case IMAGE_COORDS:
- geometry[i][0] = points->x;
- geometry[i][1] = points->y;
- break;
- case AA_IMAGE_COORDS:
- geometry[i][0] = (points->x * SUPERSAMPLE);
- geometry[i][1] = (points->y * SUPERSAMPLE);
- break;
- case SCREEN_COORDS:
- geometry[i][0] = points->sx;
- geometry[i][1] = points->sy;
- break;
- default:
- gimp_fatal_error ("bezier_draw_segment(): Unknown coordinate space: %d", space);
- break;
- }
- geometry[i][2] = 0;
- geometry[i][3] = 0;
- points = points->next;
- }
- /* subdivide the curve n times */
- /* n can be adjusted to give a finer or coarser curve */
- d = 1.0 / subdivisions;
- d2 = d * d;
- d3 = d * d * d;
- /* construct a temporary matrix for determining the forward diffencing deltas */
- tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1;
- tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0;
- tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0;
- tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0;
- /* compose the basis and geometry matrices */
- bezier_compose (basis, geometry, tmp1);
- /* compose the above results to get the deltas matrix */
- bezier_compose (tmp2, tmp1, deltas);
- /* extract the x deltas */
- x = deltas[0][0];
- dx = deltas[1][0];
- dx2 = deltas[2][0];
- dx3 = deltas[3][0];
- /* extract the y deltas */
- y = deltas[0][1];
- dy = deltas[1][1];
- dy2 = deltas[2][1];
- dy3 = deltas[3][1];
- lastx = x;
- lasty = y;
- gdk_points[0].x = (lastx);
- gdk_points[0].y = (lasty);
- index = 1;
- /* loop over the curve */
- for (i = 0; i < subdivisions; i++)
- {
- /* increment the x values */
- x += dx;
- dx += dx2;
- dx2 += dx3;
- /* increment the y values */
- y += dy;
- dy += dy2;
- dy2 += dy3;
- newx = ROUND (x);
- newy = ROUND (y);
- /* if this point is different than the last one...then draw it */
- if ((lastx != newx) || (lasty != newy))
- {
- /* add the point to the point buffer */
- gdk_points[index].x = (newx);
- gdk_points[index].y = (newy);
- index++;
- /* if the point buffer is full put it to the screen and zero it out */
- if (index >= npoints)
- {
- (* points_func) (bezier_sel, gdk_points, index, udata);
- index = 0;
- }
- }
- lastx = newx;
- lasty = newy;
- }
- /* if there are points in the buffer, then put them on the screen */
- if (index)
- (* points_func) (bezier_sel, gdk_points, index, udata);
- }
- static void
- bezier_draw_segment_points (BezierSelect *bezier_sel,
- GdkPoint *points,
- int npoints,
- gpointer udata)
- {
- gdk_draw_points (bezier_sel->core->win,
- bezier_sel->core->gc, points, npoints);
- }
- static void
- bezier_compose (BezierMatrix a,
- BezierMatrix b,
- BezierMatrix ab)
- {
- int i, j;
- for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
- {
- ab[i][j] = (a[i][0] * b[0][j] +
- a[i][1] * b[1][j] +
- a[i][2] * b[2][j] +
- a[i][3] * b[3][j]);
- }
- }
- }
- static int start_convert;
- static int width, height;
- static int lastx;
- static int lasty;
- static void
- bezier_convert (BezierSelect *bezier_sel,
- GDisplay *gdisp,
- int subdivisions,
- int antialias)
- {
- PixelRegion maskPR;
- BezierPoint * points;
- BezierPoint * start_pt;
- BezierPoint * next_curve;
- GSList * list;
- unsigned char *buf, *b;
- int draw_type;
- int * vals, val;
- int start, end;
- int x, x2, w;
- int i, j;
- if (!bezier_sel->closed)
- gimp_fatal_error ("bezier_convert(): tried to convert an open bezier curve");
- /* destroy previous mask */
- if (bezier_sel->mask)
- {
- channel_delete (bezier_sel->mask);
- bezier_sel->mask = NULL;
- }
- /* get the new mask's maximum extents */
- if (antialias)
- {
- buf = (unsigned char *) g_malloc (width);
- width = gdisp->gimage->width * SUPERSAMPLE;
- height = gdisp->gimage->height * SUPERSAMPLE;
- draw_type = AA_IMAGE_COORDS;
- /* allocate value array */
- vals = (int *) g_malloc (sizeof (int) * width);
- }
- else
- {
- buf = NULL;
- width = gdisp->gimage->width;
- height = gdisp->gimage->height;
- draw_type = IMAGE_COORDS;
- vals = NULL;
- }
- /* create a new mask */
- bezier_sel->mask = channel_ref (channel_new_mask (gdisp->gimage,
- gdisp->gimage->width,
- gdisp->gimage->height));
- /* allocate room for the scanlines */
- bezier_sel->scanlines = g_malloc (sizeof (GSList *) * height);
- /* zero out the scanlines */
- for (i = 0; i < height; i++)
- bezier_sel->scanlines[i] = NULL;
- /* scan convert the curve */
- points = bezier_sel->points;
- start_pt = bezier_sel->points;
- do {
- start_convert = 1;
- do {
- bezier_draw_segment (bezier_sel, points,
- subdivisions, draw_type,
- bezier_convert_points,
- NULL);
- /* advance to the next segment */
- points = next_anchor(points,&next_curve);
- } while (points != start_pt && points);
- start_pt = next_curve;
- points = next_curve;
- } while (next_curve);
- pixel_region_init (&maskPR, drawable_data (GIMP_DRAWABLE(bezier_sel->mask)),
- 0, 0,
- drawable_width (GIMP_DRAWABLE(bezier_sel->mask)),
- drawable_height (GIMP_DRAWABLE(bezier_sel->mask)), TRUE);
- for (i = 0; i < height; i++)
- {
- list = bezier_sel->scanlines[i];
- /* zero the vals array */
- if (antialias && !(i % SUPERSAMPLE))
- memset (vals, 0, width * sizeof (int));
- while (list)
- {
- x = (long) list->data;
- list = list->next;
- /*
- if (!list)
- g_message ("cannot properly scanline convert bezier curve: %d", i);
- else
- */
- {
- /* bounds checking */
- x = CLAMP (x, 0, width);
- x2 = CLAMP ((long) list->data, 0, width);
- w = x2 - x;
- if (!antialias)
- channel_add_segment (bezier_sel->mask, x, i, w, 255);
- else
- for (j = 0; j < w; j++)
- vals[j + x] += 255;
- list = g_slist_next (list);
- }
- }
- if (antialias && !((i+1) % SUPERSAMPLE))
- {
- b = buf;
- start = 0;
- end = width;
- for (j = start; j < end; j += SUPERSAMPLE)
- {
- val = 0;
- for (x = 0; x < SUPERSAMPLE; x++)
- val += vals[j + x];
- *b++ = (unsigned char) (val / SUPERSAMPLE2);
- }
- pixel_region_set_row (&maskPR, 0, (i / SUPERSAMPLE),
- drawable_width (GIMP_DRAWABLE(bezier_sel->mask)), buf);
- }
- g_slist_free (bezier_sel->scanlines[i]);
- }
- if (antialias)
- {
- g_free (vals);
- g_free (buf);
- }
- g_free (bezier_sel->scanlines);
- bezier_sel->scanlines = NULL;
- channel_invalidate_bounds (bezier_sel->mask);
- }
- static void
- bezier_convert_points (BezierSelect *bezier_sel,
- GdkPoint *points,
- int npoints,
- gpointer udata)
- {
- int i;
- if (start_convert)
- start_convert = 0;
- else
- bezier_convert_line (bezier_sel->scanlines, lastx, lasty, points[0].x, points[0].y);
- for (i = 0; i < (npoints - 1); i++)
- {
- bezier_convert_line (bezier_sel->scanlines,
- points[i].x, points[i].y,
- points[i+1].x, points[i+1].y);
- }
- lastx = points[npoints-1].x;
- lasty = points[npoints-1].y;
- }
- static void
- bezier_convert_line (GSList ** scanlines,
- int x1,
- int y1,
- int x2,
- int y2)
- {
- int dx, dy;
- int error, inc;
- int tmp;
- double slope;
- if (y1 == y2)
- return;
- if (y1 > y2)
- {
- tmp = y2; y2 = y1; y1 = tmp;
- tmp = x2; x2 = x1; x1 = tmp;
- }
- if (y1 < 0)
- {
- if (y2 < 0)
- return;
- if (x2 == x1)
- {
- y1 = 0;
- }
- else
- {
- slope = (double) (y2 - y1) / (double) (x2 - x1);
- x1 = x2 + (int)(0.5 + (double)(0 - y2) / slope);
- y1 = 0;
- }
- }
- if (y2 >= height)
- {
- if (y1 >= height)
- return;
- if (x2 == x1)
- {
- y2 = height;
- }
- else
- {
- slope = (double) (y2 - y1) / (double) (x2 - x1);
- x2 = x1 + (int)(0.5 + (double)(height - y1) / slope);
- y2 = height;
- }
- }
- if (y1 == y2)
- return;
- dx = x2 - x1;
- dy = y2 - y1;
- scanlines = &scanlines[y1];
- if (((dx < 0) ? -dx : dx) > ((dy < 0) ? -dy : dy))
- {
- if (dx < 0)
- {
- inc = -1;
- dx = -dx;
- }
- else
- {
- inc = 1;
- }
- error = -dx /2;
- while (x1 != x2)
- {
- error += dy;
- if (error > 0)
- {
- error -= dx;
- *scanlines = bezier_insert_in_list (*scanlines, x1);
- scanlines++;
- }
- x1 += inc;
- }
- }
- else
- {
- error = -dy /2;
- if (dx < 0)
- {
- dx = -dx;
- inc = -1;
- }
- else
- {
- inc = 1;
- }
- while (y1++ < y2)
- {
- *scanlines = bezier_insert_in_list (*scanlines, x1);
- scanlines++;
- error += dx;
- if (error > 0)
- {
- error -= dy;
- x1 += inc;
- }
- }
- }
- }
- static GSList *
- bezier_insert_in_list (GSList * list,
- int x)
- {
- GSList * orig = list;
- GSList * rest;
- if (!list)
- return g_slist_prepend (list, (void *) ((long) x));
- while (list)
- {
- rest = g_slist_next (list);
- if (x < (long) list->data)
- {
- rest = g_slist_prepend (rest, list->data);
- list->next = rest;
- list->data = (void *) ((long) x);
- return orig;
- }
- else if (!rest)
- {
- g_slist_append (list, (void *) ((long) x));
- return orig;
- }
- list = g_slist_next (list);
- }
- return orig;
- }
- gboolean
- bezier_tool_selected()
- {
- return(active_tool &&
- active_tool->type == BEZIER_SELECT &&
- active_tool->state == ACTIVE);
- }
- void
- bezier_paste_bezierselect_to_current(GDisplay *gdisp,BezierSelect *bsel)
- {
- BezierPoint *pts;
- gint i;
- Tool * tool;
- BezierPoint *bpnt = NULL;
- int need_move = 0;
- /* g_print ("bezier_paste_bezierselect_to_current::\n"); */
- /* printSel(bsel); */
- /* If the tool was being used before clear it */
- if (active_tool &&
- active_tool->type == BEZIER_SELECT &&
- active_tool->state == ACTIVE)
- {
- BezierSelect *bezier_sel = (BezierSelect*)active_tool->private;
- if(bezier_sel)
- {
- draw_core_stop ( curSel->core, active_tool );
- bezier_select_reset (bezier_sel);
- }
- }
- gimp_context_set_tool (gimp_context_get_user (), BEZIER_SELECT);
- active_tool->paused_count = 0;
- active_tool->gdisp_ptr = gdisp;
- active_tool->drawable = gimage_active_drawable (gdisp->gimage);
- tool = active_tool;
- bezier_select_reset( curSel );
- draw_core_start (curSel->core, gdisp->canvas->window, tool);
- tool->state = ACTIVE;
- pts = (BezierPoint *) bsel->points;
- for (i=0; i< bsel->num_points; i++)
- {
- if(need_move)
- {
- bezier_add_point( curSel, BEZIER_MOVE, pts->x, pts->y);
- need_move = 0;
- }
- else
- bezier_add_point( curSel, pts->type, pts->x, pts->y);
- if(bpnt == NULL)
- bpnt = curSel->last_point;
- if(pts->next_curve)
- {
- /* g_print ("bezier_paste_bezierselect_to_current:: Close last curve off \n"); */
- curSel->last_point->next = bpnt;
- bpnt->prev = curSel->last_point;
- curSel->cur_anchor = NULL;
- curSel->cur_control = NULL;
- bpnt = NULL;
- need_move = 1;
- pts = pts->next_curve;
- }
- else
- {
- pts = pts->next;
- }
- }
-
- if ( bsel->closed )
- {
- curSel->last_point->next = bpnt;
- bpnt->prev = curSel->last_point;
- curSel->cur_anchor = curSel->points;
- curSel->cur_control = curSel->points->next;
- curSel->closed = 1;
- if (curTool->gdisp_ptr)
- bezier_convert(curSel, curTool->gdisp_ptr, SUBDIVIDE, NO);
- }
- /* g_print ("After pasting...\n"); */
- /* printSel(curSel); */
- if(bsel->num_points == 0)
- {
- curSel->state = BEZIER_START;
- curSel->draw = 0;
- draw_core_stop( curSel->core, curTool);
- }
- else
- {
- curSel->state = bsel->state;
- curSel->draw = BEZIER_DRAW_ALL;
- draw_core_resume( curSel->core, curTool);
- }
- }
- static void
- bezier_to_sel_internal(BezierSelect *bezier_sel,
- Tool *tool,
- GDisplay *gdisp,
- gint op,
- gint replace)
- {
- /* If we're antialiased, then recompute the
- * mask...
- */
- if (bezier_options->antialias)
- bezier_convert (bezier_sel, tool->gdisp_ptr, SUBDIVIDE, YES);
-
- /* if (!bezier_options->extend) */
- /* { */
- /* tool->state = INACTIVE; */
- /* bezier_sel->draw = BEZIER_DRAW_CURVE; */
- /* draw_core_resume (bezier_sel->core, tool); */
-
- /* bezier_sel->draw = 0; */
- /* draw_core_stop (bezier_sel->core, tool); */
- /* } */
- if (replace)
- gimage_mask_clear (gdisp->gimage);
- else
- gimage_mask_undo (gdisp->gimage);
-
- if (bezier_options->feather)
- channel_feather (bezier_sel->mask,
- gimage_get_mask (gdisp->gimage),
- bezier_options->feather_radius,
- bezier_options->feather_radius,
- op, 0, 0);
- else
- channel_combine_mask (gimage_get_mask (gdisp->gimage),
- bezier_sel->mask, op, 0, 0);
-
- /* show selection on all views */
- gdisplays_flush ();
- }
- static int
- test_add_point_on_segment (BezierSelect *bezier_sel,
- BezierPoint *pt,
- int subdivisions,
- int space,
- int xpos,
- int ypos,
- int halfwidth)
- {
- BezierPoint *points;
- BezierMatrix geometry;
- BezierMatrix tmp1, tmp2;
- BezierMatrix deltas;
- double x, dx, dx2, dx3;
- double y, dy, dy2, dy3;
- double d, d2, d3;
- int lastx, lasty;
- int newx, newy;
- int i;
- double ratio;
- /* construct the geometry matrix from the segment */
- /* assumes that a valid segment containing 4 points is passed in */
- /* ALT ignore invalid segments since we might be working on an open curve */
- points = pt;
- ratio = -1.0;
- for (i = 0; i < 4; i++)
- {
- if (!points)
- return 0;
- switch (space)
- {
- case IMAGE_COORDS:
- geometry[i][0] = points->x;
- geometry[i][1] = points->y;
- break;
- case AA_IMAGE_COORDS:
- geometry[i][0] = RINT(points->x * SUPERSAMPLE);
- geometry[i][1] = RINT(points->y * SUPERSAMPLE);
- break;
- case SCREEN_COORDS:
- geometry[i][0] = points->sx;
- geometry[i][1] = points->sy;
- break;
- default:
- gimp_fatal_error ("test_add_point_on_segment(): Unknown coordinate space: %d", space);
- break;
- }
- geometry[i][2] = 0;
- geometry[i][3] = 0;
- points = points->next;
- }
- /* subdivide the curve n times */
- /* n can be adjusted to give a finer or coarser curve */
- d = 1.0 / subdivisions;
- d2 = d * d;
- d3 = d * d * d;
- /* construct a temporary matrix for determining the forward diffencing deltas */
- tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1;
- tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0;
- tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0;
- tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0;
- /* compose the basis and geometry matrices */
- bezier_compose (basis, geometry, tmp1);
- /* compose the above results to get the deltas matrix */
- bezier_compose (tmp2, tmp1, deltas);
- /* extract the x deltas */
- x = deltas[0][0];
- dx = deltas[1][0];
- dx2 = deltas[2][0];
- dx3 = deltas[3][0];
- /* extract the y deltas */
- y = deltas[0][1];
- dy = deltas[1][1];
- dy2 = deltas[2][1];
- dy3 = deltas[3][1];
- lastx = x;
- lasty = y;
- /* loop over the curve */
- for (i = 0; i < subdivisions; i++)
- {
- /* increment the x values */
- x += dx;
- dx += dx2;
- dx2 += dx3;
- /* increment the y values */
- y += dy;
- dy += dy2;
- dy2 += dy3;
- newx = ROUND (x);
- newy = ROUND (y);
- /* if this point is different than the last one...then test it */
- if ((lastx != newx) || (lasty != newy))
- {
- int l, r, b, t;
-
- l = newx - halfwidth;
- r = newx + halfwidth;
- t = newy - halfwidth;
- b = newy + halfwidth;
-
- if ((xpos >= l) && (xpos <= r) && (ypos >= t) && (ypos <= b))
- {
- /* so we found one point in the square hit */
-
- ratio = (double)i/(double)subdivisions;
- /* We found the exact point on the curve, so take it ...*/
- if ((xpos==newx) && (ypos==newy)) break;
- /* to Implement :
- keep each time the nearest point of the curve from where we've clicked
- in the case where we haven't click exactely on the curve.
- */
- }
- }
- lastx = newx;
- lasty = newy;
- }
- /* we found a point on the curve */
- if (ratio >= 0.0)
- {
- BezierPoint *pts, *pt1, *pt2, *pt3;
- BezierPoint *P00, *P01, *P02, *P03;
- BezierPoint P10, P11, P12;
- BezierPoint P20, P21;
- BezierPoint P30;
- pts = pt;
- P00 = pts;
- pts = pts->next;
- P01 = pts;
- pts = pts->next;
- P02 = pts;
- pts = pts->next;
- P03 = pts;
- /* De Casteljau algorithme
- [Advanced Animation & Randering Technics / Alan & Mark WATT]
- [ADDISON WESLEY ref 54412]
- Iteratif way of drawing a Bezier curve by geometrical approch
-
- P0x represent the four controls points ( anchor / control /control /anchor )
- P30 represent the new anchor point to add on the curve
- P2x represent the new control points of P30
- P1x represent the new values of the control points P01 and P02
- so if we moves ratio from 0 to 1 we draw the all curve between P00 and P03
- */
-
- P10.x = (int)((1-ratio)*P00->x + ratio * P01->x);
- P10.y = (int)((1-ratio)*P00->y + ratio * P01->y);
- P11.x = (1-ratio)*P01->x + ratio * P02->x;
- P11.y = (1-ratio)*P01->y + ratio * P02->y;
- P12.x = (1-ratio)*P02->x + ratio * P03->x;
- P12.y = (1-ratio)*P02->y + ratio * P03->y;
- P20.x = (1-ratio)*P10.x + ratio * P11.x;
- P20.y = (1-ratio)*P10.y + ratio * P11.y;
- P21.x = (1-ratio)*P11.x + ratio * P12.x;
- P21.y = (1-ratio)*P11.y + ratio * P12.y;
- P30.x = (1-ratio)*P20.x + ratio * P21.x;
- P30.y = (1-ratio)*P20.y + ratio * P21.y;
-
- P01->x = P10.x;
- P01->y = P10.y;
- P02->x = P12.x;
- P02->y = P12.y;
- /* All the computes are done, let's insert the new point on the curve */
- pt1 = g_new0(BezierPoint,1);
- pt2 = g_new0(BezierPoint,1);
- pt3 = g_new0(BezierPoint,1);
-
- pt1->type = BEZIER_CONTROL;
- pt2->type = BEZIER_ANCHOR;
- pt3->type = BEZIER_CONTROL;
-
- pt1->x = P20.x; pt1->y = P20.y;
- pt2->x = P30.x; pt2->y = P30.y;
- pt3->x = P21.x; pt3->y = P21.y;
-
- pt3->next_curve = P01->next_curve;
- P01->next = pt1;
-
- pt1->prev = P01;
- pt1->next = pt2;
-
- pt2->prev = pt1;
- pt2->next = pt3;
-
- pt3->prev = pt2;
- pt3->next = P02;
-
- P02->prev = pt3;
-
- bezier_sel->num_points += 3;
- bezier_sel->cur_anchor = pt2;
- bezier_sel->cur_control = pt1;
- return 1;
- }
- return 0;
-
- }
- void bezier_select_mode(gint mode)
- {
- ModeEdit = mode;
- }
- /* The curve has to be closed to do a selection. */
- void
- bezier_to_selection(BezierSelect *bezier_sel,
- GDisplay *gdisp)
- {
- /* Call the internal function */
- if(!bezier_sel->closed)
- {
- g_message(_("Curve not closed!"));
- return;
- }
- /* force the passed selection to be the current selection..*/
- /* This loads it into curSel for this image */
- bezier_paste_bezierselect_to_current(gdisp,bezier_sel);
- bezier_to_sel_internal(curSel,curTool,gdisp,ADD,1);
- }
- void printSel( BezierSelect *sel)
- {
- BezierPoint *pt;
- BezierPoint *start_pt;
- int i;
- pt = sel->points;
- start_pt = pt;
- g_print ("\n");
- for(i=0; i<sel->num_points; i++)
- {
- g_print ("%d(%p) x,y=%f,%f type=%d next=%p prev=%p next_curve=%p\n", i,pt, pt->x, pt->y,pt->type,pt->next,pt->prev,pt->next_curve);
- if(pt->next != start_pt && pt->next_curve)
- g_print ("Curve out a sync!!\n");
- if(pt->next_curve)
- {
- pt = pt->next_curve;
- start_pt = pt;
- }
- else
- pt = pt->next;
- }
- g_print ("core : %p\n", sel->core);
- g_print ("closed : %d\n", sel->closed);
- g_print ("draw : %d\n", sel->draw);
- g_print ("state: %d\n", sel->state);
- }
- /* check whether vectors (offx, offy), (l_offx, l_offy) have the same angle. */
- static gboolean
- stroke_interpolatable (int offx, int offy, int l_offx, int l_offy, gdouble error)
- {
- if ((offx == l_offx) & (offy == l_offy))
- return TRUE;
- else if ((offx == 0) | (l_offx == 0))
- if (offx == l_offx)
- return ((0 <= offy) & (0 <= offy)) | ((offy < 0) & (l_offy < 0));
- else
- return FALSE;
- else if ((offy == 0) | (l_offy == 0))
- if (offy == l_offy)
- return ((0 < offx) & (0 < l_offx)) | ((offx < 0) & (l_offx < 0));
- else
- return FALSE;
- /* At this point, we can assert: offx, offy, l_offx, l_offy != 0 */
- else if (((0 < offx) & (0 < l_offx)) | ((offx < 0) & (l_offx < 0)))
- {
- gdouble grad1, grad2;
- if (ABS (offy) < ABS (offx))
- {
- grad1 = (gdouble) offy / (gdouble) offx;
- grad2 = (gdouble) l_offy / (gdouble) l_offx;
- }
- else
- {
- grad1 = (gdouble) offx / (gdouble) offy;
- grad2 = (gdouble) l_offx / (gdouble) l_offy;
- }
- /* printf ("error: %f / %f\n", ABS (grad1 - grad2), error); */
- return (ABS (grad1 - grad2) <= error);
- }
- else
- return FALSE;
- }
- static void
- bezier_stack_points_aux (GdkPoint *points,
- int start,
- int end,
- gdouble error,
- BezierRenderPnts *rpnts)
- {
- const gint expand_size = 32;
- gint med;
- gint offx, offy, l_offx, l_offy;
- if (rpnts->stroke_points == NULL)
- return;
- /* BASE CASE: stack the end point */
- if (end - start <= 1)
- {
- if ((rpnts->stroke_points[rpnts->num_stroke_points * 2 - 2] == points[end].x)
- && (rpnts->stroke_points[rpnts->num_stroke_points * 2 - 1] == points[end].y))
- return;
- rpnts->num_stroke_points++;
- if (rpnts->len_stroke_points <= rpnts->num_stroke_points)
- {
- rpnts->len_stroke_points += expand_size;
- rpnts->stroke_points = g_renew (double, rpnts->stroke_points, 2 * rpnts->len_stroke_points);
- if (rpnts->stroke_points == NULL)
- {
- rpnts->len_stroke_points = rpnts->num_stroke_points = 0;
- return;
- }
- }
- rpnts->stroke_points[rpnts->num_stroke_points * 2 - 2] = points[end].x;
- rpnts->stroke_points[rpnts->num_stroke_points * 2 - 1] = points[end].y;
- return;
- }
- if (end - start <= 32)
- {
- gint i;
- for (i = start+ 1; i <= end; i++)
- bezier_stack_points_aux (points, i, i, 0,rpnts);
- return;
- }
- /* Otherwise, check whether to divide the segment recursively */
- offx = points[end].x - points[start].x;
- offy = points[end].y - points[start].y;
- med = (end + start) / 2;
- l_offx = points[med].x - points[start].x;
- l_offy = points[med].y - points[start].y;
- if (! stroke_interpolatable (offx, offy, l_offx, l_offy, error))
- {
- bezier_stack_points_aux (points, start, med, error, rpnts);
- bezier_stack_points_aux (points, med, end, error, rpnts);
- return;
- }
- l_offx = points[end].x - points[med].x;
- l_offy = points[end].y - points[med].y;
- if (! stroke_interpolatable (offx, offy, l_offx, l_offy, error))
- {
- bezier_stack_points_aux (points, start, med, error, rpnts);
- bezier_stack_points_aux (points, med, end, error, rpnts);
- return;
- }
- /* Now, the curve can be represented by a points pair: (start, end).
- So, add the last point to stroke_points. */
- bezier_stack_points_aux (points, end, end, 0, rpnts);
- }
- static void
- bezier_stack_points (BezierSelect *bezier_sel,
- GdkPoint *points,
- int npoints,
- gpointer udata)
- {
- gint i;
- gint expand_size = 32;
- gint minx, maxx, miny, maxy;
- gdouble error;
- BezierRenderPnts *rpnts = udata;
- if (npoints < 2) /* Does this happen? */
- return;
- if (rpnts->stroke_points == NULL) /* initialize it here */
- {
- rpnts->num_stroke_points = 0;
- rpnts->len_stroke_points = expand_size;
- rpnts->stroke_points = g_new (double, 2 * rpnts->len_stroke_points);
- }
- maxx = minx = points[0].x;
- maxy = miny = points[0].y;
- for (i = 1; i < npoints; i++)
- {
- if (points[i].x < minx)
- minx = points[i].x;
- else if (maxx < points[i].x)
- maxx = points[i].x;
- if (points[i].y < miny)
- miny = points[i].x;
- else if (maxy < points[i].y)
- maxy = points[i].y;
- }
- /* allow one pixel fluctuation */
- error = 2.0 / MAX(maxx - minx, maxy - miny);
- error = 0.0; /* ALT */
- /* add the start point */
- bezier_stack_points_aux (points, 0, 0, 0, rpnts);
- /* divide segments recursively */
- bezier_stack_points_aux (points, 0, npoints - 1, error, rpnts);
- /* printf ("npoints: %d\n", npoints); */
- }
- static gint
- bezier_gen_points(BezierSelect *bezier_sel,
- int open_path,
- BezierRenderPnts *rpnts)
- {
- BezierPoint * points;
- BezierPoint * start_pt;
- BezierPoint * next_curve;
- BezierRenderPnts *next_rpnts = rpnts;
- gint point_counts = 0;
- /* stack points */
- points = bezier_sel->points;
- start_pt = bezier_sel->points;
-
- if (bezier_sel->num_points >= 4)
- {
- do {
- point_counts = count_points_on_curve (points);
- if (point_counts < 4)
- return(TRUE);
- do {
- bezier_draw_segment (bezier_sel, points,
- SUBDIVIDE, AA_IMAGE_COORDS,
- bezier_stack_points,
- (gpointer) next_rpnts);
-
- points = next_anchor(points,&next_curve);
- } while (points != start_pt && points);
- start_pt = next_curve;
- points = next_curve;
- if(next_curve)
- {
- next_rpnts->next_curve = g_new0 (BezierRenderPnts, 1);
- next_rpnts = next_rpnts->next_curve;
- }
- } while (next_curve);
- }
-
- return (TRUE);
- }
- void
- bezier_stroke (BezierSelect *bezier_sel,
- GDisplay *gdisp,
- int subdivisions,
- int open_path)
- {
- Argument *return_vals;
- BezierRenderPnts *next_rpnts;
- BezierRenderPnts *rpnts;
- GimpDrawable *drawable;
- gint offset_x, offset_y;
- gint nreturn_vals;
- drawable = gimage_active_drawable (gdisp->gimage);
- if (!drawable)
- return;
- rpnts = g_new0 (BezierRenderPnts, 1);
- gimp_drawable_offsets (drawable, &offset_x, &offset_y);
- /* Start an undo group */
- undo_push_group_start (gdisp->gimage, PAINT_CORE_UNDO);
- bezier_gen_points (bezier_sel, open_path, rpnts);
- do
- {
- if (rpnts->stroke_points)
- {
- gdouble *ptr;
-
- ptr = rpnts->stroke_points;
- while (ptr < rpnts->stroke_points + (rpnts->num_stroke_points * 2))
- {
- *ptr /= SUPERSAMPLE;
- *ptr++ -= offset_x;
- *ptr /= SUPERSAMPLE;
- *ptr++ -= offset_y;
- }
-
- /* Stroke with the correct tool */
- return_vals =
- procedural_db_run_proc (tool_active_PDB_string(),
- &nreturn_vals,
- PDB_DRAWABLE, drawable_ID (drawable),
- PDB_INT32, (gint32) rpnts->num_stroke_points * 2,
- PDB_FLOATARRAY, rpnts->stroke_points,
- PDB_END);
-
- if (return_vals && return_vals[0].value.pdb_int != PDB_SUCCESS)
- g_message (_("Paintbrush operation failed."));
-
- procedural_db_destroy_args (return_vals, nreturn_vals);
-
- g_free (rpnts->stroke_points);
- }
- next_rpnts = rpnts->next_curve;
- rpnts->stroke_points = NULL;
- rpnts->len_stroke_points = rpnts->num_stroke_points = 0;
- g_free (rpnts);
- rpnts = next_rpnts;
- }
- while (rpnts);
-
- /* End an undo group */
- undo_push_group_end (gdisp->gimage);
- gdisplays_flush ();
- }
- static void
- bezier_draw_segment_for_distance (BezierSelect *bezier_sel,
- BezierPoint *points,
- int subdivisions,
- BezierDistance *bdist)
- {
- BezierMatrix geometry;
- BezierMatrix tmp1, tmp2;
- BezierMatrix deltas;
- double x, dx, dx2, dx3;
- double y, dy, dy2, dy3;
- double d, d2, d3;
- int index;
- int i;
- /* construct the geometry matrix from the segment */
- /* assumes that a valid segment containing 4 points is passed in */
- if(bdist->found)
- return;
- for (i = 0; i < 4; i++)
- {
- if (!points)
- gimp_fatal_error ("bezier_draw_segment_for_distance(): Bad bezier segment");
- geometry[i][0] = points->x;
- geometry[i][1] = points->y;
- geometry[i][2] = 0;
- geometry[i][3] = 0;
- points = points->next;
- }
- /* subdivide the curve n times */
- /* n can be adjusted to give a finer or coarser curve */
- d = 1.0 / subdivisions;
- d2 = d * d;
- d3 = d * d * d;
- /* construct a temporary matrix for determining the forward diffencing deltas */
- tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1;
- tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0;
- tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0;
- tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0;
- /* compose the basis and geometry matrices */
- bezier_compose (basis, geometry, tmp1);
- /* compose the above results to get the deltas matrix */
- bezier_compose (tmp2, tmp1, deltas);
- /* extract the x deltas */
- x = deltas[0][0];
- dx = deltas[1][0];
- dx2 = deltas[2][0];
- dx3 = deltas[3][0];
- /* extract the y deltas */
- y = deltas[0][1];
- dy = deltas[1][1];
- dy2 = deltas[2][1];
- dy3 = deltas[3][1];
- index = 1;
- /* loop over the curve */
- for (i = 0; i < subdivisions; i++)
- {
- /* increment the x values */
- x += dx;
- dx += dx2;
- dx2 += dx3;
- /* increment the y values */
- y += dy;
- dy += dy2;
- dy2 += dy3;
- /* g_print ("x = %g, y = %g\n",x,y); */
- /* if this point is different than the last one...then draw it */
- /* Note :
- * It assumes the udata is the place we want the
- * floating version of the coords to be stuffed.
- * These are needed when we calculate the gradient of the
- * curve.
- */
- if(!bdist->firstpnt)
- {
- gdouble rx = x;
- gdouble ry = y;
- gdouble dx = bdist->lastx - rx;
- gdouble dy = bdist->lasty - ry;
- bdist->curdist += sqrt((dx*dx)+(dy*dy));
- if(bdist->curdist >= bdist->dist)
- {
- *(bdist->x) = ROUND((rx + dx/2));
- *(bdist->y) = ROUND((ry + dy/2));
- if(dx == 0.0)
- *(bdist->gradient) = G_MAXDOUBLE;
- else
- *(bdist->gradient) = dy/dx;
- /* g_print ("found x = %d, y = %d\n",*(bdist->x),*(bdist->y)); */
- bdist->found = TRUE;
- break;
- }
- bdist->lastx = rx;
- bdist->lasty = ry;
- }
- else
- {
- bdist->firstpnt = FALSE;
- bdist->lastx = x;
- bdist->lasty = y;
- }
- }
- }
- static void
- bezier_draw_curve_for_distance (BezierSelect *bezier_sel,
- BezierDistance *udata)
- {
- BezierPoint * points;
- BezierPoint * start_pt;
- BezierPoint * next_curve;
- points = bezier_sel->points;
- start_pt = bezier_sel->points;
- if(bezier_sel->num_points >= 4)
- {
- do {
- do {
- bezier_draw_segment_for_distance (bezier_sel, points,
- SUBDIVIDE,
- udata);
- points = next_anchor(points,&next_curve);
- } while (points != start_pt && points);
- start_pt = next_curve;
- points = next_curve;
- } while (next_curve);
- }
- }
- gint
- bezier_distance_along(BezierSelect *bezier_sel,
- int open_path,
- gdouble dist,
- gint *x,
- gint *y,
- gdouble *gradient)
- {
- /* Render the curve as points then walk along it... */
- BezierDistance *bdist = g_new0(BezierDistance,1);
- gint ret;
- bdist->firstpnt = TRUE;
- bdist->curdist = 0.0;
- bdist->lastx = 0.0;
- bdist->lasty = 0.0;
- bdist->dist = dist;
- bdist->x = x;
- bdist->y = y;
- bdist->gradient = gradient;
- bdist->found = FALSE;
- bezier_draw_curve_for_distance (bezier_sel,bdist);
- ret = bdist->found;
- g_free(bdist);
- return (ret);
- }
|