I would like to draw circular arcs on the surface of a sphere to model as atoms intersect a probe atom in a molecule. I attach an example image that I would like to draw with either tikz or asymptote.

atoms intersecting probe atom

circular arcs for the intersection

Thanks much for your help.

  • Have a look at the tikz-3dplot package! Mar 27, 2014 at 10:18
  • Welcome to TeX.SX! On this site, a question should typically revolve around an abstract issue (e.g. "How do I get a double horizontal line in a table?") rather than a concrete application (e.g. "How do I make this table?"). Questions that look like "Please do this complicated thing for me" tend to get closed because they are either "off topic", "too broad", or "unclear". Please try to make your question clear and simple by giving a minimal working example (MWE): you'll stand a greater chance of getting help.
    – ChrisS
    Mar 27, 2014 at 10:34

1 Answer 1


The following code uses the contour module to compute the intersection of a parametrized surface with an implicitly defined surface. It doesn't offer a complete solution to your problem, since plotting one translucent surface in front of another can be tricky in Asymptote; but it's a start, and it at least more or less answers the titular question.


import graph3;
import contour;

currentlight.background = black;
currentprojection = orthographic(5, 2, 4);

// Some aliases that make the contour module a bit easier to use.
typedef path[] disconnected_path;
typedef guide[] disconnected_guide;
typedef path3[] disconnected_path3;

real fuzz = .001;

real umax(surface s, real fuzz=fuzz) {
    if (s.ucyclic()) return s.index.length;
    else return s.index.length - fuzz;
real vmax(surface s, real fuzz=fuzz) {
    if (s.vcyclic()) return s.index[0].length;
    return s.index[0].length - fuzz;

int nu = 8, nv = 8;
path3 semicircle = Arc(c=O, -Z, Z, normal=X, n=nu);
surface myUnitsphere = surface(semicircle, c=O, axis=Z, n=nv);

surface sphere(triple c, real r) {
    surface toReturn = shift(c)*scale3(r)*myUnitsphere;
    return toReturn;
// Make the type function3 an alias f0r the type real(triple), i.e., a function3 is a function from triples to reals.
typedef real function3(triple);

// Make the type function2 an alias f0r the type real(real,real), i.e., a function2 is a function from (real, real) to reals.
typedef real function2(real, real);

// Returns the restriction of f to the surface s, given by its built-in parametrization.
function2 pullback(function3 f, surface s) {
    return new real(real u, real v) {
        return f(s.point(u,v));

 * Parameters: an implicit surface {f = 0} and a parametrized surface s.
 * Returns a possibly disconnected path, in the coordinates of the parametric surface s, that describes 
 * the intersection of the two surfaces.
disconnected_path parametrized_intersection(function3 f, surface s, pair smin = (0,0), pair smax = (umax(s), vmax(s))) {
    disconnected_guide toReturn = contour(pullback(f, s), smin, smax, new real[] {0})[0];
    return toReturn;

path3 on_surface(path p, surface s) {
    int size = length(p);
    triple[] points = new triple[size];
    for (int i = 0; i < size; ++i) {
        pair pathpoint = point(p,i);
        points[i] = s.point(pathpoint.x, pathpoint.y);
    path3 toReturn = operator..(...points);
    if (cyclic(p)) {
        toReturn = toReturn & cycle;
    return toReturn;

disconnected_path3 on_surface(disconnected_path p, surface s) {
    disconnected_path3 toReturn;
    for (path segment : p) {
        toReturn.push(on_surface(segment, s));
    return toReturn;

function3 implicit_sphere(triple c, real r) {
    return new real(triple p) {
        return length(p - c)^2 - r^2;


surface mySphere = sphere(c=O, r=1);

draw(mySphere, surfacepen=material(diffusepen=gray(0.1), emissivepen=gray(0.9)));

triple c = 1.5Y;
real r = 0.8;
surface s = sphere(c=c, r=r);
function3 s_implicit = implicit_sphere(c=c, r=r);

disconnected_path param_circle = parametrized_intersection(s_implicit, mySphere);
disconnected_path3 circle = on_surface(param_circle, mySphere);

draw(s, surfacepen=material(diffusepen=0.5*blue + opacity(0.5), emissivepen=0.5*white));
draw(circle, blue);

c = 1.4X;
r = 0.5;
s = sphere(c=c, r=r);
s_implicit = implicit_sphere(c=c, r=r);

param_circle = parametrized_intersection(s_implicit, mySphere);
circle = on_surface(param_circle, mySphere);

draw(s, surfacepen=material(diffusepen=0.5*blue + opacity(0.5), emissivepen=0.5*white));
draw(circle, blue);

The result:

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .