4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
39 #include "MEM_guardedalloc.h"
43 #include "BLI_blenlib.h"
44 #include "BLI_arithb.h"
45 #include "BLI_dynstr.h"
48 #include "DNA_curve_types.h"
49 #include "DNA_key_types.h"
50 #include "DNA_mesh_types.h"
51 #include "DNA_object_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_screen_types.h"
54 #include "DNA_space_types.h"
55 #include "DNA_view3d_types.h"
56 #include "DNA_userdef_types.h"
58 #include "BKE_context.h"
59 #include "BKE_curve.h"
60 #include "BKE_depsgraph.h"
61 #include "BKE_fcurve.h"
63 #include "BKE_library.h"
64 #include "BKE_global.h"
66 #include "BKE_object.h"
67 #include "BKE_utildefines.h"
69 #include "ED_anim_api.h"
70 #include "ED_keyframes_edit.h"
71 #include "ED_object.h"
74 #include "ED_view3d.h"
76 /* still need to eradicate a few :( */
77 #define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name)
79 /* for curve objects in editmode that can have hidden handles */
80 #define BEZSELECTED_HIDDENHANDLES(bezt) ((G.f & G_HIDDENHANDLES) ? (bezt)->f2 & SELECT : BEZSELECTED(bezt))
83 static void BIF_undo_push() {}
84 static void waitcursor() {}
85 static void error() {}
86 static int okee() {return 0;}
87 static int pupmenu() {return 0;}
88 static int button() {return 0;}
89 static float fbutton() {return 0;}
90 static void adduplicate() {}
91 static void error_libdata() {}
94 float nurbcircle[8][2]= {
95 {0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0, 1.0},
96 {0.0, 1.0}, { 1.0, 1.0}, { 1.0, 0.0}, { 1.0, -1.0}
99 ListBase *curve_get_editcurve(Object *ob)
101 if(ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
108 /* this replaces the active flag used in uv/face mode */
109 void set_actNurb(Object *obedit, Nurb *nu)
111 Curve *cu= obedit->data;
116 cu->actnu = BLI_findindex(cu->editnurb, nu);
120 Nurb *get_actNurb(Object *obedit)
122 Curve *cu= obedit->data;
124 return BLI_findlink(cu->editnurb, cu->actnu);
128 /* ******************* SELECTION FUNCTIONS ********************* */
137 /* returns 1 in case (de)selection was successful */
138 static short select_beztriple(BezTriple *bezt, short selstatus, short flag, short hidden)
141 if((bezt->hide==0) || (hidden==1)) {
142 if(selstatus==1) { /* selects */
148 else { /* deselects */
160 /* returns 1 in case (de)selection was successful */
161 static short select_bpoint(BPoint *bp, short selstatus, short flag, short hidden)
164 if((bp->hide==0) || (hidden==1)) {
179 static short swap_selection_beztriple(BezTriple *bezt)
181 if(bezt->f2 & SELECT)
182 return select_beztriple(bezt, DESELECT, 1, VISIBLE);
184 return select_beztriple(bezt, SELECT, 1, VISIBLE);
187 static short swap_selection_bpoint(BPoint *bp)
190 return select_bpoint(bp, DESELECT, 1, VISIBLE);
192 return select_bpoint(bp, SELECT, 1, VISIBLE);
195 short isNurbsel(Nurb *nu)
201 if((nu->type & 7)==CU_BEZIER) {
205 if( (bezt->f1 & SELECT) || (bezt->f2 & SELECT) || (bezt->f3 & SELECT) ) return 1;
211 a= nu->pntsu*nu->pntsv;
213 if( (bp->f1 & SELECT) ) return 1;
220 int isNurbsel_count(Nurb *nu)
226 if((nu->type & 7)==CU_BEZIER) {
230 if (BEZSELECTED_HIDDENHANDLES(bezt)) sel++;
236 a= nu->pntsu*nu->pntsv;
238 if( (bp->f1 & SELECT) ) sel++;
245 /* ******************* PRINTS ********************* */
247 void printknots(Object *obedit)
249 ListBase *editnurb= curve_get_editcurve(obedit);
253 for(nu= editnurb->first; nu; nu= nu->next) {
254 if(isNurbsel(nu) && (nu->type & 7)==CU_NURBS) {
257 for(a=0;a<num;a++) printf("knotu %d: %f\n", a, nu->knotsu[a]);
261 for(a=0;a<num;a++) printf("knotv %d: %f\n", a, nu->knotsv[a]);
267 /* ********************* LOAD and MAKE *************** */
269 /* load editNurb in object */
270 void load_editNurb(Object *obedit)
272 ListBase *editnurb= curve_get_editcurve(obedit);
274 if(obedit==NULL) return;
276 if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
277 Curve *cu= obedit->data;
280 int totvert= count_curveverts(editnurb);
282 /* are there keys? */
283 actkey = ob_get_keyblock(obedit);
285 /* active key: the vertices */
288 if(actkey->data) MEM_freeN(actkey->data);
290 actkey->data= MEM_callocN(cu->key->elemsize*totvert, "actkey->data");
291 actkey->totelem= totvert;
293 curve_to_key(cu, actkey, editnurb);
297 if(cu->key && actkey!=cu->key->refkey) {
301 freeNurblist(&(cu->nurb));
303 for(nu= editnurb->first; nu; nu= nu->next) {
304 newnu= duplicateNurb(nu);
305 BLI_addtail(&(cu->nurb), newnu);
307 if((nu->type & 7)==CU_NURBS) {
308 clamp_nurb_order_u(nu);
314 set_actNurb(obedit, NULL);
317 /* make copy in cu->editnurb */
318 void make_editNurb(Object *obedit)
320 ListBase *editnurb= curve_get_editcurve(obedit);
324 if(obedit==NULL) return;
326 if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
327 Curve *cu= obedit->data;
330 freeNurblist(editnurb);
332 editnurb= cu->editnurb= MEM_callocN(sizeof(ListBase), "editnurb");
335 cu->lastselbp= NULL; /* for select row */
338 newnu= duplicateNurb(nu);
339 test2DNurb(newnu); // after join, or any other creation of curve
340 BLI_addtail(editnurb, newnu);
344 actkey = ob_get_keyblock(obedit);
346 // XXX strcpy(G.editModeTitleExtra, "(Key) ");
347 key_to_curve(actkey, cu, editnurb);
351 set_actNurb(obedit, NULL);
354 void remake_editNurb(Object *obedit)
357 if(okee("Reload original data")==0) return;
359 make_editNurb(obedit);
362 void free_editNurb(Object *obedit)
364 Curve *cu= obedit->data;
367 freeNurblist(cu->editnurb);
368 MEM_freeN(cu->editnurb);
373 void separate_nurb(Scene *scene)
375 Object *obedit= scene->obedit; // XXX use context
376 ListBase *editnurb= curve_get_editcurve(obedit);
377 View3D *v3d= NULL; // XXX
380 Base *base, *oldbase;
384 if( v3d==0 || (v3d->lay & obedit->lay)==0 ) return;
386 if(okee("Separate")==0) return;
392 error("Can't separate a curve with vertex keys");
396 /* we are going to trick everything as follows:
397 * 1. duplicate base: this is the new one, remember old pointer
398 * 2. set aside all NOT selected curves/nurbs
399 * 3. load_ebaseNurb(): this will be the new base
400 * 4. freelist and restore old nurbs
403 /* only edit-base selected */
406 if(base->lay & v3d->lay) {
407 if(base->object==obedit) base->flag |= 1;
408 else base->flag &= ~1;
413 /* set aside: everything that is not selected */
414 editnurbo.first= editnurbo.last= 0;
418 if(isNurbsel(nu)==0) {
419 BLI_remlink(editnurb, nu);
420 BLI_addtail(&editnurbo, nu);
428 adduplicate(1, 0); /* no transform and zero so do get a linked dupli */
430 obedit= BASACT->object; /* basact is set in adduplicate() */
432 obedit->data= copy_curve(cu);
433 /* because new curve is a copy: reduce user count */
436 load_editNurb(obedit);
438 BASACT->flag &= ~SELECT;
440 if(editnurb->first) freeNurblist(editnurb);
442 *editnurb= editnurbo;
444 obedit= 0; /* displists behave different in edit mode */
445 DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA); /* this is the separated one */
446 DAG_object_flush_update(scene, oldob, OB_RECALC_DATA); /* this is the original one */
450 BASACT->flag |= SELECT;
454 set_actNurb(obedit, NULL);
457 /* ******************* FLAGS ********************* */
460 short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
462 /* return u!=-1: 1 row in u-direction selected. U has value between 0-pntsv
463 * return v!=-1: 1 collumn in v-direction selected. V has value between 0-pntsu
471 for(b=0; b<nu->pntsv; b++) {
473 for(a=0; a<nu->pntsu; a++, bp++) {
474 if(bp->f1 & flag) sel++;
480 else if(sel>1) return 0; /* because sel==1 is still ok */
483 for(a=0; a<nu->pntsu; a++) {
486 for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
487 if(bp->f1 & flag) sel++;
493 else if(sel>1) return 0;
496 if(*u==-1 && *v>-1) return 1;
497 if(*v==-1 && *u>-1) return 1;
501 void setflagsNurb(ListBase *editnurb, short flag)
508 for(nu= editnurb->first; nu; nu= nu->next) {
509 if( (nu->type & 7)==CU_BEZIER) {
513 bezt->f1= bezt->f2= bezt->f3= flag;
518 a= nu->pntsu*nu->pntsv;
528 void rotateflagNurb(ListBase *editnurb, short flag, float *cent, float rotmat[][3])
530 /* all verts with (flag & 'flag') rotate */
535 for(nu= editnurb->first; nu; nu= nu->next) {
536 if((nu->type & 7)==CU_NURBS) {
538 a= nu->pntsu*nu->pntsv;
545 Mat3MulVecfl(rotmat, bp->vec);
557 void translateflagNurb(ListBase *editnurb, short flag, float *vec)
559 /* all verts with ('flag' & flag) translate */
565 for(nu= editnurb->first; nu; nu= nu->next) {
566 if( (nu->type & 7)==CU_BEZIER) {
570 if(bezt->f1 & flag) VecAddf(bezt->vec[0], bezt->vec[0], vec);
571 if(bezt->f2 & flag) VecAddf(bezt->vec[1], bezt->vec[1], vec);
572 if(bezt->f3 & flag) VecAddf(bezt->vec[2], bezt->vec[2], vec);
577 a= nu->pntsu*nu->pntsv;
580 if(bp->f1 & flag) VecAddf(bp->vec, bp->vec, vec);
589 void weightflagNurb(ListBase *editnurb, short flag, float w, int mode) /* mode==0: replace, mode==1: multiply */
595 for(nu= editnurb->first; nu; nu= nu->next) {
596 if((nu->type & 7)==CU_NURBS) {
597 a= nu->pntsu*nu->pntsv;
601 if(mode==1) bp->vec[3]*= w;
610 void deleteflagNurb(Scene *scene, short flag)
612 Object *obedit= scene->obedit; // XXX use context
613 Curve *cu= obedit->data;
614 ListBase *editnurb= curve_get_editcurve(obedit);
616 BPoint *bp, *bpn, *newbp;
617 int a, b, newu, newv, sel;
619 if(obedit && obedit->type==OB_SURF);
628 /* is entire nurb selected */
630 a= nu->pntsu*nu->pntsv;
638 BLI_remlink(editnurb, nu);
639 freeNurb(nu); nu=NULL;
642 /* is nurb in U direction selected */
645 for(b=0; b<nu->pntsv; b++) {
647 for(a=0; a<nu->pntsu; a++, bp++) {
648 if(bp->f1 & flag) sel++;
658 if(newv!=nu->pntsv && b==nu->pntsv) {
662 (BPoint*) MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
663 for(b=0; b<nu->pntsv; b++) {
664 if((bp->f1 & flag)==0) {
665 memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
673 clamp_nurb_order_v(nu);
675 makeknots(nu, 2, nu->flagv>>1);
678 /* is the nurb in V direction selected */
680 for(a=0; a<nu->pntsu; a++) {
683 for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
684 if(bp->f1 & flag) sel++;
694 if(newu!=nu->pntsu && a==nu->pntsu) {
698 (BPoint*) MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
699 for(b=0; b<nu->pntsv; b++) {
700 for(a=0; a<nu->pntsu; a++, bp++) {
701 if((bp->f1 & flag)==0) {
709 if(newu==1 && nu->pntsv>1) { /* make a U spline */
710 nu->pntsu= nu->pntsv;
712 SWAP(short, nu->orderu, nu->orderv);
713 clamp_nurb_order_u(nu);
714 if(nu->knotsv) MEM_freeN(nu->knotsv);
719 clamp_nurb_order_u(nu);
721 makeknots(nu, 1, nu->flagu>>1);
729 /* only for OB_SURF */
730 short extrudeflagNurb(ListBase *editnurb, int flag)
733 BPoint *bp, *bpn, *newbp;
734 int ok= 0, a, u, v, len;
751 (BPoint*)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
752 memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) );
753 bp= newbp+ nu->pntsu;
754 memcpy(bp, nu->bp, nu->pntsu*sizeof(BPoint) );
759 select_bpoint(bp, SELECT, flag, HIDDEN);
760 select_bpoint(newbp, DESELECT, flag, HIDDEN);
767 makeknots(nu, 2, nu->flagv>>1);
771 /* which row or collumn is selected */
773 if( isNurbselUV(nu, &u, &v, flag) ) {
777 a= nu->pntsu*nu->pntsv;
779 select_bpoint(bp, DESELECT, flag, HIDDEN);
783 if(u==0 || u== nu->pntsv-1) { /* row in u-direction selected */
786 (BPoint*) MEM_mallocN(nu->pntsu*(nu->pntsv + 1)
787 * sizeof(BPoint), "extrudeNurb1");
789 len= nu->pntsv*nu->pntsu;
790 memcpy(newbp+nu->pntsu, nu->bp, len*sizeof(BPoint) );
791 memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) );
795 len= nu->pntsv*nu->pntsu;
796 memcpy(newbp, nu->bp, len*sizeof(BPoint) );
797 memcpy(newbp+len, nu->bp+len-nu->pntsu, nu->pntsu*sizeof(BPoint) );
803 select_bpoint(bp, SELECT, flag, HIDDEN);
810 makeknots(nu, 2, nu->flagv>>1);
812 else if(v==0 || v== nu->pntsu-1) { /* collumn in v-direction selected */
815 (BPoint*) MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
818 for(a=0; a<nu->pntsv; a++) {
824 memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
827 if(v== nu->pntsu-1) {
837 makeknots(nu, 1, nu->flagu>>1);
847 void adduplicateflagNurb(Scene *scene, short flag)
849 Object *obedit= scene->obedit; // XXX context
850 ListBase *editnurb= curve_get_editcurve(obedit);
852 BezTriple *bezt, *bezt1;
854 int a, b, starta, enda, newu, newv;
859 if( (nu->type & 7)==CU_BEZIER) {
861 for(a=0; a<nu->pntsu; a++) {
864 while( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) {
865 select_beztriple(bezt, DESELECT, flag, HIDDEN);
867 if(a>=nu->pntsu-1) break;
872 newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN");
873 memcpy(newnu, nu, sizeof(Nurb));
874 BLI_addtail(editnurb, newnu);
875 set_actNurb(obedit, newnu);
876 newnu->pntsu= enda-starta+1;
878 (BezTriple*)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN");
879 memcpy(newnu->bezt, nu->bezt+starta, newnu->pntsu*sizeof(BezTriple));
884 select_beztriple(bezt1, SELECT, flag, HIDDEN);
888 if(nu->flagu & CU_CYCLIC) {
889 if(starta!=0 || enda!=nu->pntsu-1) {
890 newnu->flagu &= ~CU_CYCLIC;
897 else if(nu->pntsv==1) { /* because UV Nurb has a different method for dupli */
899 for(a=0; a<nu->pntsu; a++) {
902 while(bp->f1 & flag) {
903 select_bpoint(bp, DESELECT, flag, HIDDEN);
905 if(a>=nu->pntsu-1) break;
910 newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN3");
911 memcpy(newnu, nu, sizeof(Nurb));
912 set_actNurb(obedit, newnu);
913 BLI_addtail(editnurb, newnu);
914 newnu->pntsu= enda-starta+1;
915 newnu->bp = (BPoint*)MEM_mallocN((enda-starta+1) * sizeof(BPoint), "adduplicateN4");
916 memcpy(newnu->bp, nu->bp+starta, newnu->pntsu*sizeof(BPoint));
921 select_bpoint(bp1, SELECT, flag, HIDDEN);
925 if(nu->flagu & CU_CYCLIC) {
926 if(starta!=0 || enda!=nu->pntsu-1) {
927 newnu->flagu &= ~CU_CYCLIC;
933 makeknots(newnu, 1, newnu->flagu>>1);
939 /* a rectangular area in nurb has to be selected */
941 usel= MEM_callocN(nu->pntsu, "adduplicateN4");
943 for(a=0; a<nu->pntsv; a++) {
944 for(b=0; b<nu->pntsu; b++, bp++) {
945 if(bp->f1 & flag) usel[b]++;
950 for(a=0; a<nu->pntsu; a++) {
952 if(newv==0 || usel[a]==newv) {
962 if(newu==0 || newv==0) {
963 printf("Can't duplicate Nurb\n");
967 if(newu==1) SWAP(short, newu, newv);
969 newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN5");
970 memcpy(newnu, nu, sizeof(Nurb));
971 BLI_addtail(editnurb, newnu);
972 set_actNurb(obedit, newnu);
976 (BPoint*)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6");
977 clamp_nurb_order_u(newnu);
978 clamp_nurb_order_v(newnu);
980 newnu->knotsu= newnu->knotsv= NULL;
984 for(a=0; a<nu->pntsv; a++) {
985 for(b=0; b<nu->pntsu; b++, bp1++) {
987 memcpy(bp, bp1, sizeof(BPoint));
988 select_bpoint(bp1, DESELECT, flag, HIDDEN);
993 if (check_valid_nurb_u(newnu)) {
994 if(nu->pntsu==newnu->pntsu && nu->knotsu) {
995 newnu->knotsu= MEM_dupallocN( nu->knotsu );
997 makeknots(newnu, 1, newnu->flagu>>1);
1000 if (check_valid_nurb_v(newnu)) {
1001 if(nu->pntsv==newnu->pntsv && nu->knotsv) {
1002 newnu->knotsv= MEM_dupallocN( nu->knotsv );
1004 makeknots(newnu, 2, newnu->flagv>>1);
1019 void switchdirectionNurb2(Scene *scene)
1021 Object *obedit= scene->obedit; // XXX use context
1022 ListBase *editnurb= curve_get_editcurve(obedit);
1023 View3D *v3d= NULL; // XXX
1026 if(v3d==0 || !(obedit->lay & v3d->lay))
1029 for(nu= editnurb->first; nu; nu= nu->next) {
1030 if( isNurbsel(nu) ) switchdirectionNurb(nu);
1033 DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1035 BIF_undo_push("Switch direction");
1038 void switchdirection_knots(float *base, int tot)
1040 float *fp1, *fp2, *tempf;
1043 if(base==NULL || tot==0) return;
1050 while(fp1!=fp2 && a>0) {
1051 SWAP(float, *fp1, *fp2);
1056 /* and make in increasing order again */
1059 fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect");
1061 fp2[0]= fabs(fp1[1]-fp1[0]);
1072 fp1[0]= fp1[-1]+fp2[0];
1079 void setweightNurb(Scene *scene)
1081 Object *obedit= scene->obedit; // XXX context
1082 ListBase *editnurb= curve_get_editcurve(obedit);
1083 static float weight= 1.0f;
1089 if(fbutton(&weight, 0.0f, 1.0f, 10, 10, "Set Weight")) {
1090 for(nu= editnurb->first; nu; nu= nu->next) {
1092 for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1093 if(bezt->f2 & SELECT)
1094 bezt->weight= weight;
1098 for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1105 BIF_undo_push("Set Curve Weight");
1106 DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
1109 void setradiusNurb(Scene *scene)
1111 Object *obedit= scene->obedit; // XXX
1112 ListBase *editnurb= curve_get_editcurve(obedit);
1113 static float radius= 1.0f;
1119 if(fbutton(&radius, 0.0001f, 10.0f, 10, 10, "Set Radius")) {
1120 for(nu= editnurb->first; nu; nu= nu->next) {
1122 for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
1123 if(bezt->f2 & SELECT)
1124 bezt->radius= radius;
1128 for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
1135 BIF_undo_push("Set Curve Radius");
1136 DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
1139 void smoothNurb(Scene *scene)
1141 Object *obedit= scene->obedit; // XXX
1142 ListBase *editnurb= curve_get_editcurve(obedit);
1144 BezTriple *bezt, *beztOrig;
1145 BPoint *bp, *bpOrig;
1146 int a, i, change = 0;
1148 /* floats for smoothing */
1149 float val, newval, offset;
1151 for(nu= editnurb->first; nu; nu= nu->next) {
1154 beztOrig = MEM_dupallocN( nu->bezt );
1155 for(bezt=nu->bezt+1, a=1; a<nu->pntsu-1; a++, bezt++) {
1156 if(bezt->f2 & SELECT) {
1157 for(i=0; i<3; i++) {
1158 val = bezt->vec[1][i];
1159 newval = ((beztOrig+(a-1))->vec[1][i] * 0.5) + ((beztOrig+(a+1))->vec[1][i] * 0.5);
1160 offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
1161 /* offset handles */
1162 bezt->vec[1][i] += offset;
1163 bezt->vec[0][i] += offset;
1164 bezt->vec[2][i] += offset;
1169 MEM_freeN(beztOrig);
1171 calchandlesNurb(nu);
1172 } else if (nu->bp) {
1173 bpOrig = MEM_dupallocN( nu->bp );
1174 /* Same as above, keep these the same! */
1175 for(bp=nu->bp+1, a=1; a<nu->pntsu-1; a++, bp++) {
1176 if(bp->f1 & SELECT) {
1177 for(i=0; i<3; i++) {
1179 newval = ((bpOrig+(a-1))->vec[i] * 0.5) + ((bpOrig+(a+1))->vec[i] * 0.5);
1180 offset = (val*((1.0/6.0)*5)) + (newval*(1.0/6.0)) - val;
1182 bp->vec[i] += offset;
1189 BIF_undo_push("Smooth Curve");
1190 DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
1193 /* TODO, make smoothing distance based */
1194 void smoothradiusNurb(Scene *scene)
1196 Object *obedit= scene->obedit; // XXX
1197 ListBase *editnurb= curve_get_editcurve(obedit);
1203 /* use for smoothing */
1205 int start_sel, end_sel; /* selection indicies, inclusive */
1206 float start_rad, end_rad, fac, range;
1208 for(nu= editnurb->first; nu; nu= nu->next) {
1211 for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
1212 /* loop over selection segments of a curve, smooth each */
1214 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
1215 start_sel = end_sel = -1;
1216 for(bezt=nu->bezt+last_sel, a=last_sel; a<nu->pntsu; a++, bezt++) {
1217 if(bezt->f2 & SELECT) {
1222 /* incase there are no other selected verts */
1223 end_sel = start_sel;
1224 for(bezt=nu->bezt+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bezt++) {
1225 if((bezt->f2 & SELECT)==0) {
1231 if (start_sel == -1) {
1232 last_sel = nu->pntsu; /* next... */
1234 last_sel = end_sel; /* before we modify it */
1236 /* now blend between start and end sel */
1237 start_rad = end_rad = -1.0;
1239 if (start_sel == end_sel) {
1240 /* simple, only 1 point selected */
1241 if (start_sel>0) start_rad = (nu->bezt+start_sel-1)->radius;
1242 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bezt+start_sel+1)->radius;
1244 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bezt+start_sel)->radius = (start_rad + end_rad)/2;
1245 else if (start_rad >= 0.0) (nu->bezt+start_sel)->radius = start_rad;
1246 else if (end_rad >= 0.0) (nu->bezt+start_sel)->radius = end_rad;
1248 /* if endpoints selected, then use them */
1250 start_rad = (nu->bezt+start_sel)->radius;
1251 start_sel++; /* we dont want to edit the selected endpoint */
1253 start_rad = (nu->bezt+start_sel-1)->radius;
1255 if (end_sel==nu->pntsu-1) {
1256 end_rad = (nu->bezt+end_sel)->radius;
1257 end_sel--; /* we dont want to edit the selected endpoint */
1259 end_rad = (nu->bezt+end_sel+1)->radius;
1262 /* Now Blend between the points */
1263 range = (float)(end_sel - start_sel) + 2.0f;
1264 for(bezt=nu->bezt+start_sel, a=start_sel; a<=end_sel; a++, bezt++) {
1265 fac = (float)(1+a-start_sel) / range;
1266 bezt->radius = start_rad*(1.0-fac) + end_rad*fac;
1271 } else if (nu->bp) {
1272 /* Same as above, keep these the same! */
1273 for (last_sel=0; last_sel < nu->pntsu; last_sel++) {
1274 /* loop over selection segments of a curve, smooth each */
1276 /* Start BezTriple code, this is duplicated below for points, make sure these functions stay in sync */
1277 start_sel = end_sel = -1;
1278 for(bp=nu->bp+last_sel, a=last_sel; a<nu->pntsu; a++, bp++) {
1279 if(bp->f1 & SELECT) {
1284 /* incase there are no other selected verts */
1285 end_sel = start_sel;
1286 for(bp=nu->bp+(start_sel+1), a=start_sel+1; a<nu->pntsu; a++, bp++) {
1287 if((bp->f1 & SELECT)==0) {
1293 if (start_sel == -1) {
1294 last_sel = nu->pntsu; /* next... */
1296 last_sel = end_sel; /* before we modify it */
1298 /* now blend between start and end sel */
1299 start_rad = end_rad = -1.0;
1301 if (start_sel == end_sel) {
1302 /* simple, only 1 point selected */
1303 if (start_sel>0) start_rad = (nu->bp+start_sel-1)->radius;
1304 if (end_sel!=-1 && end_sel < nu->pntsu) end_rad = (nu->bp+start_sel+1)->radius;
1306 if (start_rad >= 0.0 && end_rad >= 0.0) (nu->bp+start_sel)->radius = (start_rad + end_rad)/2;
1307 else if (start_rad >= 0.0) (nu->bp+start_sel)->radius = start_rad;
1308 else if (end_rad >= 0.0) (nu->bp+start_sel)->radius = end_rad;
1310 /* if endpoints selected, then use them */
1312 start_rad = (nu->bp+start_sel)->radius;
1313 start_sel++; /* we dont want to edit the selected endpoint */
1315 start_rad = (nu->bp+start_sel-1)->radius;
1317 if (end_sel==nu->pntsu-1) {
1318 end_rad = (nu->bp+end_sel)->radius;
1319 end_sel--; /* we dont want to edit the selected endpoint */
1321 end_rad = (nu->bp+end_sel+1)->radius;
1324 /* Now Blend between the points */
1325 range = (float)(end_sel - start_sel) + 2.0f;
1326 for(bp=nu->bp+start_sel, a=start_sel; a<=end_sel; a++, bp++) {
1327 fac = (float)(1+a-start_sel) / range;
1328 bp->radius = start_rad*(1.0-fac) + end_rad*fac;
1335 BIF_undo_push("Smooth Curve Radius");
1336 DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
1341 /* **************** EDIT ************************ */
1343 /* next == 1 -> select next */
1344 /* next == -1 -> select previous */
1345 /* cont == 1 -> select continuously */
1346 /* selstatus, inverts behaviour */
1347 static void select_adjacent_cp(ListBase *editnurb, short next, short cont, short selstatus)
1353 short lastsel= 0, sel=0;
1357 for(nu= editnurb->first; nu; nu= nu->next) {
1359 if((nu->type & 7)==CU_BEZIER) {
1362 if(next < 0) bezt= (nu->bezt + (a-1));
1364 if(a-abs(next) < 0) break;
1366 if((lastsel==0) && (bezt->hide==0) && ((bezt->f2 & SELECT) || (selstatus==0))) {
1368 if(!(bezt->f2 & SELECT) || (selstatus==0)) {
1369 sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
1370 if((sel==1) && (cont==0)) lastsel= 1;
1377 /* move around in zigzag way so that we go through each */
1378 bezt-=(next-next/abs(next));
1382 a= nu->pntsu*nu->pntsv;
1384 if(next < 0) bp= (nu->bp + (a-1));
1386 if(a-abs(next) < 0) break;
1388 if((lastsel==0) && (bp->hide==0) && ((bp->f1 & SELECT) || (selstatus==0))) {
1390 if(!(bp->f1 & SELECT) || (selstatus==0)) {
1391 sel= select_bpoint(bp, selstatus, 1, VISIBLE);
1392 if((sel==1) && (cont==0)) lastsel= 1;
1399 /* move around in zigzag way so that we go through each */
1400 bp-=(next-next/abs(next));
1406 static short nurb_has_selected_cps(ListBase *editnurb)
1413 for(nu= editnurb->first; nu; nu= nu->next) {
1414 if((nu->type & 7)==CU_BEZIER) {
1419 if((bezt->f1 & SELECT)
1420 || (bezt->f2 & SELECT)
1421 || (bezt->f3 & SELECT)) return 1;
1427 a= nu->pntsu*nu->pntsv;
1430 if((bp->hide==0) && (bp->f1 & SELECT)) return 1;
1440 /* (de)selects first or last of visible part of each Nurb depending on selFirst */
1441 /* selFirst: defines the end of which to select */
1442 /* doswap: defines if selection state of each first/last control point is swapped */
1443 /* selstatus: selection status in case doswap is false */
1444 void selectend_nurb(Scene *scene, short selfirst, short doswap, short selstatus)
1446 Object *obedit= scene->obedit; // XXX use context
1447 ListBase *editnurb= curve_get_editcurve(obedit);
1454 if(obedit==0) return;
1456 for(nu= editnurb->first; nu; nu= nu->next) {
1458 if((nu->type & 7)==CU_BEZIER) {
1462 if(selfirst==0) { /* select last */
1463 bezt= (nu->bezt + (a-1));
1465 else { /* select first */
1470 if(doswap) sel= swap_selection_beztriple(bezt);
1471 else sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
1477 a= nu->pntsu*nu->pntsv;
1480 if(selfirst==0) { /* select last */
1481 bp= (nu->bp + (a-1));
1483 else{ /* select first */
1488 if (bp->hide == 0) {
1489 if(doswap) sel= swap_selection_bpoint(bp);
1490 else sel= select_bpoint(bp, selstatus, 1, VISIBLE);
1498 BIF_undo_push("Select/Deselect End");
1501 void deselectall_nurb(Scene *scene)
1503 Object *obedit= scene->obedit; // XXX use context
1504 ListBase *editnurb= curve_get_editcurve(obedit);
1505 View3D *v3d= NULL; // XXX
1507 if(!v3d || !(obedit->lay & v3d->lay))
1510 if(nurb_has_selected_cps(editnurb)) { /* deselect all */
1511 selectend_nurb(scene, FIRST, 0, DESELECT); /* set first control points as unselected */
1512 select_adjacent_cp(editnurb, 1, 1, DESELECT); /* cascade selection */
1514 else { /* select all */
1515 selectend_nurb(scene, FIRST, 0, SELECT); /* set first control points as selected */
1516 select_adjacent_cp(editnurb, 1, 1, SELECT); /* cascade selection */
1519 BIF_undo_push("Deselect all");
1522 void hideNurb(Scene *scene, int swap)
1524 Object *obedit= scene->obedit; // XXX
1525 ListBase *editnurb= curve_get_editcurve(obedit);
1531 if(obedit==0) return;
1533 BIF_undo_push("Hide");
1535 for(nu= editnurb->first; nu; nu= nu->next) {
1536 if((nu->type & 7)==CU_BEZIER) {
1541 if(BEZSELECTED_HIDDENHANDLES(bezt)) {
1542 select_beztriple(bezt, DESELECT, 1, HIDDEN);
1545 if(bezt->hide) sel++;
1548 if(sel==nu->pntsu) nu->hide= 1;
1552 a= nu->pntsu*nu->pntsv;
1555 if(swap==0 && (bp->f1 & SELECT)) {
1556 select_bpoint(bp, DESELECT, 1, HIDDEN);
1559 else if(swap && (bp->f1 & SELECT)==0) {
1560 select_bpoint(bp, DESELECT, 1, HIDDEN);
1566 if(sel==nu->pntsu*nu->pntsv) nu->hide= 1;
1570 DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1573 void revealNurb(Scene *scene)
1575 Object *obedit= scene->obedit; // XXX
1576 ListBase *editnurb= curve_get_editcurve(obedit);
1582 if(obedit==0) return;
1584 for(nu= editnurb->first; nu; nu= nu->next) {
1586 if((nu->type & 7)==CU_BEZIER) {
1591 select_beztriple(bezt, SELECT, 1, HIDDEN);
1599 a= nu->pntsu*nu->pntsv;
1602 select_bpoint(bp, SELECT, 1, HIDDEN);
1610 DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
1611 BIF_undo_push("Reveal");
1615 void selectswapNurb(Scene *scene)
1617 Object *obedit= scene->obedit; // XXX
1618 ListBase *editnurb= curve_get_editcurve(obedit);
1624 if(obedit==0) return;
1626 for(nu= editnurb->first; nu; nu= nu->next) {
1627 if((nu->type & 7)==CU_BEZIER) {
1632 bezt->f2 ^= SELECT; /* always do the center point */
1633 if ((G.f & G_HIDDENHANDLES)==0) {
1643 a= nu->pntsu*nu->pntsv;
1645 swap_selection_bpoint(bp);
1651 BIF_undo_push("Select swap");
1655 /** Divide the line segments associated with the currently selected
1656 * curve nodes (Bezier or NURB). If there are no valid segment
1657 * selections within the current selection, nothing happens.
1659 * @deffunc subdividenurb subdivideNurb(void)
1663 void subdivideNurb(Scene *scene)
1665 Object *obedit= scene->obedit; // XXX
1666 ListBase *editnurb= curve_get_editcurve(obedit);
1668 BezTriple *prevbezt, *bezt, *beztnew, *beztn;
1669 BPoint *bp, *prevbp, *bpnew, *bpn;
1671 int a, b, sel, amount, *usel, *vsel;
1673 // printf("*** subdivideNurb: entering subdivide\n");
1675 for(nu= editnurb->first; nu; nu= nu->next) {
1677 if((nu->type & 7)==CU_BEZIER) {
1679 Insert a point into a 2D Bezier curve.
1680 Endpoints are preserved. Otherwise, all selected and inserted points are
1681 newly created. Old points are discarded.
1684 if(nu->flagu & CU_CYCLIC) {
1687 prevbezt= bezt+(a-1);
1695 if( BEZSELECTED_HIDDENHANDLES(prevbezt) && BEZSELECTED_HIDDENHANDLES(bezt) ) amount++;
1703 (BezTriple*)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
1705 if(nu->flagu & CU_CYCLIC) {
1708 prevbezt= bezt+(a-1);
1716 memcpy(beztn, prevbezt, sizeof(BezTriple));
1719 if( BEZSELECTED_HIDDENHANDLES(prevbezt) && BEZSELECTED_HIDDENHANDLES(bezt) ) {
1720 memcpy(beztn, bezt, sizeof(BezTriple));
1722 /* midpoint subdividing */
1723 VecMidf(vec, prevbezt->vec[1], prevbezt->vec[2]);
1724 VecMidf(vec+3, prevbezt->vec[2], bezt->vec[0]);
1725 VecMidf(vec+6, bezt->vec[0], bezt->vec[1]);
1727 VecMidf(vec+9, vec, vec+3);
1728 VecMidf(vec+12, vec+3, vec+6);
1730 /* change handle of prev beztn */
1731 VECCOPY((beztn-1)->vec[2], vec);
1733 VECCOPY(beztn->vec[0], vec+9);
1734 VecMidf(beztn->vec[1], vec+9, vec+12);
1735 VECCOPY(beztn->vec[2], vec+12);
1736 /* handle of next bezt */
1737 if(a==0 && (nu->flagu & CU_CYCLIC)) {VECCOPY(beztnew->vec[0], vec+6);}
1738 else {VECCOPY(bezt->vec[0], vec+6);}
1740 beztn->radius = (prevbezt->radius + bezt->radius)/2.0f;
1741 beztn->weight = (prevbezt->weight + bezt->weight)/2.0f;
1750 if((nu->flagu & CU_CYCLIC)==0) memcpy(beztn, prevbezt, sizeof(BezTriple));
1752 MEM_freeN(nu->bezt);
1756 calchandlesNurb(nu);
1758 } /* End of 'if((nu->type & 7)==CU_BEZIER)' */
1759 else if (nu->pntsv==1) {
1761 All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves
1762 are handled together with the regular NURB plane division, as it
1763 should be. I split it off just now, let's see if it is
1764 stable... nzc 30-5-'00
1767 if(nu->flagu & CU_CYCLIC) {
1778 if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) amount++;
1786 (BPoint*)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
1789 if(nu->flagu & CU_CYCLIC) {
1800 memcpy(bpn, prevbp, sizeof(BPoint));
1803 if( (bp->f1 & SELECT) && (prevbp->f1 & SELECT) ) {
1804 // printf("*** subdivideNurb: insert 'linear' point\n");
1805 memcpy(bpn, bp, sizeof(BPoint));
1806 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1807 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1808 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1809 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1816 if((nu->flagu & CU_CYCLIC)==0) memcpy(bpn, prevbp, sizeof(BPoint)); /* last point */
1823 makeknots(nu, 1, nu->flagu>>1);
1826 } /* End of 'else if(nu->pntsv==1)' */
1827 else if((nu->type & 7)==CU_NURBS) {
1828 /* This is a very strange test ... */
1830 Subdivide NURB surfaces - nzc 30-5-'00 -
1832 Subdivision of a NURB curve can be effected by adding a
1833 control point (insertion of a knot), or by raising the
1834 degree of the functions used to build the NURB. The
1837 degree = #knots - #controlpoints + 1 (J Walter piece)
1838 degree = #knots - #controlpoints (Blender
1840 ( this is confusing.... what is true? Another concern
1841 is that the JW piece allows the curve to become
1842 explicitly 1st order derivative discontinuous, while
1843 this is not what we want here... )
1845 is an invariant for a single NURB curve. Raising the degree
1846 of the NURB is done elsewhere; the degree is assumed
1847 constant during this opration. Degree is a property shared
1848 by all controlpoints in a curve (even though it is stored
1849 per control point - this can be misleading).
1850 Adding a knot is done by searching for the place in the
1851 knot vector where a certain knot value must be inserted, or
1852 by picking an appropriate knot value between two existing
1853 ones. The number of controlpoints that is influenced by the
1854 insertion depends on the order of the curve. A certain
1855 minimum number of knots is needed to form high-order
1856 curves, as can be seen from the equation above. In Blender,
1857 currently NURBs may be up to 6th order, so we modify at
1858 most 6 points. One point is added. For an n-degree curve,
1859 n points are discarded, and n+1 points inserted
1860 (so effectively, n points are modified). (that holds for
1861 the JW piece, but it seems not for our NURBs)
1862 In practice, the knot spacing is copied, but the tail
1863 (the points following the insertion point) need to be
1864 offset to keep the knot series ascending. The knot series
1865 is always a series of monotonically ascending integers in
1866 Blender. When not enough control points are available to
1867 fit the order, duplicates of the endpoints are added as
1870 /* selection-arrays */
1871 usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3");
1872 vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3");
1875 /* Count the number of selected points. */
1877 for(a=0; a<nu->pntsv; a++) {
1878 for(b=0; b<nu->pntsu; b++) {
1879 if(bp->f1 & SELECT) {
1887 if( sel == (nu->pntsu*nu->pntsv) ) { /* subdivide entire nurb */
1888 /* Global subdivision is a special case of partial
1889 subdivision. Strange it is considered separately... */
1890 bpn=bpnew= MEM_mallocN( (2*nu->pntsu-1)*(2*nu->pntsv-1)*sizeof(BPoint), "subdivideNurb4");
1892 /* first subdivide rows */
1893 for(a=0; a<nu->pntsv; a++) {
1894 for(b=0; b<nu->pntsu; b++) {
1901 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1902 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1903 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1904 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1908 bpn+= (2*nu->pntsu-1);
1910 /* now insert new */
1911 bpn= bpnew+(2*nu->pntsu-1);
1912 bp= bpnew+(4*nu->pntsu-2);
1914 for(a=1; a<nu->pntsv; a++) {
1916 for(b=0; b<2*nu->pntsu-1; b++) {
1918 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1919 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1920 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1921 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1926 bp+= (2*nu->pntsu-1);
1927 bpn+= (2*nu->pntsu-1);
1928 prevbp+= (2*nu->pntsu-1);
1932 nu->pntsu= 2*nu->pntsu-1;
1933 nu->pntsv= 2*nu->pntsv-1;
1934 makeknots(nu, 1, nu->flagu>>1);
1935 makeknots(nu, 2, nu->flagv>>1);
1936 } /* End of 'if(sel== nu->pntsu*nu->pntsv)' (subdivide entire NURB) */
1938 /* subdivide in v direction? */
1940 for(a=0; a<nu->pntsv-1; a++) {
1941 if(vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu) sel++;
1945 bpn=bpnew= MEM_mallocN( (sel+nu->pntsv)*nu->pntsu*sizeof(BPoint), "subdivideNurb4");
1947 for(a=0; a<nu->pntsv; a++) {
1948 for(b=0; b<nu->pntsu; b++) {
1953 if( (a<nu->pntsv-1) && vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu ) {
1954 prevbp= bp- nu->pntsu;
1955 for(b=0; b<nu->pntsu; b++) {
1957 This simple bisection must be replaces by a
1958 subtle resampling of a number of points. Our
1959 task is made slightly easier because each
1960 point in our curve is a separate data
1964 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
1965 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
1966 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
1967 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
1978 makeknots(nu, 2, nu->flagv>>1);
1981 /* or in u direction? */
1983 for(a=0; a<nu->pntsu-1; a++) {
1984 if(usel[a]==nu->pntsv && usel[a+1]==nu->pntsv) sel++;
1988 /* Inserting U points is sort of 'default' Flat curves only get */
1989 /* U points inserted in them. */
1990 bpn=bpnew= MEM_mallocN( (sel+nu->pntsu)*nu->pntsv*sizeof(BPoint), "subdivideNurb4");
1992 for(a=0; a<nu->pntsv; a++) {
1993 for(b=0; b<nu->pntsu; b++) {
1997 if( (b<nu->pntsu-1) && usel[b]==nu->pntsv && usel[b+1]==nu->pntsv ) {
1999 One thing that bugs me here is that the
2000 orders of things are not the same as in
2001 the JW piece. Also, this implies that we
2002 handle at most 3rd order curves? I miss
2003 some symmetry here...
2007 bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
2008 bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
2009 bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
2010 bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
2018 makeknots(nu, 1, nu->flagu>>1); /* shift knots
2026 } /* End of 'if((nu->type & 7)==CU_NURBS)' */
2030 DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2032 BIF_undo_push("Subdivide");
2036 static void findnearestNurbvert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
2038 struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; short dist, hpoint, select, mval[2]; } *data = userData;
2048 } else if (beztindex==1) {
2055 temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
2056 if ((flag&1)==data->select) temp += 5;
2057 if (bezt && beztindex==1) temp += 3; /* middle points get a small disadvantage */
2059 if (temp<data->dist) {
2065 data->hpoint = bezt?beztindex:0;
2069 static short findnearestNurbvert(ViewContext *vc, short sel, short mval[2], Nurb **nurb, BezTriple **bezt, BPoint **bp)
2071 /* sel==1: selected gets a disadvantage */
2072 /* in nurb and bezt or bp the nearest is written */
2073 /* return 0 1 2: handlepunt */
2074 struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; short dist, hpoint, select, mval[2]; } data = {0};
2079 data.mval[0] = mval[0];
2080 data.mval[1] = mval[1];
2082 nurbs_foreachScreenVert(vc, findnearestNurbvert__doClosest, &data);
2092 static void findselectedNurbvert(ListBase *editnurb, Nurb **nu, BezTriple **bezt, BPoint **bp)
2094 /* in nu and (bezt or bp) selected are written if there's 1 sel. */
2095 /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
2104 for(nu1= editnurb->first; nu1; nu1= nu1->next) {
2105 if((nu1->type & 7)==CU_BEZIER) {
2109 if( (bezt1->f1 & SELECT) || (bezt1->f2 & SELECT) || (bezt1->f3 & SELECT) ) {
2110 if(*nu!=0 && *nu!= nu1) {
2116 else if(*bezt || *bp) {
2130 a= nu1->pntsu*nu1->pntsv;
2133 if(*nu!=0 && *nu!= nu1) {
2139 else if(*bezt || *bp) {
2154 int convertspline(short type, Nurb *nu)
2160 if((nu->type & 7)==0) { /* Poly */
2161 if(type==CU_BEZIER) { /* to Bezier with vecthandles */
2164 (BezTriple*)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
2169 VECCOPY(bezt->vec[1], bp->vec);
2170 bezt->f1=bezt->f2=bezt->f3= bp->f1;
2171 bezt->h1= bezt->h2= HD_VECT;
2172 bezt->weight= bp->weight;
2173 bezt->radius= bp->radius;
2182 calchandlesNurb(nu);
2184 else if(type==CU_NURBS) {
2188 nu->flagu &= CU_CYCLIC; /* disable all flags except for cyclic */
2190 makeknots(nu, 1, nu->flagu>>1);
2191 a= nu->pntsu*nu->pntsv;
2199 else if((nu->type & 7)==CU_BEZIER) { /* Bezier */
2200 if(type==0 || type==4) { /* to Poly or Nurb */
2202 nu->bp = MEM_callocN(nr * sizeof(BPoint), "setsplinetype");
2207 if(type==0 && bezt->h1==HD_VECT && bezt->h2==HD_VECT) {
2208 /* vector handle becomes 1 poly vertice */
2209 VECCOPY(bp->vec, bezt->vec[1]);
2213 bp->radius= bezt->radius;
2214 bp->weight= bezt->weight;
2219 VECCOPY(bp->vec, bezt->vec[c]);
2221 if(c==0) bp->f1= bezt->f1;
2222 else if(c==1) bp->f1= bezt->f2;
2223 else bp->f1= bezt->f3;
2224 bp->radius= bezt->radius;
2225 bp->weight= bezt->weight;
2231 MEM_freeN(nu->bezt);
2239 if(nu->flagu & CU_CYCLIC) c= nu->orderu-1;
2242 nu->flagu &= CU_CYCLIC; /* disable all flags except for cyclic */
2244 makeknots(nu, 1, nu->flagu>>1);
2248 else if( (nu->type & 7)==CU_NURBS) {
2249 if(type==0) { /* to Poly */
2251 if(nu->knotsu) MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
2253 if(nu->knotsv) MEM_freeN(nu->knotsv);
2256 else if(type==CU_BEZIER) { /* to Bezier */
2260 return 1; /* conversion impossible */
2262 bezt = MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
2267 VECCOPY(bezt->vec[0], bp->vec);
2270 VECCOPY(bezt->vec[1], bp->vec);
2273 VECCOPY(bezt->vec[2], bp->vec);
2275 bezt->radius= bp->radius;
2276 bezt->weight= bp->weight;
2282 MEM_freeN(nu->knotsu);
2293 void setsplinetype(Scene *scene, short type)
2295 Object *obedit= scene->obedit; // XXX
2296 ListBase *editnurb= curve_get_editcurve(obedit);
2299 if(type==CU_CARDINAL || type==CU_BSPLINE) {
2300 error("Not implemented yet");
2304 for(nu= editnurb->first; nu; nu= nu->next) {
2306 if (convertspline(type, nu))
2307 error("no conversion possible");
2310 BIF_undo_push("Set spline type");
2314 /* ******************** SKINNING LOFTING!!! ******************** */
2316 void rotate_direction_nurb(Nurb *nu)
2318 BPoint *bp1, *bp2, *temp;
2321 SWAP(short, nu->pntsu, nu->pntsv);
2322 SWAP(short, nu->orderu, nu->orderv);
2323 SWAP(short, nu->resolu, nu->resolv);
2324 SWAP(short, nu->flagu, nu->flagv);
2326 SWAP(float *, nu->knotsu, nu->knotsv);
2327 switchdirection_knots(nu->knotsv, KNOTSV(nu) );
2329 temp= MEM_dupallocN(nu->bp);
2331 for(v=0; v<nu->pntsv; v++) {
2332 for(u=0; u<nu->pntsu; u++, bp1++) {
2333 bp2= temp + (nu->pntsu-u-1)*(nu->pntsv) + v;
2341 int is_u_selected(Nurb *nu, int u)
2346 /* what about resolu == 2? */
2348 for(v=0; v<nu->pntsv-1; v++, bp+=nu->pntsu) {
2349 if(v) if(bp->f1 & SELECT) return 1;
2355 /* ******************************** */
2357 typedef struct NurbSort {
2358 struct NurbSort *next, *prev;
2363 static ListBase nsortbase= {0, 0};
2364 /* static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
2366 void make_selection_list_nurb(ListBase *editnurb)
2368 ListBase nbase= {0, 0};
2369 NurbSort *nus, *nustest, *headdo, *taildo;
2372 float dist, headdist, taildist;
2375 for(nu= editnurb->first; nu; nu= nu->next) {
2376 if( isNurbsel(nu) ) {
2378 nus = (NurbSort*)MEM_callocN(sizeof(NurbSort), "sort");
2379 BLI_addhead(&nbase, nus);
2385 VecAddf(nus->vec, nus->vec, bp->vec);
2388 VecMulf(nus->vec, 1.0/(float)nu->pntsu);
2394 /* just add the first one */
2396 BLI_remlink(&nbase, nus);
2397 BLI_addtail( &nsortbase, nus);
2399 /* now add, either at head or tail, the closest one */
2400 while(nbase.first) {
2402 headdist= taildist= 1.0e30;
2405 nustest= nbase.first;
2407 dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.first)->vec);
2413 dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.last)->vec);
2419 nustest= nustest->next;
2422 if(headdist<taildist) {
2423 BLI_remlink(&nbase, headdo);
2424 BLI_addhead(&nsortbase, headdo);
2427 BLI_remlink(&nbase, taildo);
2428 BLI_addtail(&nsortbase, taildo);
2433 void merge_2_nurb(ListBase *editnurb, Nurb *nu1, Nurb *nu2)
2435 BPoint *bp, *bp1, *bp2, *temp;
2439 /* first nurbs will be changed to make u = resolu-1 selected */
2440 /* 2nd nurbs will be changed to make u = 0 selected */
2442 /* first nurbs: u = resolu-1 selected */
2444 if( is_u_selected(nu1, nu1->pntsu-1) );
2446 rotate_direction_nurb(nu1);
2447 if( is_u_selected(nu1, nu1->pntsu-1) );
2449 rotate_direction_nurb(nu1);
2450 if( is_u_selected(nu1, nu1->pntsu-1) );
2452 rotate_direction_nurb(nu1);
2453 if( is_u_selected(nu1, nu1->pntsu-1) );
2455 /* rotate again, now its OK! */
2456 if(nu1->pntsv!=1) rotate_direction_nurb(nu1);
2463 /* 2nd nurbs: u = 0 selected */
2464 if( is_u_selected(nu2, 0) );
2466 rotate_direction_nurb(nu2);
2467 if( is_u_selected(nu2, 0) );
2469 rotate_direction_nurb(nu2);
2470 if( is_u_selected(nu2, 0) );
2472 rotate_direction_nurb(nu2);
2473 if( is_u_selected(nu2, 0) );
2475 /* rotate again, now its OK! */
2476 if(nu1->pntsu==1) rotate_direction_nurb(nu1);
2477 if(nu2->pntsv!=1) rotate_direction_nurb(nu2);
2484 if( nu1->pntsv != nu2->pntsv ) {
2485 error("Resolution doesn't match");
2489 /* ok, now nu1 has the rightmost collumn and nu2 the leftmost collumn selected */
2490 /* maybe we need a 'v' flip of nu2? */
2492 bp1= nu1->bp+nu1->pntsu-1;
2496 for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2+=nu2->pntsu) {
2497 len1+= VecLenf(bp1->vec, bp2->vec);
2500 bp1= nu1->bp + nu1->pntsu-1;
2501 bp2= nu2->bp + nu2->pntsu*(nu2->pntsv-1);
2504 for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2-=nu2->pntsu) {
2505 len2+= VecLenf(bp1->vec, bp2->vec);
2510 nu1->pntsu+= nu2->pntsu;
2511 if(nu1->orderu<3) nu1->orderu++;
2512 if(nu1->orderv<3) nu1->orderv++;
2514 nu1->bp= MEM_mallocN(nu1->pntsu*nu1->pntsv*sizeof(BPoint), "mergeBP");
2519 for(v=0; v<nu1->pntsv; v++) {
2521 /* switch direction? */
2522 if(len1<len2) bp2= nu2->bp + v*nu2->pntsu;
2523 else bp2= nu2->bp + (nu1->pntsv-v-1)*nu2->pntsu;
2525 for(u=0; u<nu1->pntsu; u++, bp++) {
2528 select_bpoint(bp, SELECT, 1, HIDDEN);
2536 if((nu1->type & 7)==4) {
2538 makeknots(nu1, 1, nu1->flagu>>1);
2540 /* make knots, for merged curved for example */
2541 makeknots(nu1, 2, nu1->flagv>>1);
2545 BLI_remlink(editnurb, nu2);
2549 void merge_nurb(Scene *scene)
2551 Object *obedit= scene->obedit; // XXX use context
2552 ListBase *editnurb= curve_get_editcurve(obedit);
2553 NurbSort *nus1, *nus2;
2556 make_selection_list_nurb(editnurb);
2558 if(nsortbase.first == nsortbase.last) {
2559 BLI_freelistN(&nsortbase);
2560 error("Too few selections to merge");
2564 nus1= nsortbase.first;
2567 /* resolution match, to avoid uv rotations */
2568 if(nus1->nu->pntsv==1) {
2569 if(nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsu==nus2->nu->pntsv);
2572 else if(nus2->nu->pntsv==1) {
2573 if(nus2->nu->pntsu==nus1->nu->pntsu || nus2->nu->pntsu==nus1->nu->pntsv);
2576 else if( nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsv==nus2->nu->pntsv);
2577 else if( nus1->nu->pntsu==nus2->nu->pntsv || nus1->nu->pntsv==nus2->nu->pntsu);
2583 error("Resolution doesn't match");
2584 BLI_freelistN(&nsortbase);
2589 merge_2_nurb(editnurb, nus1->nu, nus2->nu);
2593 BLI_freelistN(&nsortbase);
2595 set_actNurb(obedit, NULL);
2597 DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
2599 BIF_undo_push("Merge");
2604 void addsegment_nurb(Scene *scene)
2606 /* joins 2 curves */
2607 Object *obedit= scene->obedit; // XXX
2608 ListBase *editnurb= curve_get_editcurve(obedit);
2609 Nurb *nu, *nu1=0, *nu2=0;
2615 /* first decide if this is a surface merge! */
2616 if(obedit->type==OB_SURF) nu= editnurb->first;
2620 if( isNurbsel(nu) ) {
2622 if(nu->pntsu>1 && nu->pntsv>1) break;
2623 if(isNurbsel_count(nu)>1) break;
2624 if(isNurbsel_count(nu)==1) {
2625 /* only 1 selected, not first or last, a little complex, but intuitive */
2627 if( (nu->bp->f1 & SELECT) || ((nu->bp+nu->pntsu-1)->f1 & SELECT));
2639 /* find both nurbs and points, nu1 will be put behind nu2 */
2640 for(nu= editnurb->first; nu; nu= nu->next) {
2641 if((nu->flagu & CU_CYCLIC)==0) { /* not cyclic */
2642 if( (nu->type & 7)==CU_BEZIER ) {
2645 if( BEZSELECTED_HIDDENHANDLES(bezt) ) nu1= nu;
2647 bezt= bezt+(nu->pntsu-1);
2648 if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
2650 switchdirectionNurb(nu);
2655 if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
2657 switchdirectionNurb(nu);
2660 bezt= bezt+(nu->pntsu-1);
2661 if( BEZSELECTED_HIDDENHANDLES(bezt) ) {
2668 else if(nu->pntsv==1) {
2671 if( bp->f1 & SELECT) nu1= nu;
2673 bp= bp+(nu->pntsu-1);
2674 if( bp->f1 & SELECT ) {
2676 switchdirectionNurb(nu);
2681 if( bp->f1 & SELECT ) {
2683 switchdirectionNurb(nu);
2686 bp= bp+(nu->pntsu-1);
2687 if( bp->f1 & SELECT ) {
2697 if((nu1 && nu2) && (nu1!=nu2)) {
2698 if( nu1->type==nu2->type) {
2699 if((nu1->type & 7)==CU_BEZIER) {
2701 (BezTriple*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BezTriple), "addsegmentN");
2702 memcpy(bezt, nu2->bezt, nu2->pntsu*sizeof(BezTriple));
2703 memcpy(bezt+nu2->pntsu, nu1->bezt, nu1->pntsu*sizeof(BezTriple));
2704 MEM_freeN(nu1->bezt);
2706 nu1->pntsu+= nu2->pntsu;
2707 BLI_remlink(editnurb, nu2);