cse0080@desire.wright.edu (06/11/91)
In article <1991Jun3.095901.3793@desire.wright.edu>, I wrote: > Help! > > I need to know how to generate spline curves in PostScript when > all the data I have on hand is an array of data points that lie on > the curve itself. (IE: no control points for the curveto operator) > > Anyone know a good way to do this? > > Thanks for your assistance. > > John Hansen > cse0080@wsu.bitnet > cse0080@desire.wright.edu > I received two C program fragments, and a copy of the posted PostScript code that attempted to help me solve my problem. Unfortunately, none of them seemed to do what I needed. The PostScript code didn't draw through every point so it seemed pointless (pun intended) to use that. The other two C programs produced weird results (and I'm no C expert so I didn't try too hard to fix/modify them to my needs. So... I decided to attempt a solution myself. Written in my native tongue: Fortran. (Sorry about that...) I have included at the end a code fragment which should be easily translated into C or Pascal for you CS types. My program appears to work for all the test datasets which I tried. It works like this: 1. Calculate angle to horizontal of a line "tangent" to the desired curve at each point. (tangle(i) in the code) 2. Calculate two control points in between each set of two data points using the 1/4 (magic number 8-) the distance between the two data points. formula: new_x = 0.25*len*sind(tangle(i)) + point(i).x, where len is dist. between point_i & point_i+1. I set the tangent angle of the first and last points to be equal to the straight line angle between each of those points and the next/previous point. Anyway, the code shouldn't be too obtuse (heh, heh, heh...) I have also included a /SPline word in PostScript which I use to eat all the numbers I write out. Hopefully this will save someone out there some time and effort. It took me the better part of three days to get this to actually work in all the cases that I threw at it. Thanks for your help John Hansen cse0080@wsu.bitnet cse0080@desire.wright.edu hansen@mdss1.hq.aflc.af.mil (work) --------------------------- cut here -------------------------------- C C Sample do loop for processing my spline data. C do i=1,numsp clr = splines(i).clr/10.0 wid = max(mod(splines(i).width,10)*1.0,0.5) write(unit=pat,fmt='(I1)') mod(splines(i).style,10) if (pat .eq. '0') pat = ' ' write(7,'(F5.2,A)') clr,' [' do j=1,splines(i).points pts(j).x = int(splines(i).x(j)*10) pts(j).y = int(splines(i).y(j)*10) end do call dospline(splines(i).points) write(7,'(3A,F5.2,A)') '] [',pat,'] 0',wid,' SPline' end do C C The Fortran code which writes /SPline to my prolog file C write(7,'(A)') ' ' write(7,'(A)') '/SPline { setlinewidth setdash /polyarray exch def' write(7,'(A)') '/pcount polyarray length 2 sub 6 idiv def' write(7,'(A)') 'polyarray aload pop moveto pcount {curveto}' write(7,'(A)') 'repeat setgray stroke} def' write(7,'(A)') ' ' C C The pts point array is COMMON but could be passed as a parameter C to DOSPLINE. My splines will never be more than 30 points long C so I hard-coded the array sizes. C subroutine dospline(npts) structure /point/ real x,y end structure record /point/ pts(50), cp1(50), cp2(50) real dx1,dx2,dy1,dy2,angle1(50),angle2(50),distp(50) real jarct2d, tangle(50) integer npts common /ptdata/ pts if (npts .lt. 3) goto 1000 do i=2,npts-1 dx1 = pts(i).x - pts(i-1).x dy1 = pts(i).y - pts(i-1).y dx2 = pts(i+1).x - pts(i).x dy2 = pts(i+1).y - pts(i).y distp(i) = sqrt(dx1*dx1+dy1*dy1) angle1(i) = jarct2d(dy1,dx1) angle2(i) = jarct2d(dy2,dx2) tangle(i) = (angle2(i) + angle1(i))/2.0 end do dx2 = pts(npts-1).x - pts(npts).x dy2 = pts(npts-1).y - pts(npts).y distp(npts) = sqrt(dx2*dx2+dy2*dy2) angle1(npts) = jarct2d(dy2,dx2) C C The commented change slightly the look of the curve at start & end C C tangle(1) = angle1(2) + tangle(2) - angle2(2) C tangle(npts)=angle1(npts)+(angle1(npts-1)-angle2(npt-1))/2.0 C C Here they are set == to straight-line angle to next/previous points C tangle(1) = angle1(2) tangle(npts)=angle1(npts) do i=1,npts-1 call compcp(distp(i+1),tangle(i),i,1,cp1(i).x,cp1(i).y) if (i .le. npts-2) then call compcp(distp(i+1),tangle(i+1),i+1,2,cp2(i).x,cp2(i).y) endif end do call compcp(distp(npts),tangle(npts),npts,2, 1 cp2(npts-1).x,cp2(npts-1).y) do i=npts-1,1,-1 write(7,'(6F10.4)') cp1(i).x,cp1(i).y, 1 cp2(i).x,cp2(i).y,pts(i+1).x,pts(i+1).y end do write(7,'(2F10.4)') pts(1).x,pts(1).y 1000 return end real function compcp(len,ang,ptnum,cp,cpx,cpy) structure /point/ real x, y end structure record /point/ pts(50) real len, ang, tx, ty, dd, dx, dy, temp, cpx, cpy real computecpx, computecpy integer ptnum,cp common /ptdata/ pts tx = computecpx(len,ang,ptnum) ty = computecpy(len,ang,ptnum) if (cp .eq. 1) then dx = pts(ptnum+1).x - tx dy = pts(ptnum+1).y - ty else dx = pts(ptnum-1).x - tx dy = pts(ptnum-1).y - ty endif dd = sqrt(dx*dx+dy*dy) if (dd .gt. len) then tx = computecpx(len,180+ang,ptnum) ty = computecpy(len,180+ang,ptnum) endif cpx = tx cpy = ty return end real function computecpx(len,ang,ptnum) structure /point/ real x, y end structure record /point/ pts(50) real len, ang integer ptnum common /ptdata/ pts C C The number 0.25 could be used as a variable for "shaping" C the curve between each data point. C temp = 0.25*len*cosd(ang) + pts(ptnum).x computecpx = temp return end real function computecpy(len,ang,ptnum) structure /point/ real x, y end structure record /point/ pts(50) real len, ang integer ptnum common /ptdata/ pts temp = 0.25*len*sind(ang) + pts(ptnum).y computecpy = temp return end C C The atan2d VMS fortran intrinsic funtion returns angles between C -180 & 180. I remove the undefined case of dx=dy=0. C real function jarct2d(dumy,dumx) real dumx,dumy if (dumx .eq. 0 .and. dumy .eq. 0) then jarct2d = 0 else jarct2d = atan2d(dumy,dumx) endif return end
larry@csccat.cs.com (Larry Spence) (06/12/91)
In article <1991Jun10.162302.3900@desire.wright.edu> cse0080@desire.wright.edu writes: >In article <1991Jun3.095901.3793@desire.wright.edu>, I wrote: >> Help! >> >> I need to know how to generate spline curves in PostScript when >> all the data I have on hand is an array of data points that lie on >> the curve itself. (IE: no control points for the curveto operator) >> >> Anyone know a good way to do this? >> > [FORTRAN code (wince,shudder!) for interpolation deleted] I still suggest that anyone who wants to implement this go look at Farin's book. There are a number of well-known schemes for determining tangents and end conditions, no need to reinvent them! Also, drop those arctangents and just use the direction from the previous point to the next point. Will someone please whack his knuckles for posting FORTRAN here? %) %) -- Larry Spence larry@csccat.cs.com ....{uunet,texsun,cs.utexas.edu,decwrl}!csccat!larry