 
Task

Display a region that consists of a large sphere with part of a smaller sphere removed from it as a result of geometric subtraction.

(This will basically produce a shape like a "death star".)



Related tasks

 draw a sphere
 draw a cuboid
 draw a rotating cube
 write language name in 3D ASCII


T Sphere
   Float cx, cy, cz, r
   F (cx, cy, cz, r)
      .cx = cx
      .cy = cy
      .cz = cz
      .r = r
 
F dotp(v1, v2)
   V d = dot(v1, v2)
   R I d < 0 {-d} E 0.0
 
F hit_sphere(sph, x0, y0)
   V x = x0 - sph.cx
   V y = y0 - sph.cy
   V zsq = sph.r ^ 2 - (x ^ 2 + y ^ 2)
   I zsq < 0
      R (0B, 0.0, 0.0)
   V szsq = sqrt(zsq)
   R (1B, sph.cz - szsq, sph.cz + szsq)
 
F draw_sphere(k, ambient, light)
   V shades = ‘.:!*oe&#%@’
   V pos = Sphere(20.0, 20.0, 0.0, 20.0)
   V neg = Sphere(1.0, 1.0, -6.0, 20.0)
 
   L(i) Int(floor(pos.cy - pos.r)) .< Int(ceil(pos.cy + pos.r) + 1)
      V y = i + 0.5
      L(j) Int(floor(pos.cx - 2 * pos.r)) .< Int(ceil(pos.cx + 2 * pos.r) + 1)
         V x = (j - pos.cx) / 2.0 + 0.5 + pos.cx
 
         V (h, zb1, zb2) = hit_sphere(pos, x, y)
         Int hit_result
         Float zs2
         I !h
            hit_result = 0
         E
            (h, V zs1, zs2) = hit_sphere(neg, x, y)
            I !h
               hit_result = 1
            E I zs1 > zb1
               hit_result = 1
            E I zs2 > zb2
               hit_result = 0
            E I zs2 > zb1
               hit_result = 2
            E
               hit_result = 1
 
         V vec = (0.0, 0.0, 0.0)
         I hit_result == 0
            print(‘ ’, end' ‘’)
            L.continue
         E I hit_result == 1
            vec = (x - pos.cx, y - pos.cy, zb1 - pos.cz)
         E I hit_result == 2
            vec = (neg.cx - x, neg.cy - y, neg.cz - zs2)
         vec = normalize(vec)
 
         V b = dotp(light, vec) ^ k + ambient
         V intensity = Int((1 - b) * shades.len)
         intensity = min(shades.len, max(0, intensity))
         print(shades[intensity], end' ‘’)
      print()
 
V light = normalize((-50.0, 30.0, 50.0))
draw_sphere(2, 0.5, light)