/* CMD: Clay Morph
*
* Set up your control points in a layer by themselves and call ClayInit.
* Then put your object to be morphed in the background layer.
* Then move your control points and call ClayMorph.
* That's all there is to it.
*
* Note that ClayMorph only moves points. It doesn't make new polygons.
* So make sure your object is subdivided enough.
*
*/
call addlib("LWModelerARexx.port",0)
signal on error
signal on syntax
call addlib("rexxmathlib.library",0,-30,0)
call addlib("rexxsupport.library",0,-30,0)
call main
exit
syntax:
error:
t=Notify(1,'!Rexx Script Error','@'ErrorText(rc),'Line 'SIGL)
if (mxx_add) then call remlib(mxx)
exit
MAIN:
pi = 3.1415926385897932384626
call random(,,time('s'))
syscode = "Clay Morph"
claynam = "ENV:clay.tmp"
/* Store current and background layers and first empty layer. */
fg = curlayer()
bg = curblayer()
emp = emptylayers()
if (words(emp) = 0) then do
ok = notify(2,'!No empty layer.','Morph will be placed','on current layer.','Original will be','!nuked.')
if ok = 0 then return
tlt = 0
end
if (words(emp) > 0) then do
tl = word(emp,1)
tlt = 1
end
/* Get original clay positions */
if (~open(state, claynam, 'R')) then break
clays = readln(state)
call meter_begin(clays*2, syscode, "Reading Clay")
ccx = 0
ccy = 0
ccz = 0
do i=1 to clays
xyz = readln(state)
parse var xyz ox.i oy.i oz.i
ccx = ccx + ox.i
ccy = ccy + oy.i
ccz = ccz + oz.i
call meter_step()
end i
do i=1 to clays
x = ox.i-ccx/clays
y = oy.i-ccy/clays
z = oz.i-ccz/clays
call GETROT
orx.i = rox
ory.i = roy
orz.i = roz
call meter_step()
end i
call meter_end()
call close(state)
n = xfrm_begin()
if (n ~= clays) then call notify(1,'Clay has been damaged.','Try again.')
if (n ~= clays) then return
call meter_begin(n, syscode, "Computing changes")
do i=1 to n
xyz = xfrm_getpos(i)
parse var xyz nx ny nz
x = nx-ccx/clays
y = ny-ccy/clays
z = nz-ccz/clays
call GETROT
drx.i = rox-orx.i
dry.i = roy-ory.i
drz.i = roz-orz.i
call meter_step()
end i
call meter_end()
call xfrm_end()
call setlayer(bg)
n = xfrm_begin()
if (n = 0) then return
call meter_begin(n, syscode, "Morphing Points")
do i=1 to n
xyz = xfrm_getpos(i)
parse var xyz x y z
x = x-ccx/clays
y = y-ccy/clays
z = z-ccz/clays
call GETROT
x = x+ccx/clays
y = y+ccy/clays
z = z+ccz/clays
cx = rox
cy = roy
cz = roz
call Clay
call SETROT
call xfrm_setpos i,x y z
call meter_step()
end i
call meter_end()
call xfrm_end()
CLAY:
dtot = 0
dmx = 0
dmy = 0
dmz = 0
do c=1 to clays
if dtot ~= -1 then do
dist = sqrt((x-ox.c)**2 + (y-oy.c)**2 + (z-oz.c)**2)
if dist = 0 then do
dtot = -1
dmx = drx.c
dmy = dry.c
dmz = drz.c
end
if dist ~= 0 then do
dtot = dtot + 1/dist
dmx = dmx + drx.c/dist
dmy = dmy + dry.c/dist
dmz = dmz + drz.c/dist
end
end
end
/* normalize */
if dtot ~= -1 then do
dmx = dmx/dtot
dmy = dmy/dtot
dmz = dmz/dtot
end
cx = cx+dmx
cy = cy+dmy
cz = cz+dmz
return
GETROT:
/* 3-D Radial Rotation */
/* takes x,y,z, returns with rox,roy,roz */
rox = 0
roy = 0
roz = sqrt(x*x+y*y+z*z)
/* First we adjust our heading */
yf=0
if z=0 then do
if x>0 then roy=roy+pi/2
if x<0 then roy=roy-pi/2
yf = 1
end
if x=0 then do
if z>0 then roy=roy+0
if z<0 then roy=roy+pi
yf = 1
end
if yf=0 then do
actn=abs(x/z)
call arctan
if z>0 then do /* quadrant 1 */
if x>0 then roy=roy+th
end
if z>0 then do /* quadrant 2 */
if x<0 then roy=roy-th
end
if x<0 then do /* quadrant 3 */
if z<0 then roy=roy+pi+th
end
if z<0 then do /* quadrant 4 */
if x>0 then roy=roy+pi-th
end
end
/* Now we pitch up */
nd=sqrt(z*z+x*x)
yf=0
if nd=0 then do
if y>0 then rox=rox+pi/2
if y<0 then rox=rox+-pi/2
yf = 1
end
if y=0 then yf = 1
if yf=0 then do
actn=abs(y/nd)
call arctan
if y>0 then rox=rox+th
if y<0 then rox=rox-th
end
return
ARCTAN:
actu = actn
if actu < -1 then th = pi/2+atan(1/abs(actn))
if (actu < 1.00001)&(actu > -1.00001) then th = atan(actn)
if actu > 1 then th = pi/2-atan(1/actn)
return
SETROT:
/* takes cx,cy,cz & returns with x,y,z */
/* pitch */
x = 0
y = sin(cx)
z = cos(cx)
/* heading */
x = sin(cy)*z
y = y
z = cos(cy)*z
/* radius */
x = x * cz + ccx/clays
y = y * cz + ccy/clays
z = z * cz + ccz/clays
return
               (
geocities.com/g_fyffe)