How to make Cross Hatching sections of a sphere?

I am trying to recreate:

using CETZ.

Here is my code so far:

#import "@preview/cetz:0.3.1"
#cetz.canvas({
  import cetz.draw: *
  content=content.with(padding:0.5em)

  set-style(
    grid:(
      stroke:gray,
    ),
  mark: (
    fill: black,
    scale:0.5,
  )
  )
  scale(175%)

  on-xy({
      arc((2,0), start: 0deg, stop: 180deg, radius:2, stroke:0.5pt)
    })
  
  ortho({
    on-xz({
      set-style(
        line: (stroke:0.5pt )
      )
      line((-2,2),(2,2))
      line((-2,-2),(2,-2))

      for i in range(4){
        line((-1+i,2.8),(-1+i,-2))
        content((-1.5+i,2.3),$x$)

        line((-1.7+i,2.3), (-2+i,2.3), mark:(end:">"))
        line((-1+i,2.3), (-1.3+i,2.3), mark:(start:">"))

        content((-1.5+i,3),numbering("I", i+1))
        
      }
      line((-2,2.8),(-2,-2))

      line((-2.4,2.4),(2.4,-2.4))

      line((-2.4+fsqrt(2),2.4),(1.8+fsqrt(2),-1.8))
    
      circle((0,0),radius:2,stroke:0.5pt)


      
    })
    on-yz({
    arc((fsqrt(3),0), start: 0deg, stop: 180deg, radius:fsqrt(3))
    },x:-1)

    on-yz({
    arc((fsqrt(3),0), start: 0deg, stop: 180deg, radius:fsqrt(3))
    },x:1)
    
    on-yz({
    arc((2,0), start: 0deg, stop: 180deg, radius:2)
    })

    rotate(y:-45deg)
    on-yz({
    arc((2,0), start: 0deg, stop: 180deg, radius:2)
    })
    on-yz({
    arc((fsqrt(3),0), start: 0deg, stop: 180deg, radius:fsqrt(3))
    },x:1)

  },  x:40deg, y:34deg)

})]

And the result:
image

I’m totally stuck on how to make the cross-hatching. Any ideas?

3 Likes

Hi @DVDTSB, could you maybe try to revise your post’s title to be a complete question as per the question guidelines:

Good titles are questions you would ask your friend about Typst.

We hope by adhering to this, we make the information in this forum easy to find in the future.


Also, while I have no help to offer for this problem, let me say: this is awesome! I assume fsqrt stands for “fast square root”? It’s not part of your example, but adding #let fsqrt = calc.sqrt still works well. (And there’s an extra ] in the end, if you care enough to clean it up.)

Also also, for anyone who wants to play with this like me: you can get rudimentary animation by using "".len() * 5deg as the x and y angles, and then just adding characters to the strings (Laurenz mentioned that trick at some point somewhere.)

In the end i managed to solve it by myself:

#import "@preview/cetz:0.3.1"
#let fsqrt=calc.sqrt
#cetz.canvas({
  import cetz.draw: *
  content=content.with(padding:0.5em)

  set-style(
    grid:(
      stroke:gray,
    ),
  mark: (
    fill: black,
    scale:0.5,
  )
  )
  scale(175%)

  on-xy({
      arc((2,0), start: 0deg, stop: 180deg, radius:2, stroke:0.5pt)
    })

  let det=80
    
  ortho({
    on-xz({
      set-style(
        line: (stroke:0.5pt )
      )
      line((-2,2),(2,2))
      line((-2,-2),(2,-2))

      for i in range(4){
        line((-1+i,2.8),(-1+i,-2))
        content((-1.5+i,2.3),$x$)

        line((-1.7+i,2.3), (-2+i,2.3), mark:(end:">"))
        line((-1+i,2.3), (-1.3+i,2.3), mark:(start:">"))

        content((-1.5+i,3),numbering("I", i+1))
        
      }
      line((-2,2.8),(-2,-2))

      line((-2.4,2.4),(2.4,-2.4))

      line((-2.4+fsqrt(2),2.4),(1.8+fsqrt(2),-1.8))
    
      circle((0,0),radius:2,stroke:0.5pt)


        
      for i in range(det){
        let depth=2/det*i
        let start=-calc.min(1,fsqrt(4-depth*depth))
        let end=calc.min(0, -depth+fsqrt(2))
        start=calc.max(start,-depth)
        if start < end{
          line((start,depth),(end,depth))
        }
      }

      
    })
    on-yz({
    arc((fsqrt(3),0), start: 0deg, stop: 180deg, radius:fsqrt(3))
    },x:-1)

    on-yz({
    arc((fsqrt(3),0), start: 0deg, stop: 180deg, radius:fsqrt(3))
    },x:1)
    
    on-yz({
    arc((2,0), start: 0deg, stop: 180deg, radius:2)
    })


    
    rotate(y:-90deg)
    
    for i in range(det){
      let depth=2/det*i

      on-yz({

        let r=fsqrt(4-depth*depth)

        let start=-calc.min(1,r)
        let end=calc.min(0, -depth+fsqrt(2))
        start=calc.max(start,-depth)
        
        if start < end{
          arc((-start,fsqrt(r*r - start*start)), start: calc.acos(-start/r), stop: calc.acos(-end/r), radius:r, stroke:0.5pt)
        }
          
        
      },x:depth)
    }

    rotate(y:45deg)
    on-yz({
    arc((2,0), start: 0deg, stop: 180deg, radius:2)
    })
    on-yz({
    arc((fsqrt(3),0), start: 0deg, stop: 180deg, radius:fsqrt(3))
    },x:1)

  },  x:40deg, y:34deg)

})

@SillyFreak, thanks, i’ll update it asap.

5 Likes

That. is. beautiful. Cetz ist the best!