PS
# Orbits.m4
threeD_init
NeedDpicTools

 crad = 1.0
 g = 0.65

#                              `orbitpos(long,lat,rad,ang)'
define(`orbitpos',
`rot3Dx((`$2')*dtor_,rot3Dz((`$1')*dtor_,rot3Dy(-(`$4')*dtor_,`$3',0,0)))')

define(`PO',`B.C+(Project(orbitpos(orbitlong,orbitlat,orbitrad,`$1')))')

define vis { X: PO($1)
 if (distance(X,B.C)>crad) || \
   (dot3D(View3D,orbitpos(orbitlong,orbitlat,orbitrad,$1))>0) \
 then {$2 = 1} else {$2 = -1} }

#                              `orbit(long,lat,rad)'
define(`orbit',
`[da = 3
 orbitlong = `$1'
 orbitlat = `$2'
 orbitrad = `$3'
 define(`decorated',`ifelse(`$4',,,`outlined `$4'')')
 arrow from PO(0) to PO(da*3) decorated
 n=0
 P[n]: PO(0)
 vis(0,v)
 for d=da to 360 by da do {
   vis(d,x)
   if  x*v < 0 then {
     findroot(vis,d-da,d,1e-6,x)
     n+=1; P[n]: PO(x)
     if v < 0 then { fitcurve(P,n,dashed decorated) } \
     else { fitcurve(P,n,decorated) }
     P[0]: P[n]
     n = 0; v = -v }
   n +=1; P[n]: PO(d)
   }
 if v < 0 then { fitcurve(P,n,dashed decorated) } \
 else { fitcurve(P,n,decorated) }
 ] with .c at B.C')

#                               ball(rad,highlight rad,highlight degrees)
define(`ball',`[
 lt = linethick bp__
 C: circle invis rad `$1' at (0,0)
 D: C+(Rect_(`$2',`$3'))
 rm = `$1'+distance(C,D)
 a = 1 # fade rate parameter
 for r=lt to rm by lt do {
   u = 1-(r/rm*(a*r/rm+(1-a)))
   if r < (1-g)*`$1' then { circle outlined rgbstring(u,u,u) rad r at D } \
   else { arc cw outlined rgbstring(u,u,u) from Cintersect(D,r,C,`$1') \
     to Cintersect(D,r,C,`$1',R) with .c at D
     }
   }
 circle rad C.rad at C
 ]')

 linethick = 0.8
 B: ball(crad,crad*g,110)

 azimuth = 0
 elevation = 0
 setview(azimuth,elevation)

 orbit(10, 30,crad*1.3,"red")
 orbit(10,-30,crad*1.3,"blue")
 orbit(10,-90,crad*1.3,"cyan")

PE