I am trying to reproduce the construction of bisectors with compass.

enter image description here

Here is what I managed to get so far

vardef bisector(expr A, O, B, r) =
  save arc, E, F, I;
  path arc[] ; pair E, F, I[];

  % Draw one arc of radius \r\ around center \O\ such that
  % it cuts \OA\ and \OB\ respectively at points \E\ and \F\.
  arc[0] = fullcircle scaled r shifted O;
  E      = (O--A) intersectiontimes arc[0];
  F      = (O--B) intersectiontimes arc[0];

  % With the same length \r\, draw two arcs respectively around
  % centers \E\ and \F\ intersecting each other.
  arc[1] = fullcircle scaled r shifted point (ypart E) of arc[0];
  arc[2] = fullcircle scaled r shifted point (ypart F) of arc[0];

  % That intersection point is \I\.
  I[0] = (reverse arc[1]) intersectionpoint (reverse arc[2]) ;
  I[1] = (reverse arc[1]) intersectiontimes (reverse arc[2]) ;
  I[2] = arc[2] intersectiontimes arc[1] ;

  save rad ; numeric rad ; rad = .33 ;
  % Draw the arc around points \E\ and \F\ on rays \OA\ and \OB\.
  draw subpath(ypart E - rad, ypart E + rad) of arc[0] withcolor .8[black,white];
  draw subpath(ypart F - rad, ypart F + rad) of arc[0] withcolor .8[black,white];

  % Draw arcs around point \I\.
  draw subpath(ypart I[1] - rad, ypart I[1] + rad) of arc[1] withcolor .5[black,white] ;
  draw subpath(xpart I[2] - rad, xpart I[2] + rad) of arc[2] withcolor .5[black,white] ;


Which, when used in this piece of code

  u = cm ;
  pair O, x, y, A, B, M[] ;

  O = origin ;
  x = (4u,2u) ;
  y = (5u,-3u) ;

  M[0] = bisector(x,O,y,30) ;
  M[1] = bisector(O,x,y,30) ;
  M[2] = bisector(x,y,O,30) ;

  draw O -- x -- y -- cycle ;
  draw O -- y ;
  draw O -- M[0] shortened -u;
  draw x -- M[1] shortened -u;
  draw y -- M[2] shortened -u;

  dotlabel.top("O", O) ;
  dotlabel.top("x", x) ;
  dotlabel.top("y", y) ;


enter image description here

And I do not understand why this is working in some cases but not in others… In fact, I am not even sure how it even works in the working cases.

What I am doing wrong?

  • 2
    This is horrible style! I[0] = (reverse arc[1]) intersectionpoint (reverse arc[2]) ; I[1] = (reverse arc[1]) intersectiontimes (reverse arc[2]) ; It is almost deliberately obfusticated.
    – Thruston
    May 27 at 16:38

1 Answer 1


Here's an alternative approach, that produces this version of your diagram.

enter image description here

My source is wrapped up in luamplib so you need to compile it with lualatex, but I have only used plain MP macros, so you can easily adapt it for Context or plain MP.


boolean show_construction; show_construction = true;
numeric extra_angle; extra_angle = 16;

vardef bisection_point(expr a, o, b, r) = 
    % declare local variables
    save arc, arc_a, arc_b;    path arc, arc_a, arc_b; 
    save point_a, point_b, m;  pair point_a, point_b, m; 
    % make the first arc scaled and centred at "o"
    arc = fullcircle scaled 2r 
          rotated (angle (b-o) - extra_angle)
          shifted o
          cutafter (o--a) rotatedabout(o, extra_angle);
    % find the points where the arc crosses each line
    point_a = arc intersectionpoint (o--a);
    point_b = arc intersectionpoint (o--b);

    % make the subsidiary arcs, scaled and centered at the points just found
    arc_a = fullcircle scaled 2r rotated angle (a-o) shifted point_a;
    arc_b = fullcircle scaled 2r rotated angle (b-o) shifted point_b;

    % find the intersections of the arcs -- the rotations above and 
    % reversing arc_a here ensures we get the right intersection of arc_a and arc_b
    m = reverse arc_a intersectionpoint arc_b;

    % draw what we have done if required
    if show_construction:
        drawoptions(withpen pencircle scaled 1/4 withcolor 1/2);
        draw arc; 
        save t; pair t; t = 1/45(-extra_angle, extra_angle);
        draw subpath t of fullcircle scaled 2r rotated angle (m-point_a) shifted point_a;
        draw subpath t of fullcircle scaled 2r rotated angle (m-point_b) shifted point_b;
        drawoptions(withpen pencircle scaled 3/2 withcolor 1/2);
        draw m; draw point_a; draw point_b;

    % return the bisection point


    pair A, B, C;

    A = (10, 5);
    B = (200, 90);
    C = (190, -80);

    pair m; m = bisection_point(B, A, C, 30); draw A -- 4[A,m];
    pair n; n = bisection_point(C, B, A, 30); draw B -- 4[B,n];
    pair o; o = bisection_point(A, C, B, 30); draw C -- 4[C,o];

    draw A--C--B--cycle;
    dotlabel.lft("$A$", A);
    dotlabel.urt("$B$", B);
    dotlabel.lrt("$C$", C);


If you set show_construction := false then you get this version:

enter image description here

The important bit of the construction is to make sure that you rotate arc_a and arc_b correctly so that you always get the correct intersection. But this is not the most efficient or simplest way to get the bisection point in Metapost. This, for example, is rather quicker and much simpler:

vardef bisection_point(expr a, o, b, r) = 
    o + unitvector (a-o) scaled r
      + unitvector (b-o) scaled r

although you don't get the pretty construction marks...

For more on this topic you might like to read sections 9.1 and 9.2 of my Drawing with Metapost document, now available on CTAN.

  • 4
    I really like your work with Drawing with Metapost. May 30 at 3:11

You must log in to answer this question.