2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r19323...
[blender.git] / source / blender / editors / curve / editcurve.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <string.h>
32
33 #ifndef WIN32
34 #include <unistd.h>
35 #else
36 #include <io.h>
37 #endif
38 #include <stdlib.h>
39 #include "MEM_guardedalloc.h"
40
41 #include "BMF_Api.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_arithb.h"
45 #include "BLI_dynstr.h"
46 #include "BLI_rand.h"
47
48 #include "DNA_curve_types.h"
49 #include "DNA_key_types.h"
50 #include "DNA_mesh_types.h"
51 #include "DNA_object_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_screen_types.h"
54 #include "DNA_space_types.h"
55 #include "DNA_view3d_types.h"
56 #include "DNA_userdef_types.h"
57
58 #include "BKE_context.h"
59 #include "BKE_curve.h"
60 #include "BKE_depsgraph.h"
61 #include "BKE_fcurve.h"
62 #include "BKE_global.h"
63 #include "BKE_key.h"
64 #include "BKE_library.h"
65 #include "BKE_main.h"
66 #include "BKE_object.h"
67 #include "BKE_report.h"
68 #include "BKE_utildefines.h"
69
70 #include "WM_api.h"
71 #include "WM_types.h"
72
73 #include "ED_anim_api.h"
74 #include "ED_curve.h"
75 #include "ED_keyframes_edit.h"
76 #include "ED_object.h"
77 #include "ED_screen.h"
78 #include "ED_types.h"
79 #include "ED_util.h"
80 #include "ED_view3d.h"
81
82 #include "UI_interface.h"
83
84 #include "BIF_transform.h"
85
86 #include "RNA_access.h"
87 #include "RNA_define.h"
88
89 /* still need to eradicate a few :( */
90 #define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name)
91
92 /* for curve objects in editmode that can have hidden handles  */
93 #define BEZSELECTED_HIDDENHANDLES(bezt)   ((G.f & G_HIDDENHANDLES) ? (bezt)->f2 & SELECT : BEZSELECTED(bezt))
94
95 float nurbcircle[8][2]= {
96         {0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0,  1.0},
97         {0.0,  1.0}, { 1.0,  1.0}, { 1.0, 0.0}, { 1.0, -1.0}
98 };
99
100 ListBase *curve_get_editcurve(Object *ob)
101 {
102         if(ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
103                 Curve *cu= ob->data;
104                 return cu->editnurb;
105         }
106         return NULL;
107 }
108
109 /* this replaces the active flag used in uv/face mode */
110 void set_actNurb(Object *obedit, Nurb *nu)
111 {
112         Curve *cu= obedit->data;
113         
114         if(nu==NULL)
115                 cu->actnu = -1;
116         else
117                 cu->actnu = BLI_findindex(cu->editnurb, nu);
118 }
119
120 Nurb *get_actNurb(Object *obedit)
121 {
122         Curve *cu= obedit->data;
123         
124         return BLI_findlink(cu->editnurb, cu->actnu);
125 }
126
127 /* ******************* SELECTION FUNCTIONS ********************* */
128
129 #define HIDDEN                  1
130 #define VISIBLE                 0
131
132 #define FIRST                   1
133 #define LAST                    0
134
135
136 /* returns 1 in case (de)selection was successful */
137 static short select_beztriple(BezTriple *bezt, short selstatus, short flag, short hidden)
138 {       
139         if(bezt) {
140                 if((bezt->hide==0) || (hidden==1)) {
141                         if(selstatus==1) { /* selects */                        
142                                 bezt->f1 |= flag;
143                                 bezt->f2 |= flag;
144                                 bezt->f3 |= flag;
145                                 return 1;                       
146                         }
147                         else { /* deselects */  
148                                 bezt->f1 &= ~flag; 
149                                 bezt->f2 &= ~flag; 
150                                 bezt->f3 &= ~flag; 
151                                 return 1;
152                         }
153                 }
154         }
155         
156         return 0;
157 }
158
159 /* returns 1 in case (de)selection was successful */
160 static short select_bpoint(BPoint *bp, short selstatus, short flag, short hidden) 
161 {       
162         if(bp) {
163                 if((bp->hide==0) || (hidden==1)) {
164                         if(selstatus==1) {
165                                 bp->f1 |= flag;
166                                 return 1;
167                         }
168                         else {
169                                 bp->f1 &= ~flag;
170                                 return 1;
171                         }
172                 }
173         }
174
175         return 0;
176 }
177
178 static short swap_selection_beztriple(BezTriple *bezt)
179 {
180         if(bezt->f2 & SELECT)
181                 return select_beztriple(bezt, DESELECT, 1, VISIBLE);
182         else
183                 return select_beztriple(bezt, SELECT, 1, VISIBLE);
184 }
185
186 static short swap_selection_bpoint(BPoint *bp)
187 {
188         if(bp->f1 & SELECT)
189                 return select_bpoint(bp, DESELECT, 1, VISIBLE);
190         else
191                 return select_bpoint(bp, SELECT, 1, VISIBLE);
192 }
193
194 short isNurbsel(Nurb *nu)
195 {
196         BezTriple *bezt;
197         BPoint *bp;
198         int a;
199
200         if((nu->type & 7)==CU_BEZIER) {
201                 bezt= nu->bezt;
202                 a= nu->pntsu;
203                 while(a--) {
204                         if( (bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT) ) return 1;
205                         bezt++;
206                 }
207         }
208         else {
209                 bp= nu->bp;
210                 a= nu->pntsu*nu->pntsv;
211                 while(a--) {
212                         if( (bp->f1 & SELECT) ) return 1;
213                         bp++;
214                 }
215         }
216         return 0;
217 }
218
219 int isNurbsel_count(Nurb *nu)
220 {
221         BezTriple *bezt;
222         BPoint *bp;
223         int a, sel=0;
224
225         if((nu->type & 7)==CU_BEZIER) {
226                 bezt= nu->bezt;
227                 a= nu->pntsu;
228                 while(a--) {
229                         if (BEZSELECTED_HIDDENHANDLES(bezt)) sel++;
230                         bezt++;
231                 }
232         }
233         else {
234                 bp= nu->bp;
235                 a= nu->pntsu*nu->pntsv;
236                 while(a--) {
237                         if( (bp->f1 & SELECT) ) sel++;
238                         bp++;
239                 }
240         }
241         return sel;
242 }
243
244 /* ******************* PRINTS ********************* */
245
246 void printknots(Object *obedit)
247 {
248         ListBase *editnurb= curve_get_editcurve(obedit);
249         Nurb *nu;
250         int a, num;
251
252         for(nu= editnurb->first; nu; nu= nu->next) {
253                 if(isNurbsel(nu) &&  (nu->type & 7)==CU_NURBS) {
254                         if(nu->knotsu) {
255                                 num= KNOTSU(nu);
256                                 for(a=0;a<num;a++) printf("knotu %d: %f\n", a, nu->knotsu[a]);
257                         }
258                         if(nu->knotsv) {
259                                 num= KNOTSV(nu);
260                                 for(a=0;a<num;a++) printf("knotv %d: %f\n", a, nu->knotsv[a]);
261                         }
262                 }
263         }
264 }
265
266 /* ********************* LOAD and MAKE *************** */
267
268 /* load editNurb in object */
269 void load_editNurb(Object *obedit)
270 {
271         ListBase *editnurb= curve_get_editcurve(obedit);
272
273         if(obedit==NULL) return;
274
275         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
276                 Curve *cu= obedit->data;
277                 Nurb *nu, *newnu;
278                 KeyBlock *actkey;
279                 int totvert= count_curveverts(editnurb);
280
281                 /* are there keys? */
282                 actkey = ob_get_keyblock(obedit);
283                 if(actkey) {
284                         /* active key: the vertices */
285                         
286                         if(totvert) {
287                                 if(actkey->data) MEM_freeN(actkey->data);
288                         
289                                 actkey->data= MEM_callocN(cu->key->elemsize*totvert, "actkey->data");
290                                 actkey->totelem= totvert;
291                 
292                                 curve_to_key(cu, actkey, editnurb);
293                         }
294                 }
295                 
296                 if(cu->key && actkey!=cu->key->refkey) {
297                         ;
298                 }
299                 else {
300                         freeNurblist(&(cu->nurb));
301                         
302                         for(nu= editnurb->first; nu; nu= nu->next) {
303                                 newnu= duplicateNurb(nu);
304                                 BLI_addtail(&(cu->nurb), newnu);
305                                 
306                                 if((nu->type & 7)==CU_NURBS) {
307                                         clamp_nurb_order_u(nu);
308                                 }
309                         }
310                 }
311         }
312         
313         set_actNurb(obedit, NULL);
314 }
315
316 /* make copy in cu->editnurb */
317 void make_editNurb(Object *obedit)
318 {
319         ListBase *editnurb= curve_get_editcurve(obedit);
320         Nurb *nu, *newnu;
321         KeyBlock *actkey;
322
323         if(obedit==NULL) return;
324
325         if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
326                 Curve *cu= obedit->data;
327                 
328                 if(editnurb)
329                         freeNurblist(editnurb);
330                 else
331                         editnurb= cu->editnurb= MEM_callocN(sizeof(ListBase), "editnurb");
332                 
333                 nu= cu->nurb.first;
334                 cu->lastselbp= NULL;   /* for select row */
335                 
336                 while(nu) {
337                         newnu= duplicateNurb(nu);
338                         test2DNurb(newnu);      // after join, or any other creation of curve
339                         BLI_addtail(editnurb, newnu);
340                         nu= nu->next;
341                 }
342                 
343                 actkey = ob_get_keyblock(obedit);
344                 if(actkey) {
345                         // XXX strcpy(G.editModeTitleExtra, "(Key) ");
346                         key_to_curve(actkey, cu, editnurb);
347                 }
348         }
349         
350         set_actNurb(obedit, NULL);
351 }
352
353 void free_editNurb(Object *obedit)
354 {
355         Curve *cu= obedit->data;
356
357         if(cu->editnurb) {
358                 freeNurblist(cu->editnurb);
359                 MEM_freeN(cu->editnurb);
360                 cu->editnurb= NULL;
361         }
362 }
363
364 /******************** separate operator ***********************/
365
366 static int separate_exec(bContext *C, wmOperator *op)
367 {
368         Scene *scene= CTX_data_scene(C);
369         Nurb *nu, *nu1;
370         Object *oldob, *newob;
371         Base *oldbase, *newbase;
372         Curve *oldcu, *newcu;
373         ListBase *oldedit, *newedit;
374
375         oldbase= CTX_data_active_base(C);
376         oldob= oldbase->object;
377         oldcu= oldob->data;
378         oldedit= oldcu->editnurb;
379
380         if(oldcu->key) {
381                 BKE_report(op->reports, RPT_ERROR, "Can't separate a curve with vertex keys.");
382                 return OPERATOR_CANCELLED;
383         }
384
385         WM_cursor_wait(1);
386         
387         /* 1. duplicate the object and data */
388         newbase= ED_object_add_duplicate(scene, oldbase, 0);    /* 0 = fully linked */
389         ED_base_object_select(newbase, BA_DESELECT);
390         newob= newbase->object;
391
392         newcu= newob->data= copy_curve(oldcu);
393         newcu->editnurb= NULL;
394         oldcu->id.us--; /* because new curve is a copy: reduce user count */
395
396         /* 2. put new object in editmode and clear it */
397         make_editNurb(newob);
398         newedit= newcu->editnurb;
399         freeNurblist(newedit);
400
401         /* 3. move over parts from old object */
402         for(nu= oldedit->first; nu; nu=nu1) {
403                 nu1= nu->next;
404
405                 if(isNurbsel(nu)) {
406                         BLI_remlink(oldedit, nu);
407                         BLI_addtail(newedit, nu);
408                 }
409         }
410
411         /* 4. put old object out of editmode */
412         load_editNurb(newob);
413         free_editNurb(newob);
414
415         DAG_object_flush_update(scene, oldob, OB_RECALC_DATA);  /* this is the original one */
416         DAG_object_flush_update(scene, newob, OB_RECALC_DATA);  /* this is the separated one */
417
418         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, oldob);
419
420         WM_cursor_wait(0);
421
422         return OPERATOR_FINISHED;
423 }
424
425 void CURVE_OT_separate(wmOperatorType *ot)
426 {
427         /* identifiers */
428         ot->name= "Separate";
429         ot->idname= "CURVE_OT_separate";
430         
431         /* api callbacks */
432         ot->exec= separate_exec;
433         ot->poll= ED_operator_editsurfcurve;
434         
435         /* flags */
436         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
437 }
438
439 /* ******************* FLAGS ********************* */
440
441 static short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
442 {
443         /* return u!=-1:     1 row in u-direction selected. U has value between 0-pntsv 
444      * return v!=-1: 1 collumn in v-direction selected. V has value between 0-pntsu 
445      */
446         BPoint *bp;
447         int a, b, sel;
448
449         *u= *v= -1;
450
451         bp= nu->bp;
452         for(b=0; b<nu->pntsv; b++) {
453                 sel= 0;
454                 for(a=0; a<nu->pntsu; a++, bp++) {
455                         if(bp->f1 & flag) sel++;
456                 }
457                 if(sel==nu->pntsu) {
458                         if(*u== -1) *u= b;
459                         else return 0;
460                 }
461                 else if(sel>1) return 0;    /* because sel==1 is still ok */
462         }
463
464         for(a=0; a<nu->pntsu; a++) {
465                 sel= 0;
466                 bp= nu->bp+a;
467                 for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
468                         if(bp->f1 & flag) sel++;
469                 }
470                 if(sel==nu->pntsv) {
471                         if(*v== -1) *v= a;
472                         else return 0;
473                 }
474                 else if(sel>1) return 0;
475         }
476
477         if(*u==-1 && *v>-1) return 1;
478         if(*v==-1 && *u>-1) return 1;
479         return 0;
480 }
481
482 static void setflagsNurb(ListBase *editnurb, short flag)
483 {
484         Nurb *nu;
485         BezTriple *bezt;
486         BPoint *bp;
487         int a;
488
489         for(nu= editnurb->first; nu; nu= nu->next) {
490                 if( (nu->type & 7)==CU_BEZIER) {
491                         a= nu->pntsu;
492                         bezt= nu->bezt;
493                         while(a--) {
494                                 bezt->f1= bezt->f2= bezt->f3= flag;
495                                 bezt++;
496                         }
497                 }
498                 else {
499                         a= nu->pntsu*nu->pntsv;
500                         bp= nu->bp;
501                         while(a--) {
502                                 bp->f1= flag;
503                                 bp++;
504                         }
505                 }
506         }
507 }
508
509 static void rotateflagNurb(ListBase *editnurb, short flag, float *cent, float rotmat[][3])
510 {
511         /* all verts with (flag & 'flag') rotate */
512         Nurb *nu;
513         BPoint *bp;
514         int a;
515
516         for(nu= editnurb->first; nu; nu= nu->next) {
517                 if((nu->type & 7)==CU_NURBS) {
518                         bp= nu->bp;
519                         a= nu->pntsu*nu->pntsv;
520
521                         while(a--) {
522                                 if(bp->f1 & flag) {
523                                         bp->vec[0]-=cent[0];
524                                         bp->vec[1]-=cent[1];
525                                         bp->vec[2]-=cent[2];
526                                         Mat3MulVecfl(rotmat, bp->vec);
527                                         bp->vec[0]+=cent[0];
528                                         bp->vec[1]+=cent[1];
529                                         bp->vec[2]+=cent[2];
530                                 }
531                                 bp++;
532                         }
533                 }
534         }
535 }
536
537 static void translateflagNurb(ListBase *editnurb, short flag, float *vec)
538 {
539         /* all verts with ('flag' & flag) translate */
540         Nurb *nu;
541         BezTriple *bezt;
542         BPoint *bp;
543         int a;
544
545         for(nu= editnurb->first; nu; nu= nu->next) {
546                 if( (nu->type & 7)==CU_BEZIER) {
547                         a= nu->pntsu;
548                         bezt= nu->bezt;
549                         while(a--) {
550                                 if(bezt->f1 & flag) VecAddf(bezt->vec[0], bezt->vec[0], vec);
551                                 if(bezt->f2 & flag) VecAddf(bezt->vec[1], bezt->vec[1], vec);
552                                 if(bezt->f3 & flag) VecAddf(bezt->vec[2], bezt->vec[2], vec);
553                                 bezt++;
554                         }
555                 }
556                 else {
557                         a= nu->pntsu*nu->pntsv;
558                         bp= nu->bp;
559                         while(a--) {
560                                 if(bp->f1 & flag) VecAddf(bp->vec, bp->vec, vec);
561                                 bp++;
562                         }
563                 }
564
565                 test2DNurb(nu);
566         }
567 }
568
569 static void weightflagNurb(ListBase *editnurb, short flag, float w, int mode)   /* mode==0: replace, mode==1: multiply */
570 {
571         Nurb *nu;
572         BPoint *bp;
573         int a;
574
575         for(nu= editnurb->first; nu; nu= nu->next) {
576                 if((nu->type & 7)==CU_NURBS) {
577                         a= nu->pntsu*nu->pntsv;
578                         bp= nu->bp;
579                         while(a--) {
580                                 if(bp->f1 & flag) {
581                                         if(mode==1) bp->vec[3]*= w;
582                                         else bp->vec[3]= w;
583                                 }
584                                 bp++;
585                         }
586                 }
587         }
588 }
589
590 static int deleteflagNurb(bContext *C, wmOperator *op, int flag)
591 {
592         Object *obedit= CTX_data_edit_object(C);
593         Curve *cu= obedit->data;
594         ListBase *editnurb= curve_get_editcurve(obedit);
595         Nurb *nu, *next;
596         BPoint *bp, *bpn, *newbp;
597         int a, b, newu, newv, sel;
598
599         if(obedit && obedit->type==OB_SURF);
600         else return OPERATOR_CANCELLED;
601
602         cu->lastselbp= NULL;
603
604         nu= editnurb->first;
605         while(nu) {
606                 next= nu->next;
607
608                 /* is entire nurb selected */
609                 bp= nu->bp;
610                 a= nu->pntsu*nu->pntsv;
611                 while(a) {
612                         a--;
613                         if(bp->f1 & flag);
614                         else break;
615                         bp++;
616                 }
617                 if(a==0) {
618                         BLI_remlink(editnurb, nu);
619                         freeNurb(nu); nu=NULL;
620                 }
621                 else {
622                         /* is nurb in U direction selected */
623                         newv= nu->pntsv;
624                         bp= nu->bp;
625                         for(b=0; b<nu->pntsv; b++) {
626                                 sel= 0;
627                                 for(a=0; a<nu->pntsu; a++, bp++) {
628                                         if(bp->f1 & flag) sel++;
629                                 }
630                                 if(sel==nu->pntsu) {
631                                         newv--;
632                                 }
633                                 else if(sel>=1) {
634                                         /* don't delete */
635                                         break;
636                                 }
637                         }
638                         if(newv!=nu->pntsv && b==nu->pntsv)     {
639                                 /* delete */
640                                 bp= nu->bp;
641                                 bpn = newbp =
642                                         (BPoint*) MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
643                                 for(b=0; b<nu->pntsv; b++) {
644                                         if((bp->f1 & flag)==0) {
645                                                 memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
646                                                 bpn+= nu->pntsu;
647                                         }
648                                         bp+= nu->pntsu;
649                                 }
650                                 nu->pntsv= newv;
651                                 MEM_freeN(nu->bp);
652                                 nu->bp= newbp;
653                                 clamp_nurb_order_v(nu);
654
655                                 makeknots(nu, 2);
656                         }
657                         else {
658                                 /* is the nurb in V direction selected */
659                                 newu= nu->pntsu;
660                                 for(a=0; a<nu->pntsu; a++) {
661                                         bp= nu->bp+a;
662                                         sel= 0;
663                                         for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
664                                                 if(bp->f1 & flag) sel++;
665                                         }
666                                         if(sel==nu->pntsv) {
667                                                 newu--;
668                                         }
669                                         else if(sel>=1) {
670                                                 /* don't delete */
671                                                 break;
672                                         }
673                                 }
674                                 if(newu!=nu->pntsu && a==nu->pntsu)     {
675                                         /* delete */
676                                         bp= nu->bp;
677                                         bpn = newbp =
678                                                 (BPoint*) MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
679                                         for(b=0; b<nu->pntsv; b++) {
680                                                 for(a=0; a<nu->pntsu; a++, bp++) {
681                                                         if((bp->f1 & flag)==0) {
682                                                                 *bpn= *bp;
683                                                                 bpn++;
684                                                         }
685                                                 }
686                                         }
687                                         MEM_freeN(nu->bp);
688                                         nu->bp= newbp;
689                                         if(newu==1 && nu->pntsv>1) {    /* make a U spline */
690                                                 nu->pntsu= nu->pntsv;
691                                                 nu->pntsv= 1;
692                                                 SWAP(short, nu->orderu, nu->orderv);
693                                                 clamp_nurb_order_u(nu);
694                                                 if(nu->knotsv) MEM_freeN(nu->knotsv);
695                                                 nu->knotsv= NULL;
696                                         }
697                                         else {
698                                                 nu->pntsu= newu;
699                                                 clamp_nurb_order_u(nu);
700                                         }
701                                         makeknots(nu, 1);
702                                 }
703                         }
704                 }
705                 nu= next;
706         }
707
708         return OPERATOR_FINISHED;
709 }
710
711 /* only for OB_SURF */
712 static short extrudeflagNurb(ListBase *editnurb, int flag)
713 {
714         Nurb *nu;
715         BPoint *bp, *bpn, *newbp;
716         int ok= 0, a, u, v, len;
717
718         nu= editnurb->first;
719         while(nu) {
720
721                 if(nu->pntsv==1) {
722                         bp= nu->bp;
723                         a= nu->pntsu;
724                         while(a) {
725                                 if(bp->f1 & flag);
726                                 else break;
727                                 bp++;
728                                 a--;
729                         }
730                         if(a==0) {
731                                 ok= 1;
732                                 newbp =
733                                         (BPoint*)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
734                                 memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) );
735                                 bp= newbp+ nu->pntsu;
736                                 memcpy(bp, nu->bp, nu->pntsu*sizeof(BPoint) );
737                                 MEM_freeN(nu->bp);
738                                 nu->bp= newbp;
739                                 a= nu->pntsu;
740                                 while(a--) {
741                                         select_bpoint(bp, SELECT, flag, HIDDEN);
742                                         select_bpoint(newbp, DESELECT, flag, HIDDEN);
743                                         bp++; 
744                                         newbp++;
745                                 }
746
747                                 nu->pntsv= 2;
748                                 nu->orderv= 2;
749                                 makeknots(nu, 2);
750                         }
751                 }
752                 else {
753                         /* which row or collumn is selected */
754
755                         if( isNurbselUV(nu, &u, &v, flag) ) {
756
757                                 /* deselect all */
758                                 bp= nu->bp;
759                                 a= nu->pntsu*nu->pntsv;
760                                 while(a--) {
761                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
762                                         bp++;
763                                 }
764
765                                 if(u==0 || u== nu->pntsv-1) {       /* row in u-direction selected */
766                                         ok= 1;
767                                         newbp =
768                                                 (BPoint*) MEM_mallocN(nu->pntsu*(nu->pntsv + 1)
769                                                                                   * sizeof(BPoint), "extrudeNurb1");
770                                         if(u==0) {
771                                                 len= nu->pntsv*nu->pntsu;
772                                                 memcpy(newbp+nu->pntsu, nu->bp, len*sizeof(BPoint) );
773                                                 memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) );
774                                                 bp= newbp;
775                                         }
776                                         else {
777                                                 len= nu->pntsv*nu->pntsu;
778                                                 memcpy(newbp, nu->bp, len*sizeof(BPoint) );
779                                                 memcpy(newbp+len, nu->bp+len-nu->pntsu, nu->pntsu*sizeof(BPoint) );
780                                                 bp= newbp+len;
781                                         }
782
783                                         a= nu->pntsu;
784                                         while(a--) {
785                                                 select_bpoint(bp, SELECT, flag, HIDDEN);
786                                                 bp++;
787                                         }
788
789                                         MEM_freeN(nu->bp);
790                                         nu->bp= newbp;
791                                         nu->pntsv++;
792                                         makeknots(nu, 2);
793                                 }
794                                 else if(v==0 || v== nu->pntsu-1) {          /* collumn in v-direction selected */
795                                         ok= 1;
796                                         bpn = newbp =
797                                                 (BPoint*) MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
798                                         bp= nu->bp;
799
800                                         for(a=0; a<nu->pntsv; a++) {
801                                                 if(v==0) {
802                                                         *bpn= *bp;
803                                                         bpn->f1 |= flag;
804                                                         bpn++;
805                                                 }
806                                                 memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
807                                                 bp+= nu->pntsu;
808                                                 bpn+= nu->pntsu;
809                                                 if(v== nu->pntsu-1) {
810                                                         *bpn= *(bp-1);
811                                                         bpn->f1 |= flag;
812                                                         bpn++;
813                                                 }
814                                         }
815
816                                         MEM_freeN(nu->bp);
817                                         nu->bp= newbp;
818                                         nu->pntsu++;
819                                         makeknots(nu, 1);
820                                 }
821                         }
822                 }
823                 nu= nu->next;
824         }
825
826         return ok;
827 }
828
829 static void adduplicateflagNurb(Object *obedit, short flag)
830 {
831         ListBase *editnurb= curve_get_editcurve(obedit);
832         Nurb *nu, *newnu;
833         BezTriple *bezt, *bezt1;
834         BPoint *bp, *bp1;
835         int a, b, starta, enda, newu, newv;
836         char *usel;
837
838         nu= editnurb->last;
839         while(nu) {
840                 if( (nu->type & 7)==CU_BEZIER) {
841                         bezt= nu->bezt;
842                         for(a=0; a<nu->pntsu; a++) {
843                                 enda= -1;
844                                 starta= a;
845                                 while( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) {
846                                         select_beztriple(bezt, DESELECT, flag, HIDDEN);
847                                         enda=a;
848                                         if(a>=nu->pntsu-1) break;
849                                         a++;
850                                         bezt++;
851                                 }
852                                 if(enda>=starta) {
853                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN");  
854                                         memcpy(newnu, nu, sizeof(Nurb));
855                                         BLI_addtail(editnurb, newnu);
856                                         set_actNurb(obedit, newnu);
857                                         newnu->pntsu= enda-starta+1;
858                                         newnu->bezt=
859                                                 (BezTriple*)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN");  
860                                         memcpy(newnu->bezt, nu->bezt+starta, newnu->pntsu*sizeof(BezTriple));
861
862                                         b= newnu->pntsu;
863                                         bezt1= newnu->bezt;
864                                         while(b--) {
865                                                 select_beztriple(bezt1, SELECT, flag, HIDDEN);
866                                                 bezt1++;
867                                         }
868
869                                         if(nu->flagu & CU_CYCLIC) {
870                                                 if(starta!=0 || enda!=nu->pntsu-1) {
871                                                         newnu->flagu &= ~CU_CYCLIC;
872                                                 }
873                                         }
874                                 }
875                                 bezt++;
876                         }
877                 }
878                 else if(nu->pntsv==1) { /* because UV Nurb has a different method for dupli */
879                         bp= nu->bp;
880                         for(a=0; a<nu->pntsu; a++) {
881                                 enda= -1;
882                                 starta= a;
883                                 while(bp->f1 & flag) {
884                                         select_bpoint(bp, DESELECT, flag, HIDDEN);
885                                         enda= a;
886                                         if(a>=nu->pntsu-1) break;
887                                         a++;
888                                         bp++;
889                                 }
890                                 if(enda>=starta) {
891                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN3");  
892                                         memcpy(newnu, nu, sizeof(Nurb));
893                                         set_actNurb(obedit, newnu);
894                                         BLI_addtail(editnurb, newnu);
895                                         newnu->pntsu= enda-starta+1;
896                                         newnu->bp = (BPoint*)MEM_mallocN((enda-starta+1) * sizeof(BPoint), "adduplicateN4");
897                                         memcpy(newnu->bp, nu->bp+starta, newnu->pntsu*sizeof(BPoint));
898
899                                         b= newnu->pntsu;
900                                         bp1= newnu->bp;
901                                         while(b--) {
902                                                 select_bpoint(bp1, SELECT, flag, HIDDEN);
903                                                 bp1++;
904                                         }
905
906                                         if(nu->flagu & CU_CYCLIC) {
907                                                 if(starta!=0 || enda!=nu->pntsu-1) {
908                                                         newnu->flagu &= ~CU_CYCLIC;
909                                                 }
910                                         }
911
912                                         /* knots */
913                                         newnu->knotsu= NULL;
914                                         makeknots(newnu, 1);
915                                 }
916                                 bp++;
917                         }
918                 }
919                 else {
920                         /* a rectangular area in nurb has to be selected */
921                         if(isNurbsel(nu)) {
922                                 usel= MEM_callocN(nu->pntsu, "adduplicateN4");
923                                 bp= nu->bp;
924                                 for(a=0; a<nu->pntsv; a++) {
925                                         for(b=0; b<nu->pntsu; b++, bp++) {
926                                                 if(bp->f1 & flag) usel[b]++;
927                                         }
928                                 }
929                                 newu= 0;
930                                 newv= 0;
931                                 for(a=0; a<nu->pntsu; a++) {
932                                         if(usel[a]) {
933                                                 if(newv==0 || usel[a]==newv) {
934                                                         newv= usel[a];
935                                                         newu++;
936                                                 }
937                                                 else {
938                                                         newv= 0;
939                                                         break;
940                                                 }
941                                         }
942                                 }
943                                 if(newu==0 || newv==0) {
944                                         printf("Can't duplicate Nurb\n");
945                                 }
946                                 else {
947
948                                         if(newu==1) SWAP(short, newu, newv);
949
950                                         newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN5");
951                                         memcpy(newnu, nu, sizeof(Nurb));
952                                         BLI_addtail(editnurb, newnu);
953                                         set_actNurb(obedit, newnu);
954                                         newnu->pntsu= newu;
955                                         newnu->pntsv= newv;
956                                         newnu->bp =
957                                                 (BPoint*)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6");
958                                         clamp_nurb_order_u(newnu);
959                                         clamp_nurb_order_v(newnu);
960                                         
961                                         newnu->knotsu= newnu->knotsv= NULL;
962                                         
963                                         bp= newnu->bp;
964                                         bp1= nu->bp;
965                                         for(a=0; a<nu->pntsv; a++) {
966                                                 for(b=0; b<nu->pntsu; b++, bp1++) {
967                                                         if(bp1->f1 & flag) {
968                                                                 memcpy(bp, bp1, sizeof(BPoint));
969                                                                 select_bpoint(bp1, DESELECT, flag, HIDDEN);
970                                                                 bp++;
971                                                         }
972                                                 }
973                                         }
974                                         if (check_valid_nurb_u(newnu)) {
975                                                 if(nu->pntsu==newnu->pntsu && nu->knotsu) {
976                                                         newnu->knotsu= MEM_dupallocN( nu->knotsu );
977                                                 } else {
978                                                         makeknots(newnu, 1);
979                                                 }
980                                         }
981                                         if (check_valid_nurb_v(newnu)) {
982                                                 if(nu->pntsv==newnu->pntsv && nu->knotsv) {
983                                                         newnu->knotsv= MEM_dupallocN( nu->knotsv );
984                                                 } else {
985                                                         makeknots(newnu, 2);
986                                                 }
987                                         }
988                                 }
989                                 MEM_freeN(usel);
990                         }
991                 }
992
993                 nu= nu->prev;
994         }
995         
996         /* actnu changed */
997 }
998
999 /**************** switch direction operator ***************/
1000
1001 static int switch_direction_exec(bContext *C, wmOperator *op)
1002 {
1003         Object *obedit= CTX_data_edit_object(C);
1004         ListBase *editnurb= curve_get_editcurve(obedit);
1005         Nurb *nu;
1006         
1007         for(nu= editnurb->first; nu; nu= nu->next)
1008                 if(isNurbsel(nu))
1009                         switchdirectionNurb(nu);
1010         
1011         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1012         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
1013
1014         return OPERATOR_FINISHED;
1015 }
1016
1017 void CURVE_OT_switch_direction(wmOperatorType *ot)
1018 {
1019         /* identifiers */
1020         ot->name= "Switch Direction";
1021         ot->idname= "CURVE_OT_switch_direction";
1022         
1023         /* api callbacks */
1024         ot->exec= switch_direction_exec;
1025         ot->poll= ED_operator_editsurfcurve;
1026
1027         /* flags */
1028         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1029 }
1030
1031 /****************** set weight operator *******************/
1032
1033 static int set_weight_exec(bContext *C, wmOperator *op)
1034 {
1035         Object *obedit= CTX_data_edit_object(C);
1036         ListBase *editnurb= curve_get_editcurve(obedit);
1037         Nurb *nu;
1038         BezTriple *bezt;
1039         BPoint *bp;
1040         float weight= RNA_float_get(op->ptr, "weight");
1041         int a;
1042                                 
1043         for(nu= editnurb->first; nu; nu= nu->next) {
1044                 if(nu->bezt) {
1045                         for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1046                                 if(bezt->f2 & SELECT)
1047                                         bezt->weight= weight;
1048                         }
1049                 }
1050                 else if(nu->bp) {
1051                         for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1052                                 if(bp->f1 & SELECT)
1053                                         bp->weight= weight;
1054                         }
1055                 }
1056         }       
1057
1058         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1059         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
1060
1061         return OPERATOR_FINISHED;
1062 }
1063
1064 void CURVE_OT_spline_weight_set(wmOperatorType *ot)
1065 {
1066         /* identifiers */
1067         ot->name= "Set Curve Weight";
1068         ot->idname= "CURVE_OT_spline_weight_set";
1069         
1070         /* api callbacks */
1071         ot->exec= set_weight_exec;
1072         ot->invoke= WM_operator_redo;
1073         ot->poll= ED_operator_editsurfcurve;
1074
1075         /* flags */
1076         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1077
1078         /* properties */
1079         RNA_def_float_percentage(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
1080 }
1081
1082 /******************* set radius operator ******************/
1083
1084 static int set_radius_exec(bContext *C, wmOperator *op)
1085 {
1086         Object *obedit= CTX_data_edit_object(C);
1087         ListBase *editnurb= curve_get_editcurve(obedit);
1088         Nurb *nu;
1089         BezTriple *bezt;
1090         BPoint *bp;
1091         float radius= RNA_float_get(op->ptr, "radius");
1092         int a;
1093         
1094         for(nu= editnurb->first; nu; nu= nu->next) {
1095                 if(nu->bezt) {
1096                         for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1097                                 if(bezt->f2 & SELECT)
1098                                         bezt->radius= radius;
1099                         }
1100                 }
1101                 else if(nu->bp) {
1102                         for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1103                                 if(bp->f1 & SELECT)
1104                                         bp->radius= radius;
1105                         }
1106                 }
1107         }       
1108
1109         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
1110         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1111
1112         return OPERATOR_FINISHED;
1113 }
1114
1115 void CURVE_OT_radius_set(wmOperatorType *ot)
1116 {
1117         /* identifiers */
1118         ot->name= "Set Curve Radius";
1119         ot->idname= "CURVE_OT_radius_set";
1120         
1121         /* api callbacks */
1122         ot->exec= set_radius_exec;
1123         ot->invoke= WM_operator_redo;
1124         ot->poll= ED_operator_editsurfcurve;
1125
1126         /* flags */
1127         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1128
1129         /* properties */
1130         RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "", 0.0001f, 10.0f);
1131 }
1132
1133 /********************* smooth operator ********************/
1134
1135 static int smooth_exec(bContext *C, wmOperator *op)
1136 {
1137         Object *obedit= CTX_data_edit_object(C);
1138         ListBase *editnurb= curve_get_editcurve(obedit);
1139         Nurb *nu;
1140         BezTriple *bezt, *beztOrig;
1141         BPoint *bp, *bpOrig;
1142         float val, newval, offset;
1143         int a, i, change = 0;
1144         
1145         for(nu= editnurb->first; nu; nu= nu->next) {
1146                 if(nu->bezt) {
1147                         change = 0;
1148                         beztOrig = MEM_dupallocN( nu->bezt );
1149                         for(bezt=nu->bezt+1, a=1; a<nu->pntsu-1; a++, bezt++) {
1150                                 if(bezt->f2 & SELECT) {
1151                                         for(i=0; i<3; i++) {
1152                                                 val = bezt->vec[1][i];
1153                                                 newval = ((beztOrig+(a-1))->vec[1][i] * 0.5) + ((beztOrig+(a+1))->vec[1][i] * 0.5);
1154                                                 offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
1155                                                 /* offset handles */
1156                                                 bezt->vec[1][i] += offset;
1157                                                 bezt->vec[0][i] += offset;
1158                                                 bezt->vec[2][i] += offset;
1159                                         }
1160                                         change = 1;
1161                                 }
1162                         }
1163                         MEM_freeN(beztOrig);
1164                         if (change)
1165                                 calchandlesNurb(nu);
1166                 } else if (nu->bp) {
1167                         bpOrig = MEM_dupallocN( nu->bp );
1168                         /* Same as above, keep these the same! */
1169                         for(bp=nu->bp+1, a=1; a<nu->pntsu-1; a++, bp++) {
1170                                 if(bp->f1 & SELECT) {
1171                                         for(i=0; i<3; i++) {
1172                                                 val = bp->vec[i];
1173                                                 newval = ((bpOrig+(a-1))->vec[i] * 0.5) + ((bpOrig+(a+1))->vec[i] * 0.5);
1174                                                 offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
1175                                         
1176                                                 bp->vec[i] += offset;
1177                                         }
1178                                 }
1179                         }
1180                         MEM_freeN(bpOrig);
1181                 }
1182         }
1183
1184         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
1185         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1186
1187         return OPERATOR_FINISHED;
1188 }
1189
1190 void CURVE_OT_smooth(wmOperatorType *ot)
1191 {
1192         /* identifiers */
1193         ot->name= "Smooth";
1194         ot->idname= "CURVE_OT_smooth";
1195         
1196         /* api callbacks */
1197         ot->exec= smooth_exec;
1198         ot->poll= ED_operator_editsurfcurve;
1199
1200         /* flags */
1201         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1202 }
1203
1204 /**************** smooth curve radius operator *************/
1205
1206 /* TODO, make smoothing distance based */
1207 static int smooth_radius_exec(bContext *C, wmOperator *op)
1208 {
1209         Object *obedit= CTX_data_edit_object(C);
1210         ListBase *editnurb= curve_get_editcurve(obedit);
1211         Nurb *nu;
1212         BezTriple *bezt;
1213         BPoint *bp;
1214         int a;
1215         
1216         /* use for smoothing */
1217         int last_sel;
1218         int start_sel, end_sel; /* selection indicies, inclusive */
1219         float start_rad, end_rad, fac, range;
1220         
1221         for(nu= editnurb->first; nu; nu= nu->next) {
1222                 if(nu->bezt) {
1223                         
1224                         for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
1225                                 /* loop over selection segments of a curve, smooth each */
1226                                 
1227                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
1228                                 start_sel = end_sel = -1;
1229                                 for(bezt=nu->bezt+last_sel, a=last_sel; a<nu->pntsu; a++, bezt++) {
1230                                         if(bezt->f2 & SELECT) {
1231                                                 start_sel = a;
1232                                                 break;
1233                                         }
1234                                 }
1235                                 /* incase there are no other selected verts */
1236                                 end_sel = start_sel;
1237                                 for(bezt=nu->bezt+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bezt++) {
1238                                         if((bezt->f2 & SELECT)==0) {
1239                                                 break;
1240                                         }
1241                                         end_sel = a;
1242                                 }
1243                                 
1244                                 if (start_sel == -1) {
1245                                         last_sel = nu->pntsu; /* next... */
1246                                 } else {
1247                                         last_sel = end_sel; /* before we modify it */
1248                                         
1249                                         /* now blend between start and end sel */
1250                                         start_rad = end_rad = -1.0;
1251                                         
1252                                         if (start_sel == end_sel) {
1253                                                 /* simple, only 1 point selected */
1254                                                 if (start_sel>0)                                                start_rad = (nu->bezt+start_sel-1)->radius;
1255                                                 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bezt+start_sel+1)->radius;
1256                                                 
1257                                                 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bezt+start_sel)->radius = (start_rad + end_rad)/2;
1258                                                 else if (start_rad >= 0.0)                              (nu->bezt+start_sel)->radius = start_rad;
1259                                                 else if (end_rad >= 0.0)                                (nu->bezt+start_sel)->radius = end_rad;
1260                                         } else {
1261                                                 /* if endpoints selected, then use them */
1262                                                 if (start_sel==0) {
1263                                                         start_rad = (nu->bezt+start_sel)->radius;
1264                                                         start_sel++; /* we dont want to edit the selected endpoint */
1265                                                 } else {
1266                                                         start_rad = (nu->bezt+start_sel-1)->radius;
1267                                                 }
1268                                                 if (end_sel==nu->pntsu-1) {
1269                                                         end_rad = (nu->bezt+end_sel)->radius;
1270                                                         end_sel--; /* we dont want to edit the selected endpoint */
1271                                                 } else {
1272                                                         end_rad = (nu->bezt+end_sel+1)->radius;
1273                                                 }
1274                                                 
1275                                                 /* Now Blend between the points */
1276                                                 range = (float)(end_sel - start_sel) + 2.0f;
1277                                                 for(bezt=nu->bezt+start_sel, a=start_sel; a<=end_sel; a++, bezt++) {
1278                                                         fac = (float)(1+a-start_sel) / range;
1279                                                         bezt->radius = start_rad*(1.0-fac) + end_rad*fac;
1280                                                 }
1281                                         }
1282                                 }
1283                         }
1284                 } else if (nu->bp) {
1285                         /* Same as above, keep these the same! */
1286                         for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
1287                                 /* loop over selection segments of a curve, smooth each */
1288                                 
1289                                 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
1290                                 start_sel = end_sel = -1;
1291                                 for(bp=nu->bp+last_sel, a=last_sel; a<nu->pntsu; a++, bp++) {
1292                                         if(bp->f1 & SELECT) {
1293                                                 start_sel = a;
1294                                                 break;
1295                                         }
1296                                 }
1297                                 /* incase there are no other selected verts */
1298                                 end_sel = start_sel;
1299                                 for(bp=nu->bp+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bp++) {
1300                                         if((bp->f1 & SELECT)==0) {
1301                                                 break;
1302                                         }
1303                                         end_sel = a;
1304                                 }
1305                                 
1306                                 if (start_sel == -1) {
1307                                         last_sel = nu->pntsu; /* next... */
1308                                 } else {
1309                                         last_sel = end_sel; /* before we modify it */
1310                                         
1311                                         /* now blend between start and end sel */
1312                                         start_rad = end_rad = -1.0;
1313                                         
1314                                         if (start_sel == end_sel) {
1315                                                 /* simple, only 1 point selected */
1316                                                 if (start_sel>0)                                                start_rad = (nu->bp+start_sel-1)->radius;
1317                                                 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bp+start_sel+1)->radius;
1318                                                 
1319                                                 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bp+start_sel)->radius = (start_rad + end_rad)/2;
1320                                                 else if (start_rad >= 0.0)                              (nu->bp+start_sel)->radius = start_rad;
1321                                                 else if (end_rad >= 0.0)                                (nu->bp+start_sel)->radius = end_rad;
1322                                         } else {
1323                                                 /* if endpoints selected, then use them */
1324                                                 if (start_sel==0) {
1325                                                         start_rad = (nu->bp+start_sel)->radius;
1326                                                         start_sel++; /* we dont want to edit the selected endpoint */
1327                                                 } else {
1328                                                         start_rad = (nu->bp+start_sel-1)->radius;
1329                                                 }
1330                                                 if (end_sel==nu->pntsu-1) {
1331                                                         end_rad = (nu->bp+end_sel)->radius;
1332                                                         end_sel--; /* we dont want to edit the selected endpoint */
1333                                                 } else {
1334                                                         end_rad = (nu->bp+end_sel+1)->radius;
1335                                                 }
1336                                                 
1337                                                 /* Now Blend between the points */
1338                                                 range = (float)(end_sel - start_sel) + 2.0f;
1339                                                 for(bp=nu->bp+start_sel, a=start_sel; a<=end_sel; a++, bp++) {
1340                                                         fac = (float)(1+a-start_sel) / range;
1341                                                         bp->radius = start_rad*(1.0-fac) + end_rad*fac;
1342                                                 }
1343                                         }
1344                                 }
1345                         }
1346                 }
1347         }
1348
1349         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
1350         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1351
1352         return OPERATOR_FINISHED;
1353 }
1354
1355 void CURVE_OT_smooth_radius(wmOperatorType *ot)
1356 {
1357         /* identifiers */
1358         ot->name= "Smooth Curve Radius";
1359         ot->idname= "CURVE_OT_smooth_radius";
1360         
1361         /* api clastbacks */
1362         ot->exec= smooth_radius_exec;
1363         ot->poll= ED_operator_editsurfcurve;
1364         
1365         /* flags */
1366         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1367 }
1368
1369 /***************** selection utility *************************/
1370
1371 /* next == 1 -> select next             */
1372 /* next == -1 -> select previous        */
1373 /* cont == 1 -> select continuously     */
1374 /* selstatus, inverts behaviour         */
1375 static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus)
1376 {
1377         Nurb *nu;
1378         BezTriple *bezt;
1379         BPoint *bp;
1380         int a;
1381         short lastsel= 0, sel=0;
1382         
1383         if(next==0) return;
1384         
1385         for(nu= editnurb->first; nu; nu= nu->next) {
1386                 lastsel=0;
1387                 if((nu->type & 7)==CU_BEZIER) {                 
1388                         a= nu->pntsu;
1389                         bezt= nu->bezt;
1390                         if(next < 0) bezt= (nu->bezt + (a-1));
1391                         while(a--) {
1392                                 if(a-abs(next) < 0) break;
1393                                 sel= 0;
1394                                 if((lastsel==0) && (bezt->hide==0) && ((bezt->f2 & SELECT) || (selstatus==0))) {
1395                                         bezt+=next;
1396                                         if(!(bezt->f2 & SELECT) || (selstatus==0)) {
1397                                                 sel= select_beztriple(bezt, selstatus, 1, VISIBLE);     
1398                                                 if((sel==1) && (cont==0)) lastsel= 1;
1399                                         }                                                       
1400                                 }
1401                                 else {
1402                                         bezt+=next;
1403                                         lastsel= 0;
1404                                 }
1405                                 /* move around in zigzag way so that we go through each */                              
1406                                 bezt-=(next-next/abs(next));                            
1407                         }
1408                 }
1409                 else {
1410                         a= nu->pntsu*nu->pntsv;
1411                         bp= nu->bp;
1412                         if(next < 0) bp= (nu->bp + (a-1));
1413                         while(a--) {
1414                                 if(a-abs(next) < 0) break;
1415                                 sel=0;
1416                                 if((lastsel==0) && (bp->hide==0) && ((bp->f1 & SELECT) || (selstatus==0))) {
1417                                         bp+=next;
1418                                         if(!(bp->f1 & SELECT) || (selstatus==0)) {
1419                                                 sel= select_bpoint(bp, selstatus, 1, VISIBLE);
1420                                                 if((sel==1) && (cont==0)) lastsel= 1;
1421                                         }                       
1422                                 }
1423                                 else {
1424                                         bp+=next;
1425                                         lastsel= 0;
1426                                 }
1427                                 /* move around in zigzag way so that we go through each */
1428                                 bp-=(next-next/abs(next));                              
1429                         }
1430                 }
1431         }
1432 }
1433
1434 /**************** select start/end operators **************/
1435
1436 /* (de)selects first or last of visible part of each Nurb depending on selFirst     */
1437 /* selFirst: defines the end of which to select                                     */
1438 /* doswap: defines if selection state of each first/last control point is swapped   */
1439 /* selstatus: selection status in case doswap is false                              */
1440 void selectend_nurb(Object *obedit, short selfirst, short doswap, short selstatus)
1441 {
1442         ListBase *editnurb= curve_get_editcurve(obedit);
1443         Nurb *nu;
1444         BPoint *bp;
1445         BezTriple *bezt;
1446         int a;
1447         short sel;
1448         
1449         if(obedit==0) return;
1450         
1451         for(nu= editnurb->first; nu; nu= nu->next) {
1452                 sel= 0;
1453                 if((nu->type & 7)==CU_BEZIER) {
1454                         a= nu->pntsu;
1455                         
1456                         /* which point? */
1457                         if(selfirst==0) { /* select last */ 
1458                                 bezt= (nu->bezt + (a-1));
1459                         }
1460                         else { /* select first */
1461                                 bezt= nu->bezt;
1462                         }
1463                         
1464                         while(a--) {
1465                                 if(doswap) sel= swap_selection_beztriple(bezt);
1466                                 else sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
1467                                 
1468                                 if(sel==1) break;
1469                         }
1470                 }
1471                 else {
1472                         a= nu->pntsu*nu->pntsv;
1473                         
1474                         /* which point? */
1475                         if(selfirst==0) { /* select last */
1476                                 bp= (nu->bp + (a-1));
1477                         }
1478                         else{ /* select first */
1479                                 bp= nu->bp;
1480                         }
1481
1482                         while(a--) {
1483                                 if (bp->hide == 0) {
1484                                         if(doswap) sel= swap_selection_bpoint(bp);
1485                                         else sel= select_bpoint(bp, selstatus, 1, VISIBLE);
1486                                         
1487                                         if(sel==1) break;
1488                                 }
1489                         }
1490                 }
1491         }
1492 }
1493
1494 static int de_select_first_exec(bContext *C, wmOperator *op)
1495 {
1496         Object *obedit= CTX_data_edit_object(C);
1497
1498         selectend_nurb(obedit, FIRST, 1, DESELECT);
1499         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1500
1501         return OPERATOR_FINISHED;
1502 }
1503
1504 void CURVE_OT_de_select_first(wmOperatorType *ot)
1505 {
1506         /* identifiers */
1507         ot->name= "Select or Deselect First";
1508         ot->idname= "CURVE_OT_de_select_first";
1509         
1510         /* api cfirstbacks */
1511         ot->exec= de_select_first_exec;
1512         ot->poll= ED_operator_editcurve;
1513         
1514         /* flags */
1515         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1516 }
1517
1518 static int de_select_last_exec(bContext *C, wmOperator *op)
1519 {
1520         Object *obedit= CTX_data_edit_object(C);
1521
1522         selectend_nurb(obedit, LAST, 1, DESELECT);
1523         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1524
1525         return OPERATOR_FINISHED;
1526 }
1527
1528 void CURVE_OT_de_select_last(wmOperatorType *ot)
1529 {
1530         /* identifiers */
1531         ot->name= "Select or Deselect Last";
1532         ot->idname= "CURVE_OT_de_select_last";
1533         
1534         /* api clastbacks */
1535         ot->exec= de_select_last_exec;
1536         ot->poll= ED_operator_editcurve;
1537         
1538         /* flags */
1539         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1540 }
1541
1542 /******************* de select all operator ***************/
1543
1544 static short nurb_has_selected_cps(ListBase *editnurb)
1545 {
1546         Nurb *nu;
1547         BezTriple *bezt;
1548         BPoint *bp;
1549         int a;
1550
1551         for(nu= editnurb->first; nu; nu= nu->next) {
1552                 if((nu->type & 7)==CU_BEZIER) {
1553                         a= nu->pntsu;
1554                         bezt= nu->bezt;
1555                         while(a--) {
1556                                 if(bezt->hide==0) {
1557                                         if((bezt->f1 & SELECT)
1558                                         || (bezt->f2 & SELECT)
1559                                         || (bezt->f3 & SELECT)) return 1;
1560                                 }
1561                                 bezt++;
1562                         }
1563                 }
1564                 else {
1565                         a= nu->pntsu*nu->pntsv;
1566                         bp= nu->bp;
1567                         while(a--) {
1568                                 if((bp->hide==0) && (bp->f1 & SELECT)) return 1;
1569                                 bp++;
1570                         }
1571                 }
1572         }
1573         
1574         return 0;
1575 }
1576
1577 static int de_select_all_exec(bContext *C, wmOperator *op)
1578 {
1579         Object *obedit= CTX_data_edit_object(C);
1580         ListBase *editnurb= curve_get_editcurve(obedit);
1581         
1582         if(nurb_has_selected_cps(editnurb)) { /* deselect all */
1583                 selectend_nurb(obedit, FIRST, 0, DESELECT); /* set first control points as unselected */
1584                 select_adjacent_cp(editnurb, 1, 1, DESELECT); /* cascade selection */   
1585         }
1586         else { /* select all */
1587                 selectend_nurb(obedit, FIRST, 0, SELECT); /* set first control points as selected */
1588                 select_adjacent_cp(editnurb, 1, 1, SELECT); /* cascade selection */
1589         }
1590         
1591         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1592
1593         return OPERATOR_FINISHED;
1594 }
1595
1596 void CURVE_OT_select_all_toggle(wmOperatorType *ot)
1597 {
1598         /* identifiers */
1599         ot->name= "Select or Deselect All";
1600         ot->idname= "CURVE_OT_select_all_toggle";
1601         
1602         /* api callbacks */
1603         ot->exec= de_select_all_exec;
1604         ot->poll= ED_operator_editsurfcurve;
1605         
1606         /* flags */
1607         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1608 }
1609
1610 /********************** hide operator *********************/
1611
1612 static int hide_exec(bContext *C, wmOperator *op)
1613 {
1614         Object *obedit= CTX_data_edit_object(C);
1615         ListBase *editnurb= curve_get_editcurve(obedit);
1616         Nurb *nu;
1617         BPoint *bp;
1618         BezTriple *bezt;
1619         int a, sel, invert= RNA_boolean_get(op->ptr, "unselected");
1620
1621         for(nu= editnurb->first; nu; nu= nu->next) {
1622                 if((nu->type & 7)==CU_BEZIER) {
1623                         bezt= nu->bezt;
1624                         a= nu->pntsu;
1625                         sel= 0;
1626                         while(a--) {
1627                                 if(invert == 0 && BEZSELECTED_HIDDENHANDLES(bezt)) {
1628                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
1629                                         bezt->hide= 1;
1630                                 }
1631                                 else if(invert && !BEZSELECTED_HIDDENHANDLES(bezt)) {
1632                                         select_beztriple(bezt, DESELECT, 1, HIDDEN);
1633                                         bezt->hide= 1;
1634                                 }
1635                                 if(bezt->hide) sel++;
1636                                 bezt++;
1637                         }
1638                         if(sel==nu->pntsu) nu->hide= 1;
1639                 }
1640                 else {
1641                         bp= nu->bp;
1642                         a= nu->pntsu*nu->pntsv;
1643                         sel= 0;
1644                         while(a--) {
1645                                 if(invert==0 && (bp->f1 & SELECT)) {
1646                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
1647                                         bp->hide= 1;
1648                                 }
1649                                 else if(invert && (bp->f1 & SELECT)==0) {
1650                                         select_bpoint(bp, DESELECT, 1, HIDDEN);
1651                                         bp->hide= 1;
1652                                 }
1653                                 if(bp->hide) sel++;
1654                                 bp++;
1655                         }
1656                         if(sel==nu->pntsu*nu->pntsv) nu->hide= 1;
1657                 }
1658         }
1659
1660         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1661         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1662
1663         return OPERATOR_FINISHED;       
1664 }
1665
1666 void CURVE_OT_hide(wmOperatorType *ot)
1667 {
1668         /* identifiers */
1669         ot->name= "Hide Selected";
1670         ot->idname= "CURVE_OT_hide";
1671         
1672         /* api callbacks */
1673         ot->exec= hide_exec;
1674         ot->poll= ED_operator_editsurfcurve;
1675         
1676         /* flags */
1677         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1678         
1679         /* props */
1680         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1681 }
1682
1683 /********************** reveal operator *********************/
1684
1685 static int reveal_exec(bContext *C, wmOperator *op)
1686 {
1687         Object *obedit= CTX_data_edit_object(C);
1688         ListBase *editnurb= curve_get_editcurve(obedit);
1689         Nurb *nu;
1690         BPoint *bp;
1691         BezTriple *bezt;
1692         int a;
1693
1694         for(nu= editnurb->first; nu; nu= nu->next) {
1695                 nu->hide= 0;
1696                 if((nu->type & 7)==CU_BEZIER) {
1697                         bezt= nu->bezt;
1698                         a= nu->pntsu;
1699                         while(a--) {
1700                                 if(bezt->hide) {
1701                                         select_beztriple(bezt, SELECT, 1, HIDDEN);
1702                                         bezt->hide= 0;
1703                                 }
1704                                 bezt++;
1705                         }
1706                 }
1707                 else {
1708                         bp= nu->bp;
1709                         a= nu->pntsu*nu->pntsv;
1710                         while(a--) {
1711                                 if(bp->hide) {
1712                                         select_bpoint(bp, SELECT, 1, HIDDEN);
1713                                         bp->hide= 0;
1714                                 }
1715                                 bp++;
1716                         }
1717                 }
1718         }
1719
1720         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
1721         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1722
1723         return OPERATOR_FINISHED;       
1724 }
1725
1726 void CURVE_OT_reveal(wmOperatorType *ot)
1727 {
1728         /* identifiers */
1729         ot->name= "Reveal Hidden";
1730         ot->idname= "CURVE_OT_reveal";
1731         
1732         /* api callbacks */
1733         ot->exec= reveal_exec;
1734         ot->poll= ED_operator_editsurfcurve;
1735         
1736         /* flags */
1737         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1738 }
1739
1740 /********************** select invert operator *********************/
1741
1742 static int select_invert_exec(bContext *C, wmOperator *op)
1743 {
1744         Object *obedit= CTX_data_edit_object(C);
1745         ListBase *editnurb= curve_get_editcurve(obedit);
1746         Nurb *nu;
1747         BPoint *bp;
1748         BezTriple *bezt;
1749         int a;
1750
1751         for(nu= editnurb->first; nu; nu= nu->next) {
1752                 if((nu->type & 7)==CU_BEZIER) {
1753                         bezt= nu->bezt;
1754                         a= nu->pntsu;
1755                         while(a--) {
1756                                 if(bezt->hide==0) {
1757                                         bezt->f2 ^= SELECT; /* always do the center point */
1758                                         if ((G.f & G_HIDDENHANDLES)==0) {
1759                                                 bezt->f1 ^= SELECT;
1760                                                 bezt->f3 ^= SELECT;
1761                                         }
1762                                 }
1763                                 bezt++;
1764                         }
1765                 }
1766                 else {
1767                         bp= nu->bp;
1768                         a= nu->pntsu*nu->pntsv;
1769                         while(a--) {
1770                                 swap_selection_bpoint(bp);
1771                                 bp++;
1772                         }
1773                 }
1774         }
1775
1776         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
1777
1778         return OPERATOR_FINISHED;       
1779 }
1780
1781 void CURVE_OT_select_invert(wmOperatorType *ot)
1782 {
1783         /* identifiers */
1784         ot->name= "Select Invert";
1785         ot->idname= "CURVE_OT_select_invert";
1786         
1787         /* api callbacks */
1788         ot->exec= select_invert_exec;
1789         ot->poll= ED_operator_editsurfcurve;
1790         
1791         /* flags */
1792         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1793 }
1794
1795 /********************** subdivide operator *********************/
1796
1797 /** Divide the line segments associated with the currently selected
1798  * curve nodes (Bezier or NURB). If there are no valid segment
1799  * selections within the current selection, nothing happens.
1800  *
1801  * @deffunc subdividenurb subdivideNurb(void)
1802  * @return Nothing
1803  * @param  None
1804 */
1805
1806 static int subdivide_exec(bContext *C, wmOperator *op)
1807 {
1808         Object *obedit= CTX_data_edit_object(C);
1809         ListBase *editnurb= curve_get_editcurve(obedit);
1810         Nurb *nu;
1811         BezTriple *prevbezt, *bezt, *beztnew, *beztn;
1812         BPoint *bp, *prevbp, *bpnew, *bpn;
1813         float vec[15];
1814         int a, b, sel, amount, *usel, *vsel;
1815
1816    // printf("*** subdivideNurb: entering subdivide\n");
1817
1818         for(nu= editnurb->first; nu; nu= nu->next) {
1819                 amount= 0;
1820                 if((nu->type & 7)==CU_BEZIER) {
1821         /* 
1822            Insert a point into a 2D Bezier curve. 
1823            Endpoints are preserved. Otherwise, all selected and inserted points are 
1824            newly created. Old points are discarded.
1825         */
1826                         /* count */
1827                         if(nu->flagu & CU_CYCLIC) {
1828                                 a= nu->pntsu;
1829                                 bezt= nu->bezt;
1830                                 prevbezt= bezt+(a-1);
1831                         }
1832                         else {
1833                                 a= nu->pntsu-1;
1834                                 prevbezt= nu->bezt;
1835                                 bezt= prevbezt+1;
1836                         }
1837                         while(a--) {
1838                                 if( BEZSELECTED_HIDDENHANDLES(prevbezt) && BEZSELECTED_HIDDENHANDLES(bezt) ) amount++;
1839                                 prevbezt= bezt;
1840                                 bezt++;
1841                         }
1842
1843                         if(amount) {
1844                                 /* insert */
1845                                 beztnew =
1846                                         (BezTriple*)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
1847                                 beztn= beztnew;
1848                                 if(nu->flagu & CU_CYCLIC) {
1849                                         a= nu->pntsu;
1850                                         bezt= nu->bezt;
1851                                         prevbezt= bezt+(a-1);
1852                                 }
1853                                 else {
1854                                         a= nu->pntsu-1;
1855                                         prevbezt= nu->bezt;
1856                                         bezt= prevbezt+1;
1857                                 }
1858                                 while(a--) {
1859                                         memcpy(beztn, prevbezt, sizeof(BezTriple));
1860                                         beztn++;
1861
1862                                         if( BEZSELECTED_HIDDENHANDLES(prevbezt) && BEZSELECTED_HIDDENHANDLES(bezt) ) {
1863                                                 memcpy(beztn, bezt, sizeof(BezTriple));
1864                                                 
1865                                                 /* midpoint subdividing */
1866                                                 VecMidf(vec, prevbezt->vec[1], prevbezt->vec[2]);
1867                                                 VecMidf(vec+3, prevbezt->vec[2], bezt->vec[0]);
1868                                                 VecMidf(vec+6, bezt->vec[0], bezt->vec[1]);
1869                                                 
1870                                                 VecMidf(vec+9, vec, vec+3);
1871                                                 VecMidf(vec+12, vec+3, vec+6);
1872                                                 
1873                                                 /* change handle of prev beztn */
1874                                                 VECCOPY((beztn-1)->vec[2], vec);
1875                                                 /* new point */
1876                                                 VECCOPY(beztn->vec[0], vec+9);
1877                                                 VecMidf(beztn->vec[1], vec+9, vec+12);
1878                                                 VECCOPY(beztn->vec[2], vec+12);
1879                                                 /* handle of next bezt */
1880                                                 if(a==0 && (nu->flagu & CU_CYCLIC)) {VECCOPY(beztnew->vec[0], vec+6);}
1881                                                 else {VECCOPY(bezt->vec[0], vec+6);}
1882                                                 
1883                                                 beztn->radius = (prevbezt->radius + bezt->radius)/2.0f;
1884                                                 beztn->weight = (prevbezt->weight + bezt->weight)/2.0f;
1885                                                 
1886                                                 beztn++;
1887                                         }
1888
1889                                         prevbezt= bezt;
1890                                         bezt++;
1891                                 }
1892                                 /* last point */
1893                                 if((nu->flagu & CU_CYCLIC)==0) memcpy(beztn, prevbezt, sizeof(BezTriple));
1894
1895                                 MEM_freeN(nu->bezt);
1896                                 nu->bezt= beztnew;
1897                                 nu->pntsu+= amount;
1898
1899                                 calchandlesNurb(nu);
1900                         }
1901                 } /* End of 'if((nu->type & 7)==CU_BEZIER)' */
1902                 else if (nu->pntsv==1) {
1903         /* 
1904            All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves 
1905            are handled together with the regular NURB plane division, as it 
1906            should be. I split it off just now, let's see if it is
1907            stable... nzc 30-5-'00
1908          */
1909                         /* count */
1910                         if(nu->flagu & CU_CYCLIC) {
1911                                 a= nu->pntsu;
1912                                 bp= nu->bp;
1913                                 prevbp= bp+(a-1);
1914                         }
1915                         else {
1916                                 a= nu->pntsu-1;
1917                                 prevbp= nu->bp;
1918                                 bp= prevbp+1;
1919                         }
1920                         while(a--) {
1921                                 if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) amount++;
1922                                 prevbp= bp;
1923                                 bp++;
1924                         }
1925
1926                         if(amount) {
1927                                 /* insert */
1928                                 bpnew =
1929                                         (BPoint*)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
1930                                 bpn= bpnew;
1931
1932                                 if(nu->flagu & CU_CYCLIC) {
1933                                         a= nu->pntsu;
1934                                         bp= nu->bp;
1935                                         prevbp= bp+(a-1);
1936                                 }
1937                                 else {
1938                                         a= nu->pntsu-1;
1939                                         prevbp= nu->bp;
1940                                         bp= prevbp+1;
1941                                 }
1942                                 while(a--) {
1943                                         memcpy(bpn, prevbp, sizeof(BPoint));
1944                                         bpn++;
1945
1946                                         if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) {
1947                  // printf("*** subdivideNurb: insert 'linear' point\n");
1948                                                 memcpy(bpn, bp, sizeof(BPoint));
1949                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1950                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1951                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1952                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1953                                                 bpn++;
1954
1955                                         }
1956                                         prevbp= bp;
1957                                         bp++;
1958                                 }
1959                                 if((nu->flagu & CU_CYCLIC)==0) memcpy(bpn, prevbp, sizeof(BPoint));     /* last point */
1960
1961                                 MEM_freeN(nu->bp);
1962                                 nu->bp= bpnew;
1963                                 nu->pntsu+= amount;
1964
1965                                 if(nu->type & CU_NURBS) {
1966                                         makeknots(nu, 1);
1967                                 }
1968                         }
1969                 } /* End of 'else if(nu->pntsv==1)' */
1970                 else if((nu->type & 7)==CU_NURBS) {
1971         /* This is a very strange test ... */
1972         /** 
1973            Subdivide NURB surfaces - nzc 30-5-'00 -
1974            
1975              Subdivision of a NURB curve can be effected by adding a 
1976            control point (insertion of a knot), or by raising the
1977            degree of the functions used to build the NURB. The
1978            expression 
1979
1980                degree = #knots - #controlpoints + 1 (J Walter piece)
1981                degree = #knots - #controlpoints     (Blender
1982                                                       implementation)
1983                  ( this is confusing.... what is true? Another concern
1984                  is that the JW piece allows the curve to become
1985                  explicitly 1st order derivative discontinuous, while
1986                  this is not what we want here... )
1987
1988            is an invariant for a single NURB curve. Raising the degree
1989            of the NURB is done elsewhere; the degree is assumed
1990            constant during this opration. Degree is a property shared
1991            by all controlpoints in a curve (even though it is stored
1992            per control point - this can be misleading).
1993              Adding a knot is done by searching for the place in the
1994            knot vector where a certain knot value must be inserted, or
1995            by picking an appropriate knot value between two existing
1996            ones. The number of controlpoints that is influenced by the
1997            insertion depends on the order of the curve. A certain
1998            minimum number of knots is needed to form high-order
1999            curves, as can be seen from the equation above. In Blender,
2000            currently NURBs may be up to 6th order, so we modify at
2001            most 6 points. One point is added. For an n-degree curve,
2002            n points are discarded, and n+1 points inserted
2003            (so effectively, n points are modified).  (that holds for
2004            the JW piece, but it seems not for our NURBs)
2005               In practice, the knot spacing is copied, but the tail
2006            (the points following the insertion point) need to be
2007            offset to keep the knot series ascending. The knot series
2008            is always a series of monotonically ascending integers in
2009            Blender. When not enough control points are available to
2010            fit the order, duplicates of the endpoints are added as
2011            needed. 
2012         */
2013                         /* selection-arrays */
2014                         usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3");
2015                         vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3");
2016                         sel= 0;
2017
2018          /* Count the number of selected points. */
2019                         bp= nu->bp;
2020                         for(a=0; a<nu->pntsv; a++) {
2021                                 for(b=0; b<nu->pntsu; b++) {
2022                                         if(bp->f1 & SELECT) {
2023                                                 usel[b]++;
2024                                                 vsel[a]++;
2025                                                 sel++;
2026                                         }
2027                                         bp++;
2028                                 }
2029                         }
2030                         if( sel == (nu->pntsu*nu->pntsv) ) {    /* subdivide entire nurb */
2031            /* Global subdivision is a special case of partial
2032               subdivision. Strange it is considered separately... */
2033                                 bpn=bpnew= MEM_mallocN( (2*nu->pntsu-1)*(2*nu->pntsv-1)*sizeof(BPoint), "subdivideNurb4");
2034                                 bp= nu->bp;
2035                                 /* first subdivide rows */
2036                                 for(a=0; a<nu->pntsv; a++) {
2037                                         for(b=0; b<nu->pntsu; b++) {
2038                                                 *bpn= *bp;
2039                                                 bpn++; 
2040                                                 bp++;
2041                                                 if(b<nu->pntsu-1) {
2042                                                         *bpn= *bp;
2043                                                         prevbp= bp-1;
2044                                                         bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
2045                                                         bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
2046                                                         bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
2047                                                         bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
2048                                                         bpn++;
2049                                                 }
2050                                         }
2051                                         bpn+= (2*nu->pntsu-1);
2052                                 }
2053                                 /* now insert new */
2054                                 bpn= bpnew+(2*nu->pntsu-1);
2055                                 bp= bpnew+(4*nu->pntsu-2);
2056                                 prevbp= bpnew;
2057                                 for(a=1; a<nu->pntsv; a++) {
2058
2059                                         for(b=0; b<2*nu->pntsu-1; b++) {
2060                                                 *bpn= *bp;
2061                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
2062                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
2063                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
2064                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
2065                                                 bpn++; 
2066                                                 bp++; 
2067                                                 prevbp++;
2068                                         }
2069                                         bp+= (2*nu->pntsu-1);
2070                                         bpn+= (2*nu->pntsu-1);
2071                                         prevbp+= (2*nu->pntsu-1);
2072                                 }
2073                                 MEM_freeN(nu->bp);
2074                                 nu->bp= bpnew;
2075                                 nu->pntsu= 2*nu->pntsu-1;
2076                                 nu->pntsv= 2*nu->pntsv-1;
2077                                 makeknots(nu, 1);
2078                                 makeknots(nu, 2);
2079                         } /* End of 'if(sel== nu->pntsu*nu->pntsv)' (subdivide entire NURB) */
2080                         else {
2081                                 /* subdivide in v direction? */
2082                                 sel= 0;
2083                                 for(a=0; a<nu->pntsv-1; a++) {
2084                                         if(vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu) sel++;
2085                                 }
2086
2087                                 if(sel) {   /* V ! */
2088                                         bpn=bpnew= MEM_mallocN( (sel+nu->pntsv)*nu->pntsu*sizeof(BPoint), "subdivideNurb4");
2089                                         bp= nu->bp;
2090                                         for(a=0; a<nu->pntsv; a++) {
2091                                                 for(b=0; b<nu->pntsu; b++) {
2092                                                         *bpn= *bp;
2093                                                         bpn++; 
2094                                                         bp++;
2095                                                 }
2096                                                 if( (a<nu->pntsv-1) && vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu ) {
2097                                                         prevbp= bp- nu->pntsu;
2098                                                         for(b=0; b<nu->pntsu; b++) {
2099                        /* 
2100                           This simple bisection must be replaces by a
2101                           subtle resampling of a number of points. Our 
2102                           task is made slightly easier because each
2103                           point in our curve is a separate data
2104                           node. (is it?)
2105                        */
2106                                                                 *bpn= *prevbp;
2107                                                                 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
2108                                                                 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
2109                                                                 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
2110                                                                 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
2111                                                                 bpn++;
2112                                                                 prevbp++;
2113                                                                 bp++;
2114                                                         }
2115                                                         bp-= nu->pntsu;
2116                                                 }
2117                                         }
2118                                         MEM_freeN(nu->bp);
2119                                         nu->bp= bpnew;
2120                                         nu->pntsv+= sel;
2121                                         makeknots(nu, 2);
2122                                 }
2123                                 else {
2124                                         /* or in u direction? */
2125                                         sel= 0;
2126                                         for(a=0; a<nu->pntsu-1; a++) {
2127                                                 if(usel[a]==nu->pntsv && usel[a+1]==nu->pntsv) sel++;
2128                                         }
2129
2130                                         if(sel) {       /* U ! */
2131                  /* Inserting U points is sort of 'default' Flat curves only get */
2132                  /* U points inserted in them.                                   */
2133                                                 bpn=bpnew= MEM_mallocN( (sel+nu->pntsu)*nu->pntsv*sizeof(BPoint), "subdivideNurb4");
2134                                                 bp= nu->bp;
2135                                                 for(a=0; a<nu->pntsv; a++) {
2136                                                         for(b=0; b<nu->pntsu; b++) {
2137                                                                 *bpn= *bp;
2138                                                                 bpn++; 
2139                                                                 bp++;
2140                                                                 if( (b<nu->pntsu-1) && usel[b]==nu->pntsv && usel[b+1]==nu->pntsv ) {
2141                           /* 
2142                              One thing that bugs me here is that the
2143                              orders of things are not the same as in
2144                              the JW piece. Also, this implies that we
2145                              handle at most 3rd order curves? I miss
2146                              some symmetry here...
2147                           */
2148                                                                         prevbp= bp- 1;
2149                                                                         *bpn= *prevbp;
2150                                                                         bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
2151                                                                         bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
2152                                                                         bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
2153                                                                         bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
2154                                                                         bpn++;
2155                                                                 }
2156                                                         }
2157                                                 }
2158                                                 MEM_freeN(nu->bp);
2159                                                 nu->bp= bpnew;
2160                                                 nu->pntsu+= sel;
2161                                                 makeknots(nu, 1); /* shift knots
2162                                                      forward */
2163                                         }
2164                                 }
2165                         }
2166                         MEM_freeN(usel); 
2167                         MEM_freeN(vsel);
2168
2169                 } /* End of 'if((nu->type & 7)==CU_NURBS)'  */
2170         }
2171
2172         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
2173         DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
2174
2175         return OPERATOR_FINISHED;       
2176 }
2177
2178 void CURVE_OT_subdivide(wmOperatorType *ot)
2179 {
2180         /* identifiers */
2181         ot->name= "Subdivide";
2182         ot->idname= "CURVE_OT_subdivide";
2183         
2184         /* api callbacks */
2185         ot->exec= subdivide_exec;
2186         ot->poll= ED_operator_editsurfcurve;
2187         
2188         /* flags */
2189         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2190 }
2191
2192 /******************** find nearest ************************/
2193
2194 static void findnearestNurbvert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
2195 {
2196         struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; int dist, hpoint, select, mval[2]; } *data = userData;
2197
2198         short flag;
2199         short temp;
2200
2201         if (bp) {
2202                 flag = bp->f1;
2203         } else {
2204                 if (beztindex==0) {
2205                         flag = bezt->f1;
2206                 } else if (beztindex==1) {
2207                         flag = bezt->f2;
2208                 } else {
2209                         flag = bezt->f3;
2210                 }
2211         }
2212
2213         temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
2214         if ((flag&1)==data->select) temp += 5;
2215         if (bezt && beztindex==1) temp += 3; /* middle points get a small disadvantage */
2216
2217         if (temp<data->dist) {
2218                 data->dist = temp;
2219
2220                 data->bp = bp;
2221                 data->bezt = bezt;
2222                 data->nurb = nu;
2223                 data->hpoint = bezt?beztindex:0;
2224         }
2225 }
2226
2227 static short findnearestNurbvert(ViewContext *vc, short sel, int mval[2], Nurb **nurb, BezTriple **bezt, BPoint **bp)
2228 {
2229                 /* sel==1: selected gets a disadvantage */
2230                 /* in nurb and bezt or bp the nearest is written */
2231                 /* return 0 1 2: handlepunt */
2232         struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; int dist, hpoint, select, mval[2]; } data = {0};
2233
2234         data.dist = 100;
2235         data.hpoint = 0;
2236         data.select = sel;
2237         data.mval[0] = mval[0];
2238         data.mval[1] = mval[1];
2239
2240         nurbs_foreachScreenVert(vc, findnearestNurbvert__doClosest, &data);
2241
2242         *nurb = data.nurb;
2243         *bezt = data.bezt;
2244         *bp = data.bp;
2245
2246         return data.hpoint;
2247 }
2248
2249 static void findselectedNurbvert(ListBase *editnurb, Nurb **nu, BezTriple **bezt, BPoint **bp)
2250 {
2251         /* in nu and (bezt or bp) selected are written if there's 1 sel.  */
2252         /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
2253         Nurb *nu1;
2254         BezTriple *bezt1;
2255         BPoint *bp1;
2256         int a;
2257
2258         *nu= 0;
2259         *bezt= 0;
2260         *bp= 0;
2261         for(nu1= editnurb->first; nu1; nu1= nu1->next) {
2262                 if((nu1->type & 7)==CU_BEZIER) {
2263                         bezt1= nu1->bezt;
2264                         a= nu1->pntsu;
2265                         while(a--) {
2266                                 if( (bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT) ) {
2267                                         if(*nu!=0 && *nu!= nu1) {
2268                                                 *nu= 0;
2269                                                 *bp= 0;
2270                                                 *bezt= 0;
2271                                                 return;
2272                                         }
2273                                         else if(*bezt || *bp) {
2274                                                 *bp= 0;
2275                                                 *bezt= 0;
2276                                         }
2277                                         else {
2278                                                 *bezt= bezt1;
2279                                                 *nu= nu1;
2280                                         }
2281                                 }
2282                                 bezt1++;
2283                         }
2284                 }
2285                 else {
2286                         bp1= nu1->bp;
2287                         a= nu1->pntsu*nu1->pntsv;
2288                         while(a--) {
2289                                 if( bp1->f1 & 1 ) {
2290                                         if(*nu!=0 && *nu!= nu1) {
2291                                                 *bp= 0;
2292                                                 *bezt= 0;
2293                                                 *nu= 0;
2294                                                 return;
2295                                         }
2296                                         else if(*bezt || *bp) {
2297                                                 *bp= 0;
2298                                                 *bezt= 0;
2299                                         }
2300                                         else {
2301                                                 *bp= bp1;
2302                                                 *nu= nu1;
2303                                         }
2304                                 }
2305                                 bp1++;
2306                         }
2307                 }
2308         }
2309 }
2310
2311 /***************** set spline type operator *******************/
2312
2313 static int convertspline(short type, Nurb *nu)
2314 {
2315         BezTriple *bezt;
2316         BPoint *bp;
2317         int a, c, nr;
2318
2319         if((nu->type & 7)==CU_POLY) {
2320                 if(type==CU_BEZIER) {                       /* to Bezier with vecthandles  */
2321                         nr= nu->pntsu;
2322                         bezt =
2323                                 (BezTriple*)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
2324                         nu->bezt= bezt;
2325                         a= nr;
2326                         bp= nu->bp;
2327                         while(a--) {
2328                                 VECCOPY(bezt->vec[1], bp->vec);
2329                                 bezt->f1=bezt->f2=bezt->f3= bp->f1;
2330                                 bezt->h1= bezt->h2= HD_VECT;
2331                                 bezt->weight= bp->weight;
2332                                 bezt->radius= bp->radius;
2333                                 bp++;
2334                                 bezt++;
2335                         }
2336                         MEM_freeN(nu->bp);
2337                         nu->bp= 0;
2338                         nu->pntsu= nr;
2339                         nu->type &= ~7;
2340                         nu->type |= CU_BEZIER;
2341                         calchandlesNurb(nu);
2342                 }
2343                 else if(type==CU_NURBS) {
2344                         nu->type &= ~7;
2345                         nu->type |= CU_NURBS;
2346                         nu->orderu= 4;
2347                         nu->flagu &= CU_CYCLIC; /* disable all flags except for cyclic */
2348                         nu->flagu += 4;
2349                         makeknots(nu, 1);
2350                         a= nu->pntsu*nu->pntsv;
2351                         bp= nu->bp;
2352                         while(a--) {
2353                                 bp->vec[3]= 1.0;
2354                                 bp++;
2355                         }
2356                 }
2357         }
2358         else if((nu->type & 7)==CU_BEZIER) {    /* Bezier */
2359                 if(type==0 || type==4) {            /* to Poly or Nurb */
2360                         nr= 3*nu->pntsu;
2361                         nu->bp = MEM_callocN(nr * sizeof(BPoint), "setsplinetype");
2362                         a= nu->pntsu;
2363                         bezt= nu->bezt;
2364                         bp= nu->bp;
2365                         while(a--) {
2366                                 if(type==0 && bezt->h1==HD_VECT && bezt->h2==HD_VECT) {
2367                                         /* vector handle becomes 1 poly vertice */
2368                                         VECCOPY(bp->vec, bezt->vec[1]);
2369                                         bp->vec[3]= 1.0;
2370                                         bp->f1= bezt->f2;
2371                                         nr-= 2;
2372                                         bp->radius= bezt->radius;
2373                                         bp->weight= bezt->weight;
2374                                         bp++;
2375                                 }
2376                                 else {
2377                                         for(c=0;c<3;c++) {
2378                                                 VECCOPY(bp->vec, bezt->vec[c]);
2379                                                 bp->vec[3]= 1.0;
2380                                                 if(c==0) bp->f1= bezt->f1;
2381                                                 else if(c==1) bp->f1= bezt->f2;
2382                                                 else bp->f1= bezt->f3;
2383                                                 bp->radius= bezt->radius;
2384                                                 bp->weight= bezt->weight;
2385                                                 bp++;
2386                                         }
2387                                 }
2388                                 bezt++;
2389                         }
2390                         MEM_freeN(nu->bezt); 
2391                         nu->bezt= 0;
2392                         nu->pntsu= nr;
2393                         nu->pntsv= 1;
2394                         nu->orderu= 4;
2395                         nu->orderv= 1;
2396                         nu->type &= ~7;
2397                         nu->type+= type;
2398                         if(nu->flagu & CU_CYCLIC) c= nu->orderu-1; 
2399                         else c= 0;
2400                         if(type== 4) {
2401                                 nu->flagu &= CU_CYCLIC; /* disable all flags except for cyclic */
2402                                 nu->flagu += 4;
2403                                 makeknots(nu, 1);
2404                         }
2405                 }
2406         }
2407         else if((nu->type & 7)==CU_NURBS) {
2408                 if(type==0) {                   /* to Poly */
2409                         nu->type &= ~7;
2410                         if(nu->knotsu) MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
2411                         nu->knotsu= NULL;
2412                         if(nu->knotsv) MEM_freeN(nu->knotsv);
2413                         nu->knotsv= NULL;
2414                 }
2415                 else if(type==CU_BEZIER) {              /* to Bezier */
2416                         nr= nu->pntsu/3;
2417
2418                         if(nr<2) 
2419                                 return 1;       /* conversion impossible */
2420                         else {
2421                                 bezt = MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
2422                                 nu->bezt= bezt;
2423                                 a= nr;
2424                                 bp= nu->bp;
2425                                 while(a--) {
2426                                         VECCOPY(bezt->vec[0], bp->vec);
2427                                         bezt->f1= bp->f1;
2428                                         bp++;
2429                                         VECCOPY(bezt->vec[1], bp->vec);
2430                                         bezt->f2= bp->f1;
2431                                         bp++;
2432                                         VECCOPY(bezt->vec[2], bp->vec);
2433                                         bezt->f3= bp->f1;
2434                                         bezt->radius= bp->radius;
2435                                         bezt->weight= bp->weight;
2436                                         bp++;
2437                                         bezt++;
2438                                 }
2439                                 MEM_freeN(nu->bp);
2440                                 nu->bp= 0;
2441                                 MEM_freeN(nu->knotsu);
2442                                 nu->knotsu= NULL;
2443                                 nu->pntsu= nr;
2444                                 nu->type &= ~7;
2445                                 nu->type |= CU_BEZIER;
2446                         }
2447                 }
2448         }
2449
2450         return 0;
2451 }
2452
2453 static int set_spline_type_exec(bContext *C, wmOperator *op)
2454 {
2455         Object *obedit= CTX_data_edit_object(C);
2456         ListBase *editnurb= curve_get_editcurve(obedit);
2457         Nurb *nu;
2458         int changed=0, type= RNA_enum_get(op->ptr, "type");
2459
2460         if(type==CU_CARDINAL || type==CU_BSPLINE) {
2461                 BKE_report(op->reports, RPT_ERROR, "Not implemented yet");
2462                 return OPERATOR_CANCELLED;
2463         }
2464         
2465         for(nu= editnurb->first; nu; nu= nu->next) {
2466                 if(isNurbsel(nu)) {
2467                         if(convertspline(type, nu))
2468                                 BKE_report(op->reports, RPT_ERROR, "No conversion possible");
2469                         else
2470                                 changed= 1;
2471                 }
2472         }
2473
2474         return (changed)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
2475 }
2476
2477 void CURVE_OT_spline_type_set(wmOperatorType *ot)
2478 {
2479         static EnumPropertyItem type_items[]= {
2480                 {CU_POLY, "POLY", "Poly", ""},
2481                 {CU_BEZIER, "BEZIER", "Bezier", ""},
2482                 {CU_CARDINAL, "CARDINAL", "Cardinal", ""},
2483                 {CU_BSPLINE, "B_SPLINE", "B-Spline", ""},
2484                 {CU_NURBS, "NURBS", "NURBS", ""},
2485                 {0, NULL, NULL, NULL}};
2486
2487         /* identifiers */
2488         ot->name= "Set Spline Type";
2489         ot->idname= "CURVE_OT_spline_type_set";
2490         
2491         /* api callbacks */
2492         ot->exec= set_spline_type_exec;
2493         ot->poll= ED_operator_editcurve;
2494         
2495         /* flags */
2496         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2497
2498         /* properties */
2499         RNA_def_enum(ot->srna, "type", type_items, CU_POLY, "Type", "Spline type");
2500 }
2501
2502 /***************** set handle type operator *******************/
2503
2504 static int set_handle_type_exec(bContext *C, wmOperator *op)
2505 {
2506         Scene *scene= CTX_data_scene(C);
2507         Object *obedit= CTX_data_edit_object(C);
2508         ListBase *editnurb= curve_get_editcurve(obedit);
2509
2510         sethandlesNurb(editnurb, RNA_enum_get(op->ptr, "type"));
2511
2512         WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, obedit);
2513         DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2514
2515         return OPERATOR_FINISHED;
2516 }
2517
2518 void CURVE_OT_handle_type_set(wmOperatorType *ot)
2519 {
2520         static EnumPropertyItem type_items[]= {
2521                 {1, "AUTOMATIC", "Automatic", ""},
2522                 {2, "VECTOR", "Vector", ""},
2523                 {3, "TOGGLE_FREE_ALIGN", "Toggle Free/Align", ""},
2524                 {5, "ALIGN", "Align", ""},
2525                 {6, "FREE_ALIGN", "Free Align", ""},
2526                 {0, NULL, NULL, NULL}};
2527
2528         /* identifiers */
2529         ot->name= "Set Handle Type";
2530         ot->idname= "CURVE_OT_handle_type_set";
2531         
2532         /* api callbacks */
2533         ot->exec= set_handle_type_exec;
2534         ot->poll= ED_operator_editcurve;
2535         
2536         /* flags */
2537         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2538
2539         /* properties */
2540         RNA_def_enum(ot->srna, "type", type_items, CU_POLY, "Type", "Spline type");
2541 }
2542
2543 /***************** make segment operator **********************/
2544
2545 /* ******************** SKINNING LOFTING!!! ******************** */
2546
2547 static void switchdirection_knots(float *base, int tot)
2548 {
2549         float *fp1, *fp2, *tempf;
2550         int a;
2551         
2552         if(base==NULL || tot==0) return;
2553         
2554         /* reverse knots */
2555         a= tot;
2556         fp1= base;
2557         fp2= fp1+(a-1);
2558         a/= 2;
2559         while(fp1!=fp2 && a>0) {
2560                 SWAP(float, *fp1, *fp2);
2561                 a--;
2562                 fp1++; 
2563                 fp2--;
2564         }
2565         /* and make in increasing order again */
2566         a= tot;
2567         fp1= base;
2568         fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect");
2569         while(a--) {
2570                 fp2[0]= fabs(fp1[1]-fp1[0]);
2571                 fp1++;
2572                 fp2++;
2573         }
2574
2575         a= tot-1;
2576         fp1= base;
2577         fp2= tempf;
2578         fp1[0]= 0.0;
2579         fp1++;
2580         while(a--) {
2581                 fp1[0]= fp1[-1]+fp2[0];
2582                 fp1++;
2583                 fp2++;
2584         }
2585         MEM_freeN(tempf);
2586 }
2587
2588 static void rotate_direction_nurb(Nurb *nu)
2589 {
2590         BPoint *bp1, *bp2, *temp;
2591         int u, v;
2592         
2593         SWAP(short, nu->pntsu, nu->pntsv);
2594         SWAP(short, nu->orderu, nu->orderv);
2595         SWAP(short, nu->resolu, nu->resolv);
2596         SWAP(short, nu->flagu, nu->flagv);
2597         
2598         SWAP(float *, nu->knotsu, nu->knotsv);
2599         switchdirection_knots(nu->knotsv, KNOTSV(nu) );
2600         
2601         temp= MEM_dupallocN(nu->bp);
2602         bp1= nu->bp;
2603         for(v=0; v<nu->pntsv; v++) {
2604                 for(u=0; u<nu->pntsu; u++, bp1++) {
2605                         bp2= temp + (nu->pntsu-u-1)*(nu->pntsv) + v;
2606                         *bp1= *bp2;
2607                 }
2608         }
2609
2610         MEM_freeN(temp);
2611 }
2612
2613 static int is_u_selected(Nurb *nu, int u)
2614 {
2615         BPoint *bp;
2616         int v;
2617         
2618         /* what about resolu == 2? */
2619         bp= nu->bp+u;
2620         for(v=0; v<nu->pntsv-1; v++, bp+=nu->pntsu) {
2621                 if(v) if(bp->f1 & SELECT) return 1;
2622         }
2623         
2624         return 0;
2625 }
2626
2627 typedef struct NurbSort {
2628         struct NurbSort *next, *prev;
2629         Nurb *nu;
2630         float vec[3];
2631 } NurbSort;
2632
2633 static ListBase nsortbase= {0, 0};
2634 /*  static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
2635
2636 static void make_selection_list_nurb(ListBase *editnurb)
2637 {
2638         ListBase nbase= {0, 0};
2639         NurbSort *nus, *nustest, *headdo, *taildo;
2640         Nurb *nu;
2641         BPoint *bp;
2642         float dist, headdist, taildist;
2643         int a;
2644         
2645         for(nu= editnurb->first; nu; nu= nu->next) {
2646                 if( isNurbsel(nu) ) {
2647                         
2648                         nus = (NurbSort*)MEM_callocN(sizeof(NurbSort), "sort");
2649                         BLI_addhead(&nbase, nus);
2650                         nus->nu= nu;
2651                         
2652                         bp= nu->bp;
2653                         a= nu->pntsu;
2654                         while(a--) {
2655                                 VecAddf(nus->vec, nus->vec, bp->vec);
2656                                 bp++;
2657                         }
2658                         VecMulf(nus->vec, 1.0/(float)nu->pntsu);
2659                         
2660                         
2661                 }
2662         }
2663
2664         /* just add the first one */
2665         nus= nbase.first;
2666         BLI_remlink(&nbase, nus);
2667         BLI_addtail( &nsortbase, nus);
2668         
2669         /* now add, either at head or tail, the closest one */
2670         while(nbase.first) {
2671         
2672                 headdist= taildist= 1.0e30;
2673                 headdo= taildo= 0;
2674
2675                 nustest= nbase.first;
2676                 while(nustest) {
2677                         dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.first)->vec);
2678
2679                         if(dist<headdist) {
2680                                 headdist= dist;
2681                                 headdo= nustest;
2682                         }
2683                         dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.last)->vec);
2684
2685                         if(dist<taildist) {
2686                                 taildist= dist;
2687                                 taildo= nustest;
2688                         }
2689                         nustest= nustest->next;
2690                 }
2691                 
2692                 if(headdist<taildist) {
2693                         BLI_remlink(&nbase, headdo);
2694                         BLI_addhead(&nsortbase, headdo);
2695                 }
2696                 else {
2697                         BLI_remlink(&nbase, taildo);
2698                         BLI_addtail(&nsortbase, taildo);
2699                 }
2700         }
2701 }
2702
2703 static void merge_2_nurb(wmOperator *op, ListBase *editnurb, Nurb *nu1, Nurb *nu2)
2704 {
2705         BPoint *bp, *bp1, *bp2, *temp;
2706         float  len1, len2;
2707         int    origu, u, v;
2708         
2709         /* first nurbs will be changed to make u = resolu-1 selected */
2710         /* 2nd nurbs will be changed to make u = 0 selected */
2711
2712         /* first nurbs: u = resolu-1 selected */
2713         
2714         if( is_u_selected(nu1, nu1->pntsu-1) );
2715         else {
2716                 rotate_direction_nurb(nu1);
2717                 if( is_u_selected(nu1, nu1->pntsu-1) );
2718                 else {
2719                         rotate_direction_nurb(nu1);
2720                         if( is_u_selected(nu1, nu1->pntsu-1) );
2721                         else {
2722                                 rotate_direction_nurb(nu1);
2723                                 if( is_u_selected(nu1, nu1->pntsu-1) );
2724                                 else {
2725                                         /* rotate again, now its OK! */
2726                                         if(nu1->pntsv!=1) rotate_direction_nurb(nu1);
2727                                         return;
2728                                 }
2729                         }
2730                 }
2731         }
2732         
2733         /* 2nd nurbs: u = 0 selected */
2734         if( is_u_selected(nu2, 0) );
2735         else {
2736                 rotate_direction_nurb(nu2);
2737                 if( is_u_selected(nu2, 0) );
2738                 else {
2739                         rotate_direction_nurb(nu2);
2740                         if( is_u_selected(nu2, 0) );
2741                         else {
2742                                 rotate_direction_nurb(nu2);
2743                                 if( is_u_selected(nu2, 0) );
2744                                 else {
2745                                         /* rotate again, now its OK! */
2746                                         if(nu1->pntsu==1) rotate_direction_nurb(nu1);
2747                                         if(nu2->pntsv!=1) rotate_direction_nurb(nu2);
2748                                         return;
2749                                 }
2750                         }
2751                 }
2752         }
2753         
2754         if( nu1->pntsv != nu2->pntsv ) {
2755                 BKE_report(op->reports, RPT_ERROR, "Resolution doesn't match");
2756                 return;
2757         }
2758         
2759         /* ok, now nu1 has the rightmost collumn and nu2 the leftmost collumn selected */
2760         /* maybe we need a 'v' flip of nu2? */
2761         
2762         bp1= nu1->bp+nu1->pntsu-1;
2763         bp2= nu2->bp;
2764         len1= 0.0;
2765         
2766         for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2+=nu2->pntsu) {
2767                 len1+= VecLenf(bp1->vec, bp2->vec);
2768         }
2769
2770         bp1= nu1->bp + nu1->pntsu-1;
2771         bp2= nu2->bp + nu2->pntsu*(nu2->pntsv-1);
2772         len2= 0.0;
2773         
2774         for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2-=nu2->pntsu) {
2775                 len2+= VecLenf(bp1->vec, bp2->vec);
2776         }
2777
2778         /* merge */
2779         origu= nu1->pntsu;
2780         nu1->pntsu+= nu2->pntsu;
2781         if(nu1->orderu<3) nu1->orderu++;
2782         if(nu1->orderv<3) nu1->orderv++;
2783         temp= nu1->bp;
2784         nu1->bp= MEM_mallocN(nu1->pntsu*nu1->pntsv*sizeof(BPoint), "mergeBP");
2785         
2786         bp= nu1->bp;
2787         bp1= temp;
2788         
2789         for(v=0; v<nu1->pntsv; v++) {
2790                 
2791                 /* switch direction? */
2792                 if(len1<len2) bp2= nu2->bp + v*nu2->pntsu;
2793                 else bp2= nu2->bp + (nu1->pntsv-v-1)*nu2->pntsu;
2794
2795                 for(u=0; u<nu1->pntsu; u++, bp++) {
2796                         if(u<origu) {
2797                                 *bp= *bp1; bp1++;
2798                                 select_bpoint(bp, SELECT, 1, HIDDEN);
2799                         }
2800                         else {
2801                                 *bp= *bp2; bp2++;
2802                         }
2803                 }
2804         }
2805
2806         if((nu1->type & 7)==CU_NURBS) {
2807                 /* merge knots */
2808                 makeknots(nu1, 1);
2809         
2810                 /* make knots, for merged curved for example */
2811                 makeknots(nu1, 2);
2812         }
2813         
2814         MEM_freeN(temp);
2815         BLI_remlink(editnurb, nu2);
2816         freeNurb(nu2);
2817 }
2818
2819 static int merge_nurb(bContext *C, wmOperator *op)
2820 {
2821         Object *obedit= CTX_data_edit_object(C);
2822         ListBase *editnurb= curve_get_editcurve(obedit);
2823         NurbSort *nus1, *nus2;
2824         int ok= 1;
2825         
2826         make_selection_list_nurb(editnurb);
2827         
2828         if(nsortbase.first == nsortbase.last) {
2829                 BLI_freelistN(&nsortbase);
2830                 BKE_report(op->reports, RPT_ERROR, "Too few selections to merge.");
2831                 return OPERATOR_CANCELLED;
2832         }
2833         
2834         nus1= nsortbase.first;
2835         nus2= nus1->next;
2836
2837         /* resolution match, to avoid uv rotations */
2838         if(nus1->nu->pntsv==1) {
2839                 if(nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsu==nus2->nu->pntsv);
2840                 else ok= 0;