home *** CD-ROM | disk | FTP | other *** search
- /*
- Pencil V1.0, Copyright 1994, 95 by Florian Marquardt.
- This program may be distributed under the terms of the GNU general
- public license (Start Pencil and select "Info>COPYING..." for a copy of the
- license).
- */
- #import "PencilGraphic.h"
- #import "PencilView.h"
- #import <math.h>
-
- #define ADJUST [view convertPoint:&te->location fromView:nil]
- #define EX te->location.x
- #define EY te->location.y
-
- #define M_180_PI 180.0/M_PI
-
- extern float athresh, sumthresh;
- extern float *fpts;
- extern int maxfpts;
-
- extern NXStream *result;
-
- extern double fabs(double x);
-
- BOOL globalOutlines=NO;
-
- float angle(float x1,float y1,float x2,float y2)
- {
- return atan2(-y1*x2+x1*y2,x1*x2+y1*y2);
- }
-
- void expandRect (NXRect *re, float x, float y)
- {
- if(x<re->origin.x) { re->size.width+=re->origin.x-x; re->origin.x=x; }
- if(x>re->origin.x+re->size.width) { re->size.width=x-re->origin.x; }
- if(y<re->origin.y) { re->size.height+=re->origin.y-y; re->origin.y=y; }
- if(y>re->origin.y+re->size.height) { re->size.height=y-re->origin.y; }
- }
-
- #define TRANSFORMX(a,b) (tx+sx*cos(phi)*(a)-sy*sin(phi)*(b))
- #define TRANSFORMY(a,b) (ty+sx*sin(phi)*(a)+sy*cos(phi)*(b))
-
-
- void read_brace_string(NXStream *stream, char *to)
- {
- int open=0;
- char a;
- int shouldLoop=1;
-
- *to=0;
-
- NXScanf(stream, " %*[^{]{");
- do {
- NXScanf(stream, "%[^{}]", to);
- to+=strlen(to);
- if((a=NXGetc(stream))=='{') {
- ++open; *(to++)='{';
- } else {
- if(a=='}') {
- --open;
- if(open<0) shouldLoop=0; else *(to++)='}';
- }
- else
- if(a<=0) shouldLoop=0;
- }
- } while(shouldLoop);
- }
-
- @implementation PencilGraphic
- + initialize
- {
- [self setVersion:1];
- return self;
- }
-
- - (void)transformPoint:(NXPoint *)pt
- {
- float xh, yh;
-
- if(transformed)
- {
- xh=pt->x-tx;
- yh=pt->y-ty;
- pt->x=(xh*cos(phi)+yh*sin(phi))/sx;
- pt->y=(-xh*sin(phi)+yh*cos(phi))/sy;
- }
- }
-
- - (void)rotateAroundCenter:(float)x:(float)y fromPoint:(NXPoint *)pt1 toPoint:(NXPoint *)pt2
- {
- float dphi, dx, dy;
-
- dphi=angle(pt1->x-x,pt1->y-y,pt2->x-x,pt2->y-y);
- phi+=dphi;
- dx=tx-x;
- dy=ty-y;
- tx=x+cos(dphi)*dx-sin(dphi)*dy;
- ty=y+sin(dphi)*dx+cos(dphi)*dy;
- if(fabs(phi)<=1e-6) { phi=0; rotated=NO; } else { rotated=YES; }
- if(hypot(tx,ty)<=1e-6) { tx=ty=0; translated=NO; } else { translated=YES; }
- transformed=(translated || scaled || rotated) ? YES:NO;
- }
-
- - (void)scaleCenter:(float)cx:(float)cy by:(float)scx:(float)scy
- {
- NXPoint c;
-
- c.x=cx;
- c.y=cy;
- [self transformPoint:&c];
- tx=TRANSFORMX(c.x*(1-scx),c.y*(1-scy));
- ty=TRANSFORMY(c.x*(1-scx),c.y*(1-scy));
- sx*=scx;
- sy*=scy;
- if(fabs(sx-1.0)+fabs(sy-1.0)<1e-6) { sx=sy=1; scaled=NO; } else { scaled=YES; }
- if(hypot(tx,ty)<=1e-6) { tx=ty=0; translated=NO; } else { translated=YES; }
- transformed=(translated || scaled || rotated) ? YES:NO;
- }
-
- - (BOOL)selected:(NXEvent *)te:(int *)cp:(id)view
- {
- int val;
- NXPoint pt;
-
- pt=te->location;
- [view lockFocus];
- [self transformPoint:&pt];
- if(data) DPSPrintf(DPSGetCurrentContext()," /udt { %s } def ", data); else DPSPrintf(DPSGetCurrentContext()," /udt {} def ");
- DPSPrintf(DPSGetCurrentContext(), " /ctrl ");
- if(controlpts) PSsendfloatarray(controlpts, 2*ncontrolpts); else DPSPrintf(DPSGetCurrentContext(), "[ ]");
- DPSPrintf(DPSGetCurrentContext()," def /nctrl %d def /mmx %g def /mmy %g def /cp { %s } def /linw %g def %sSel\n", ncontrolpts, pt.x, pt.y, methodname, linewidth, drawingmethod);
- PSgetboolean(&val);
- [view unlockFocus];
- return val;
- }
-
- - (BOOL)move:(NXEvent *)tte:(int *)cp:(id)view:(float)bsize
- {
- int oldMask;
- BOOL shouldLoop=YES;
- int val;
- NXEvent *te;
- NXEvent mte;
-
- mte=*tte;
- te=&mte;
- [view lockFocus];
- [self transformPoint:&te->location];
- DPSPrintf(DPSGetCurrentContext(), " /ctrl ");
- if(controlpts) PSsendfloatarray(controlpts, 2*ncontrolpts); else DPSPrintf(DPSGetCurrentContext(), "[ ]");
- DPSPrintf(DPSGetCurrentContext()," def /nctrl %d def /mmx %g def /mmy %g def genselpt\n", ncontrolpts, EX, EY);
- PSgetint(&val);
-
- if(val>=0)
- {
- float dx, dy;
- NXEvent thisEvent;
-
- *cp=val;
- oldMask = [[view window] addToEventMask:NX_LMOUSEDRAGGEDMASK];
-
- PSsetinstance(YES);
- dx=controlpts[2**cp]-EX;
- dy=controlpts[2**cp+1]-EY;
- while (shouldLoop) {
- do {
- te = [NXApp getNextEvent:(NX_LMOUSEUPMASK |
- NX_LMOUSEDRAGGEDMASK)];
- } while(te->type==NX_LMOUSEDRAGGED && ([NXApp peekNextEvent:NX_LMOUSEDRAGGEDMASK into:&thisEvent]));
-
- ADJUST;
- if(te->type==NX_LMOUSEUP)
- shouldLoop=NO;
- else {
- [self transformPoint:&te->location];
- controlpts[2**cp]=EX+dx;
- controlpts[2**cp+1]=EY+dy;
- PSnewinstance();
- [self drawControl:NULL:*cp:bsize];
- PSflushgraphics();
- NXPing();
- }
- }
- PSsetinstance(NO);
- [view unlockFocus];
- [[view window] setEventMask:oldMask];
-
- return YES;
- }
- else
- {
- [view unlockFocus];
- return NO;
- }
- }
-
- - create:(NXEvent *)tte:(int *)cp:(id)view:(float)bsize;
- {
- int oldMask;
- BOOL shouldLoop=YES;
- NXEvent *te;
- NXEvent mte;
- NXEvent thisEvent;
-
- mte=*tte;
- te=&mte;
-
- oldMask = [[view window] addToEventMask:NX_LMOUSEDRAGGEDMASK | NX_RMOUSEDOWNMASK];
-
- ADJUST;
- controlpts=(float *)malloc(sizeof(float)*2);
- controlpts[0]=EX; controlpts[1]=EY;
- ncontrolpts=1;
- [view lockFocus];
- PSsetinstance(YES);
- [self drawControl:NULL:0:bsize];
- PSflushgraphics();
- while (shouldLoop) {
- do {
- te = [NXApp getNextEvent:(NX_LMOUSEUPMASK |
- NX_LMOUSEDRAGGEDMASK | NX_RMOUSEDOWNMASK | NX_LMOUSEDOWNMASK)];
- } while(te->type==NX_LMOUSEDRAGGED && ([NXApp peekNextEvent:NX_LMOUSEDRAGGEDMASK into:&thisEvent]));
-
-
- switch (te->type) {
- case NX_LMOUSEUP:
- break;
- case NX_LMOUSEDRAGGED:
- ADJUST;
- controlpts[2*(ncontrolpts-1)]=EX;
- controlpts[2*(ncontrolpts-1)+1]=EY;
- PSnewinstance();
- [self drawControl:NULL:ncontrolpts-1:bsize];
- PSflushgraphics();
- NXPing();
- break;
- case NX_LMOUSEDOWN:
- ADJUST;
- ncontrolpts++;
- controlpts=(float *)realloc(controlpts, sizeof(float)*2*ncontrolpts);
- controlpts[2*(ncontrolpts-1)]=EX;
- controlpts[2*(ncontrolpts-1)+1]=EY;
- PSnewinstance();
- [self drawControl:NULL:ncontrolpts-1:bsize];
- PSflushgraphics();
- NXPing();
- break;
- case NX_RMOUSEDOWN:
- shouldLoop=NO;
- *cp=ncontrolpts-1;
- break;
- default:
- break;
- }
-
- }
- PSsetinstance(NO);
- [view unlockFocus];
- [[view window] setEventMask:oldMask];
- return self;
- }
-
- #define PX(i) fpts[(i)*2]
- #define PY(i) fpts[(i)*2+1]
- #define NLINMAX 1000
-
- - createPolyFreehand:(NXEvent *)tte:(int *)cp:(id)view:(float)bsize
- {
- int oldMask;
- BOOL shouldLoop=YES;
- NXEvent *te;
- NXEvent mte;
- int n=1, nlin=0, i0=0, i, j;
- float ax, ay, ttx, tty, tl, sum, amax, dx, dy, val;
-
- mte=*tte;
- te=&mte;
-
- oldMask = [[view window] addToEventMask:NX_LMOUSEDRAGGEDMASK];
-
- ADJUST;
-
- controlpts=(float *)malloc(sizeof(float)*2);
- controlpts[0]=EX; controlpts[1]=EY;
- ncontrolpts=1;
- [view lockFocus];
- PSnewinstance();
- PSsetinstance(YES);
- PSsetgray(0);
- PSrectfill(EX,EY,1,1);
- PSflushgraphics();
- PX(0)=EX; PY(0)=EY;
- while (shouldLoop) {
- te = [NXApp getNextEvent:(NX_LMOUSEUPMASK |
- NX_LMOUSEDRAGGEDMASK)];
-
- ADJUST;
- PSrectfill(EX,EY,1,1);
- PSflushgraphics();
- if(n>=maxfpts) { fpts=(float *)realloc(fpts, sizeof(float)*2*(maxfpts*=2)); }
- PX(n)=EX; PY(n)=EY; ++n;
- if(te->type==NX_LMOUSEUP)
- shouldLoop=NO;
- }
- PSsetinstance(NO);
- [view unlockFocus];
- [[view window] setEventMask:oldMask];
-
- controlpts=(float *)malloc(sizeof(float)*2);
- controlpts[0]=PX(0); controlpts[1]=PY(0);
- ncontrolpts=1;
-
- --n;
-
- while(++nlin<=NLINMAX && i0<n-1)
- {
- ax=PX(i0);
- ay=PY(i0);
-
- for(i=i0+2;i<=n;i++) {
- ttx=PX(i)-ax;
- tty=PY(i)-ay;
- tl=hypot(ttx,tty);
- ttx/=tl;
- tty/=tl;
- sum=0;
- amax=0;
- for(j=i0+1;j<=i-1;j++) {
- dx=PX(j)-ax;
- dy=PY(j)-ay;
- val=ttx*dy-tty*dx;
- sum+=val;
- val=fabs(val);
- if(val>amax) amax=val;
- }
- if(amax>athresh && fabs(sum/(i-i0-1))>sumthresh) break;
- }
- if(i0<i-1) i0=i-1; else i0=i;
- if(i0>n) i0=n;
- ncontrolpts++;
- controlpts=(float *)realloc(controlpts, sizeof(float)*2*ncontrolpts);
- controlpts[2*(ncontrolpts-1)]=PX(i0);
- controlpts[2*ncontrolpts-1]=PY(i0);
- }
- [view lockFocus];
- PSsetinstance(YES);
- PSnewinstance();
- [self drawControl:NULL:ncontrolpts-1:bsize];
- PSsetinstance(NO);
- PSflushgraphics();
- [view unlockFocus];
- *cp=ncontrolpts-1;
- return self;
- }
-
- - (void)drawPath
- {
- DPSPrintf(DPSGetCurrentContext()," matrix currentmatrix ");
- if(translated) PStranslate(tx,ty);
- if(rotated) PSrotate(M_180_PI*phi);
- if(scaled) PSscale(sx,sy);
- if(data) DPSPrintf(DPSGetCurrentContext()," /udt { %s } def ", data); else DPSPrintf(DPSGetCurrentContext()," /udt {} def ");
- DPSPrintf(DPSGetCurrentContext(), " /ctrl ");
- if(controlpts) PSsendfloatarray(controlpts, 2*ncontrolpts); else DPSPrintf(DPSGetCurrentContext(), "[ ]");
- DPSPrintf(DPSGetCurrentContext()," def /nctrl %d def %s setmatrix\n", ncontrolpts, methodname);
- }
-
- - (void)draw:(NXRect *)re
- {
- if(!re || NXIntersectsRect(&bounds, re))
- {
- if(globalOutlines)
- {
- PSgsave();
- if(translated) PStranslate(tx,ty);
- if(rotated) PSrotate(M_180_PI*phi);
- if(scaled) PSscale(sx,sy);
- if(data) DPSPrintf(DPSGetCurrentContext()," /udt { %s } def ", data); else DPSPrintf(DPSGetCurrentContext()," /udt {} def ");
- DPSPrintf(DPSGetCurrentContext(), " /ctrl ");
- if(controlpts) PSsendfloatarray(controlpts, 2*ncontrolpts); else DPSPrintf(DPSGetCurrentContext(), "[ ]");
- DPSPrintf(DPSGetCurrentContext()," def 0 setlinewidth 0 setgray /nctrl %d def %s stroke\n", ncontrolpts, methodname);
- PSgrestore();
- }
- else
- {
- if(transformed)
- {
- PSgsave();
- if(translated) PStranslate(tx,ty);
- if(rotated) PSrotate(M_180_PI*phi);
- if(scaled) PSscale(sx,sy);
- if(data) DPSPrintf(DPSGetCurrentContext()," /udt { %s } def ", data); else DPSPrintf(DPSGetCurrentContext()," /udt {} def ");
- DPSPrintf(DPSGetCurrentContext(), " /ctrl ");
- if(controlpts) PSsendfloatarray(controlpts, 2*ncontrolpts); else DPSPrintf(DPSGetCurrentContext(), "[ ]");
- DPSPrintf(DPSGetCurrentContext()," def /cl { %g %g %g %g %g %g } def %g setlinewidth /nctrl %d def /cfl { %s } def /cst { %s } def /cp { %s } def %s\n", c1[0], c1[1], c1[2], c2[0], c2[1], c2[2], linewidth, ncontrolpts, fillmethod, strokemethod, methodname, drawingmethod);
- PSgrestore();
- }
- else
- {
- if(data) DPSPrintf(DPSGetCurrentContext()," /udt { %s } def ", data); else DPSPrintf(DPSGetCurrentContext()," /udt {} def ");
- DPSPrintf(DPSGetCurrentContext(), " /ctrl ");
- if(controlpts) PSsendfloatarray(controlpts, 2*ncontrolpts); else DPSPrintf(DPSGetCurrentContext(), "[ ]");
- DPSPrintf(DPSGetCurrentContext()," def /cl { %g %g %g %g %g %g } def %g setlinewidth /nctrl %d def /cfl { %s } def /cst { %s } def /cp { %s } def %s\n", c1[0], c1[1], c1[2], c2[0], c2[1], c2[2], linewidth, ncontrolpts, fillmethod, strokemethod, methodname, drawingmethod);
- }
- }
- }
- }
-
- - calculateBoundingBox:(id)view
- {
- float llx, lly, urx, ury;
-
- if(view) [view lockFocus];
- PSgsave();
- if(data) DPSPrintf(DPSGetCurrentContext()," /udt { %s } def ", data); else DPSPrintf(DPSGetCurrentContext()," /udt {} def ");
- DPSPrintf(DPSGetCurrentContext(), " /ctrl ");
- if(controlpts) PSsendfloatarray(controlpts, 2*ncontrolpts); else DPSPrintf(DPSGetCurrentContext(), "[ ]");
- DPSPrintf(DPSGetCurrentContext()," def /cl { %g %g %g %g %g %g } def /linw %g def /nctrl %d def /cfl { %s } def /cst { %s } def /cp { %s } def %sBB\n", c1[0], c1[1], c1[2], c2[0], c2[1], c2[2], linewidth, ncontrolpts, fillmethod, strokemethod, methodname, drawingmethod);
- PSgetfloat(&ury);
- PSgetfloat(&urx);
- PSgetfloat(&lly);
- PSgetfloat(&llx);
- PSgrestore();
- if(view) [view unlockFocus];
- bounds.origin.x=TRANSFORMX(llx,lly);
- bounds.origin.y=TRANSFORMY(llx,lly);
- bounds.size.width=bounds.size.height=0;
- expandRect(&bounds, TRANSFORMX(llx,ury),TRANSFORMY(llx,ury));
- expandRect(&bounds, TRANSFORMX(urx,ury), TRANSFORMY(urx,ury));
- expandRect(&bounds, TRANSFORMX(urx,lly),TRANSFORMY(urx,lly));
- return self;
- }
-
- - giveBounds:(NXRect *)bnd
- {
- *bnd=bounds;
- return self;
- }
-
- - (void)drawControl:(NXRect *)re:(int)cp:(float)bsize
- {
- [self draw:re];
- if(transformed) { PSgsave();
- if(translated) PStranslate(tx,ty);
- if(rotated) PSrotate(M_180_PI*phi);
- if(scaled) PSscale(sx,sy);
- }
- bsize/=sx;
- DPSPrintf(DPSGetCurrentContext()," /bsz %g def /bszh %g def /cctrl %d def %scontrol\n", bsize, bsize/2, cp, methodname);
- if(transformed) PSgrestore();
- }
-
- - initWithSettings:(char *)name:(NXColor)co1:(NXColor)co2:(float)lw:(char *)dm:(char *)fm:(char *)sm:(char *)ud
- {
- [self setMethodname:name];
- [self setColor1:co1];
- [self setColor2:co2];
- [self setLineWidth:lw];
- [self setDrawingMethod:dm];
- [self setFillMethod:fm];
- [self setStrokeMethod:sm];
- [self setSpecialAttributes:ud];
- ncontrolpts=0;
- sx=sy=1;
- transformed=NO;
- return self;
- }
-
- // to be called for convertRTFtoCharPath:
- - initWithControlPt: (float)x:(float)y
- {
- ncontrolpts=1;
- if(controlpts) free(controlpts);
- controlpts=(float *)malloc(sizeof(float)*2);
- controlpts[0]=x;
- controlpts[1]=y;
- sx=sy=1;
- transformed=NO;
- return self;
- }
-
- - giveSettings:(char **)name:(NXColor *)co1:(NXColor *)co2:(float *)lw:(char **)dmeth:(char **)fillmeth:(char **)strokemeth:(char **)ud
- {
- *name=methodname;
- *co1=NXConvertRGBToColor(c1[0],c1[1],c1[2]);
- *co2=NXConvertRGBToColor(c2[0],c2[1],c2[2]);
- *lw=linewidth;
- *dmeth=drawingmethod; *strokemeth=strokemethod; *fillmeth=fillmethod; *ud=data; return self;
- }
- - setMethodname:(char*)name { if(methodname) free(methodname); methodname=(char *)malloc(sizeof(char)*(strlen(name)+1)); strcpy(methodname, name); return self; }
- - setDrawingMethod:(char *)name { if(drawingmethod) free(drawingmethod); drawingmethod=(char *)malloc(sizeof(char)*(strlen(name)+1)); strcpy(drawingmethod, name); return self; }
- - setStrokeMethod:(char *)name { if(strokemethod) free(strokemethod); strokemethod=(char *)malloc(sizeof(char)*(strlen(name)+1)); strcpy(strokemethod, name); return self; }
- - setSpecialAttributes:(char *)name { if(data) free(data); data=(char *)malloc(sizeof(char)*(strlen(name)+1)); strcpy(data, name); return self; }
- - setFillMethod:(char *)name { if(fillmethod) free(fillmethod); fillmethod=(char *)malloc(sizeof(char)*(strlen(name)+1)); strcpy(fillmethod, name); return self; }
-
- - setColor1:(NXColor)col { NXConvertColorToRGB(col, &c1[0], &c1[1], &c1[2]); return self; }
- - setColor2:(NXColor)col { NXConvertColorToRGB(col, &c2[0], &c2[1], &c2[2]); return self; }
- - setLineWidth:(float)lw { linewidth=lw; return self; }
- - addTranslation:(float)dtx:(float)dty
- {
- tx+=dtx; ty+=dty;
- if(pow(tx,2)+pow(ty,2)<=1e-6) { tx=ty=0; translated=NO; }
- else translated=YES;
- transformed=(translated || scaled || rotated) ? YES:NO;
- return self;
- }
-
- - centerAt:(NXPoint *)c
- {
- return [self addTranslation:(c->x-bounds.origin.x-bounds.size.width/2):(c->y-bounds.origin.y-bounds.size.height/2)];
- }
-
- - free
- {
- if(controlpts) free(controlpts);
- return [super free];
- }
-
- #define X(a) controlpts[(a)*2]
- #define Y(a) controlpts[(a)*2+1]
-
- - insertNextPoint:(int *)cp
- {
- if(controlpts)
- {
- if(*cp>=0 && *cp<ncontrolpts)
- {
- int i;
-
- controlpts=(float *)realloc(controlpts, sizeof(float)*(ncontrolpts+=2)*2);
- for(i=ncontrolpts-1;i>*cp+1;i--) { X(i)=X(i-2); Y(i)=Y(i-2); }
- *cp+=2;
- if(*cp<ncontrolpts-3)
- { X(*cp)=(X(*cp-2)+X(*cp+2))/2; Y(*cp)=(Y(*cp+2)+Y(*cp-2))/2;
- X(*cp+1)=(X(*cp-1)+X(*cp+3))/2; Y(*cp+1)=(Y(*cp-1)+Y(*cp+3))/2; }
- else
- {
- X(*cp)=(X(*cp-2)+X(0))/2; Y(*cp)=(Y(0)+Y(*cp-2))/2;
- X(*cp+1)=(X(*cp-1)+X(1))/2; Y(*cp+1)=(Y(*cp-1)+Y(1))/2;
- }
- }
- }
- return self;
- }
-
- - insertPoint:(int *)cp
- {
- if(controlpts)
- {
- if(*cp>=0 && *cp<ncontrolpts)
- {
- int i;
-
- controlpts=(float *)realloc(controlpts, sizeof(float)*(++ncontrolpts)*2);
- for(i=ncontrolpts-1;i>*cp;i--) { X(i)=X(i-1); Y(i)=Y(i-1); }
- ++*cp;
- if(*cp<ncontrolpts-1)
- { X(*cp)=(X(*cp-1)+X(*cp+1))/2; Y(*cp)=(Y(*cp+1)+Y(*cp-1))/2; }
- else
- { X(*cp)=(X(*cp-1)+X(0))/2; Y(*cp)=(Y(*cp-1)+Y(0))/2; }
- }
- }
- return self;
- }
-
- - deletePoint:(int *)cp
- {
- if(controlpts)
- {
- if(*cp>=0 && *cp<ncontrolpts && ncontrolpts>0)
- {
- int i;
-
- if(ncontrolpts>1)
- {
- for(i=*cp;i<ncontrolpts-1;i++) { X(i)=X(i+1); Y(i)=Y(i+1); }
- controlpts=(float *)realloc(controlpts, sizeof(float)*(--ncontrolpts)*2);
- }
- else
- { return self; }
- --*cp;
- if(*cp<0) *cp=0;
- }
- }
- return self;
- }
-
- // by Ralf Suckow for Bezier curves
- // added to Pencil: 26_10_94
-
- - insertThreePoints:(int *)cp
- {
- if(controlpts)
- {
- if(*cp>=0 && *cp<ncontrolpts)
- {
- int i;
-
- // go to a point on the path
-
- if (*cp % 3 == 1)
- (*cp)--;
- else if (*cp % 3 == 2)
- (*cp)++;
-
- if (*cp == ncontrolpts)
- *cp = 0;
-
- ncontrolpts += 3;
- controlpts = (float *) realloc (controlpts, sizeof (float) * (ncontrolpts) * 2);
- for (i = ncontrolpts - 1; i > *cp + 1; i--) {
- X (i) = X (i-3);
- Y (i) = Y (i-3);
- }
-
- *cp += 3; // *cp is now the new point on the path,
- // *cp - 1 and *cp + 1 are the rulers
-
- if ( *cp < ncontrolpts - 3) {
-
- X (*cp ) = (X (*cp - 3) + X (*cp + 3)) / 2;
- Y (*cp ) = (Y (*cp - 3) + Y (*cp + 3)) / 2;
- X (*cp - 1) = (X (*cp - 3) + X (*cp )) / 2;
- Y (*cp - 1) = (Y (*cp - 3) + Y (*cp )) / 2;
- X (*cp + 1) = (X (*cp ) + X (*cp + 3)) / 2;
- Y (*cp + 1) = (Y (*cp ) + Y (*cp + 3)) / 2;
- }
- else {
-
- X (*cp ) = (X (*cp - 3) + X (0 )) / 2;
- Y (*cp ) = (Y (*cp - 3) + Y (0 )) / 2;
- X (*cp - 1) = (X (*cp - 3) + X (*cp)) / 2;
- Y (*cp - 1) = (Y (*cp - 3) + Y (*cp)) / 2;
- X (*cp + 1) = (X (*cp ) + X (0 )) / 2;
- Y (*cp + 1) = (Y (*cp ) + Y (0 )) / 2;
- }
- }
- }
- return self;
- }
-
- - alignThreePoints:(int *)cp
- {
- int fixed1, fixed2, variable;
- float ffx, fvx, ffy, fvy, base, scale;
-
- if (!controlpts || *cp < 0 || *cp >= ncontrolpts || ncontrolpts < 3)
- return self;
-
- variable = *cp; // moving the selected point
-
- // look which points not to move
-
- if (*cp % 3 == 1) {
- fixed1 = *cp - 1;
- fixed2 = *cp - 2;
- }
- else if (*cp % 3 == 2) {
- fixed1 = *cp + 1;
- fixed2 = *cp + 2;
- }
- else {
- fixed1 = *cp - 1;
- fixed2 = *cp + 1;
- }
-
- fixed1 = (fixed1 + ncontrolpts) % ncontrolpts; // wrap around
- fixed2 = (fixed2 + ncontrolpts) % ncontrolpts;
-
- ffx = X (fixed2) - X (fixed1);
- fvx = X (variable) - X (fixed1);
- ffy = Y (fixed2) - Y (fixed1);
- fvy = Y (variable) - Y (fixed1);
- base = ffx * ffx + ffy * ffy;
-
- if (base < 0.000001) {
- X (variable) = X (fixed1);
- Y (variable) = Y (fixed1);
- }
- else {
- scale = (ffx * fvx + ffy * fvy) / base;
- X (variable) = X (fixed1) + scale * ffx;
- Y (variable) = Y (fixed1) + scale * ffy;
- }
- return self;
- }
-
- - write:(NXTypedStream *)stream
- {
- [super write:stream];
- NXWriteTypes(stream,"*****ffffffffffffcccci", &methodname, &drawingmethod, &strokemethod, &fillmethod, &data, &c1[0], &c1[1], &c1[2], &c2[0], &c2[1], &c2[2], &linewidth, &tx, &ty, &phi, &sx, &sy, &transformed, &rotated, &translated, &scaled, &ncontrolpts);
- NXWriteRect(stream, &bounds);
- NXWriteArray(stream, "f", ncontrolpts*2, controlpts);
- return self;
- }
-
- - read:(NXTypedStream *)stream
- {
- [super read:stream];
- if(NXTypedStreamClassVersion(stream, "PencilGraphic")<1)
- {
- NXReadTypes(stream,"*****fffffffffffcccci", &methodname, &drawingmethod, &strokemethod, &fillmethod, &data, &c1[0], &c1[1], &c1[2], &c2[0], &c2[1], &c2[2], &linewidth, &tx, &ty, &phi, &sx, &transformed, &rotated, &translated, &scaled, &ncontrolpts);
- sy=sx;
- }
- else
- NXReadTypes(stream,"*****ffffffffffffcccci", &methodname, &drawingmethod, &strokemethod, &fillmethod, &data, &c1[0], &c1[1], &c1[2], &c2[0], &c2[1], &c2[2], &linewidth, &tx, &ty, &phi, &sx, &sy, &transformed, &rotated, &translated, &scaled, &ncontrolpts);
-
- NXReadRect(stream, &bounds);
- controlpts=(float *)malloc(sizeof(float)*2*ncontrolpts);
- NXReadArray(stream, "f", ncontrolpts*2, controlpts);
- return self;
- }
-
- - (void)writeType:(NXStream *)to
- {
- NXPrintf(to,"0");
- }
-
- #define WRITE_STRING(a) if((a) && strcmp(a,"")) NXPrintf(to, "{%s} ", a); else NXPrintf(to, "{} ")
-
- - (void)writeDescription:(NXStream *)to
- {
- int i;
-
- [self writeType:(NXStream *)to];
- NXPrintf(to, " { ");
- WRITE_STRING(methodname);
- WRITE_STRING(drawingmethod);
- WRITE_STRING(strokemethod);
- WRITE_STRING(fillmethod);
- WRITE_STRING(data);
- NXPrintf(to, "%g %g %g %g %g %g %g %g %g %g %g %g %d } { %g %g %g %g } { ", c1[0], c1[1], c1[2], c2[0], c2[1], c2[2], linewidth, tx, ty, phi, sx, sy, ncontrolpts,bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
- for(i=0;i<ncontrolpts;i++) { NXPrintf(to, "%g %g ", controlpts[i*2], controlpts[i*2+1]); }
- NXPrintf(to, "}");
- }
-
- - (char *)giveDescription
- {
- int len;
- int maxlen;
- char *buf;
-
- if(result) NXCloseMemory(result, NX_TRUNCATEBUFFER);
- result=NXOpenMemory(NULL,0,NX_WRITEONLY);
- [self writeDescription:result];
- NXGetMemoryBuffer(result, &buf, &len, &maxlen);
- return buf;
- }
-
- #define NEWSTRING(a) read_brace_string(from, tmp); if(a) free(a); a=(char *)malloc(sizeof(char)*(strlen(tmp)+1)); strcpy(a,tmp)
-
- - (void)initFromDescription:(NXStream *)from
- {
- static char tmp[500];
- int i;
-
- NXScanf(from," ");
- NXGetc(from); // the {
- NEWSTRING(methodname);
- NEWSTRING(drawingmethod);
- NEWSTRING(strokemethod);
- NEWSTRING(fillmethod);
- NEWSTRING(data);
- free(controlpts);
- ncontrolpts=0;
- controlpts=NULL;
- NXScanf(from," %f %f %f %f %f %f %f %f %f %f %f %f %d", &c1[0], &c1[1], &c1[2], &c2[0], &c2[1], &c2[2], &linewidth, &tx, &ty, &phi, &sx, &sy, &ncontrolpts);
- NXScanf(from," ");
- NXGetc(from);
- NXScanf(from," ");
- NXGetc(from);
- NXScanf(from, " %f %f %f %f", &bounds.origin.x, &bounds.origin.y, &bounds.size.width, &bounds.size.height);
- NXScanf(from," ");
- NXGetc(from);
- NXScanf(from," ");
- NXGetc(from);
- controlpts=(float *)malloc(sizeof(float)*2*ncontrolpts);
- for(i=0;i<ncontrolpts;i++) { NXScanf(from, " %f %f", &controlpts[i*2], &controlpts[i*2+1]); }
- NXScanf(from," ");
- NXGetc(from);
- if(fabs(phi)<=1e-6) { phi=0; rotated=NO; } else { rotated=YES; }
- if(hypot(tx,ty)<=1e-6) { tx=ty=0; translated=NO; } else { translated=YES; }
- if(fabs(sx-1.0)+fabs(sy-1.0)<1e-6) { sx=sy=1; scaled=NO; } else { scaled=YES; }
- transformed=(translated || scaled || rotated) ? YES:NO;
- }
-
- - select:(BOOL)yesno { selected=yesno; return self; }
- - (BOOL)selected { return (BOOL)selected; }
- - (void)drawIfNeeded:(NXRect *)re:(int)cp:(float)bsize
- { } // only used for redrawing EPS after a move...
- @end