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