%%===============================================
%% GeometriePlus.mp  --  Geomeetriamakrode kirjeldused
%% Marge Ilmosaar, marge_b@ut.ee
%% Valminud : 31 mai 2006
%% Viimati muudetud : 3 juuni 2006
%%===============================================
pair _t[];
pair _tt[];
path _c[];
path _cc[];
path _s[];
boolean _bo[];
transform _tf[];
numeric _n[];
numeric _nn[];
numeric fnumeric[];

%%%%=== TÕEVÄÄRTUSED ======================================
%% Kas objekt on lõik?
%% Metaposti objekt $o$.
%% true, kui $o$ on lõik; false, kui pole.
%% issegment(o)
%%-------------------------------------------------------
vardef issegment(expr a) =
  save $; boolean $;
  if (path a):
    if (length a <> 1): $:=false;
    elseif (cycle a): $:=false;
    elseif (abs(arclength (a) - dist((startingpoint(a)),(endpoint(a)))) > 64*epsilon): $:=false;
    else: $:=true;
    fi
  else: $:=false;
  fi
  $
enddef;
%%-------------------------------------------------------
%%  Kas objekt on ringjoon?
%% Metaposti objekt $o$.
%% true, kui $o$ on ringjoon; false, kui pole.
%% iscircle(o)
%%-------------------------------------------------------
vardef iscircle(expr a) =
save $,n; boolean $; numeric n; n:=0;
  if (path a):
    for i=0 step 1 until (length(a)):
      if (abs((direction i of a) dotprod (point i of a - center(a))) > 64*epsilon): n:=n+1;
      fi
    endfor
    if (n > 0): $:=false;
    elseif (length a <> 8): $:=false;
    elseif (not (cycle a)): $:=false;
    else: $:=true;
    fi
  else: $:=false;
  fi
  $
enddef;
%%-------------------------------------------------------
%%%%=== ARVUD ===============================================
%%%% Polaarkoordinaadid
%%-------------------------------------------------------
%% Punkti polaarraadius antud pooluse suhtes.
%% Punktid [$O$] ja $A$.
%% Punkti $A$ polaarradius punkti $O$ suhtes.
%% polarradius(O,A)
%% polarradius(A)
%% dist(O,A)
%% dist(A)
%%-------------------------------------------------------
vardef polarradius(text t)=
  save $,_npairn,_nothern;
  numeric $; _npairn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=1) and (_nothern=0):
      save P;
      pair P;
      $:=dist(P); % case: polarradius(A)
      $
    elseif (_npairn=2) and (_nothern=0):
      save P,Q;
      pair P,Q;
      $:=dist(P,Q); % case: polarradius(O,A)
      $
    else: errmessage "Illegal parameters for polarangle";
    fi
enddef;
%%-------------------------------------------------------
vardef dist(text t)=
  save $,_npairn,_npathn,_nothern;
  numeric $; _npairn:=0; _npathn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif iscircle(_stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=1) and (_npathn=0) and (_nothern=0):
      save P;
      pair P;
      P:=_t1;
      $:=(xpart P)++(ypart P);
      $
    elseif (_npairn=2) and (_npathn=0) and (_nothern=0):
      save P,Q;
      pair P,Q;
      P:=_t1; Q:=_t2;
      $:=(xpart Q - xpart P)++(ypart Q - ypart P);
      $
    elseif (_npairn=3) and (_npathn=0) and (_nothern=0):
      save P,Q,R;
      pair P,Q,R;
      P:=_t1; Q:=_t2; R:=_t3;
      $:=(xpart (P Projected(Q,R)) - xpart P)++(ypart (P Projected(Q,R)) - ypart P);
      $
    elseif (_npairn=1) and (_npathn=1) and (_nothern=0):
      save P,c;
      pair P;
      path c;
      P:=_t1; c:= _c1;
      $:=abs(((xpart (center(c)) - xpart P)++(ypart (center(c)) - ypart P))-radius(c));
    else: errmessage "Illegal parameters for dist";
    fi
enddef;
%%-------------------------------------------------------
%% Punkti polaarnurk antud pooluse suhtes.
%% Punktid [$O$] ja $A$.
%% Punkti $A$ polaarnurk punkti $O$ suhtes.
%% polarangle(O,A)
%% polarangle(A)
%%-------------------------------------------------------
vardef polarangle(text t)=
  save $,_npairn,_npathn,_nothern;
  numeric $; _npairn:=0; _npathn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if(_npairn=1) and (_nothern=0):
      save P;
      pair P;
      P:=_t1;
      $:=_angle(P);
      $
    elseif(_npairn=2) and (_nothern=0):
      save P,Q;
      pair P,Q;
      P:=_t1;
      Q:=_t2;
      $=_angle(Q-P);
      $
    else: errmessage "Illegal parameters for polarangle";
    fi
enddef;
%%-------------------------------------------------------
%%%%=== Kaugused ====================================
%% Kahe punkti vaheline kaugus.
%% Kaks punkti [$A$] ja $B$.
%% Punktide $A$ ja $B$ vaheline kaugus.
%% dist(A,B)
%% dist(B)

%% Punkti kaugus sirgest.
%% Punktid $A$, $B$ ja $C$.
%% Punkti $A$ kaugus sirgest $BC$.
%% dist(A,B,C)

%% Punkti kaugus ringjoonest.
%% Punkt $A$ ja ringjoon $c$.
%% Punkti $A$ lühim kaugus ringjoone $c$ punktini.
%% dist(A,c)

%%%%=== Nurkade suurused ===========================
%% Nurga suurus.
%% Punktid $A$, $B$, $C$.
%% Nurga $ABC$ suurus.
%% angle(A,B,C)

%% Punktid $A$, $B$, $C$, $D$.
%% Sirgete $AB$ ja $CD$ vahelise nurga suurus.
%% angle(A,B,C,D)

%% Lõigud $l$ ja $m$.
%% Lõikudega $l$ ja $m$ määratud sirgete vahelise nurga suurus.
%% angle(l,m)

%% Lõik $l$ ja punktid $A$, $B$.
%% Lõiguga $l$ määratud sirge ja sirge $AB$ vahelise nurga suurus.
%% angle(l,A,B)
%% angle(A,B,l)
%%-------------------------------------------------------
let _angle = angle;
vardef angle(text t)=
  save $,_npairn,_npathn,_nothern,_coco;
  numeric $; _npairn:=0; _npathn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (picture _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn=1) and (_npathn=0) and (_nothern=0):
    save P;
    pair P;
    P:=_t1;
    $:=_angle(P);
    $
  elseif (_npairn=3) and (_npathn=0) and (_nothern=0):
    save P,Q,R;
    pair P,Q,R;
    P:=_t1; Q:=_t2; R:=_t3;
    $:=abs(_angle(R-Q) - _angle(P-Q));
    if ($>180): $:=360-$; fi
    $
  elseif (_npairn=4) and (_npathn=0) and (_nothern=0):
    save P,Q,R,S;
    pair P,Q,R,S;
    P:=_t1; Q:=_t2; R:=_t3; S:=_t4;
    $:=abs(_angle(S-R) - _angle(Q-P));
    if ($>180): $:=360-$; fi
    if ($>90):  $:=180-$; fi
    $
  elseif (_npairn=0) and (_npathn=2) and (_nothern=0):
    save v,w;
    path v,w;
    v:=_c1; w:=_c2;
    if (issegment(v)) and (issegment(w)):
      $:=abs(_angle(endpoint(w)-startingpoint(w)) - _angle(endpoint(v)-startingpoint(v)));
      if ($>180): $:=360-$; fi
      if ($>90):  $:=180-$; fi
      $
    else: errmessage "Illegal parameters for angle";
    fi
  elseif ((((fnumeric1=2) and (fnumeric2=1) and (fnumeric3=1))
	or ((fnumeric1=1) and (fnumeric2=1) and (fnumeric3=2)))
	and (_npairn=2) and (_npathn=1) and (_nothern=0)):
    save P,Q,v;
    pair P,Q; path v;
    P:=_t1; Q:=_t2; v:=_c1;
    if (issegment(v)):
      $:=abs(_angle(Q-P) - _angle(endpoint(v)-startingpoint(v)));
      if ($>180): $:=360-$; fi
      if ($>90):  $:=180-$; fi
      $
    else: errmessage "Illegal parameters for angle";
    fi
  else: errmessage "Illegal parameters for angle";
  fi
enddef;
%%-------------------------------------------------------
%% Punktid $A$, $B$, $C$.
%% Nurga $ABC$ suurus suunatud nurgana.
%% dirangle(A,B,C)

%% Punktid $A$, $B$, $C$, $D$.
%% Nurk kiire $AB$ suunast kiire $CD$ suunani.
%% dirangle(A,B,C,D)

%% Lõigud $l$ ja $m$.
%% Nurk lõigu $l$ suunast lõigu $m$ suunani.
%% dirangle(l,m)

%% Lõik $l$ ja punktid $A$, $B$.
%% Nurk lõigu $l$ suunas kiire $AB$ suunani (kiire $AB$ suunast
%% lõigu $l$ suunani).
%% dirangle(l,A,B)
%% dirangle(A,B,l)
%%-------------------------------------------------------
def dirangle(text t)=
begingroup
  save _npairn,_npathn,_nothern,_coco;
  _npairn:=0; _npathn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (picture _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn=3) and (_npathn=0) and (_nothern=0):
    save P,Q,R;
    pair P,Q,R;
    P:=_t1; Q:=_t2; R:=_t3;
    finddir(Q,P,Q,R)
  elseif (_npairn=4) and (_npathn=0) and (_nothern=0):
    save P,Q,R,S;
    pair P,Q,R,S;
    P:=_t1; Q:=_t2; R:=_t3; S:=_t4;
    finddir(P,Q,R,S)
  elseif (_npairn=0) and (_npathn=2) and (_nothern=0):
    save v,w;
    path v,w;
    v:=_c1; w:=_c2;
    if (issegment(v)) and (issegment(w)):
      finddir(startingpoint(v),endpoint(v),startingpoint(w),endpoint(w))
    else: errmessage "Illegal parameters for dirangle";
    fi
  elseif (fnumeric1=1) and (fnumeric2=1) and (fnumeric3=2)
	and (_npairn=2) and (_npathn=1) and (_nothern=0):
    save P,Q,v;
    pair P,Q; path v;
    P:=_t1; Q:=_t2; v:=_c1;
    if (issegment(v)):
      finddir(P,Q,startingpoint(v),endpoint(v))
    else: errmessage "Illegal parameters for dirangle";
    fi
  elseif (fnumeric1=2) and (fnumeric2=1) and (fnumeric3=1)
	and (_npairn=2) and (_npathn=1) and (_nothern=0):
    save P,Q,v;
    pair P,Q; path v;
    P:=_t1; Q:=_t2; v:=_c1;
    if (issegment(v)):
      finddir(startingpoint(v),endpoint(v),P,Q)
    else: errmessage "Illegal parameters for dirangle";
    fi
  else: errmessage "Illegal parameters for dirangle";
  fi
  endgroup
enddef;
%%-------------------------------------------------------
vardef finddir(expr a,b,c,d)=
  save $; numeric $;
  if (_angle(b-a)<0) and (_angle(d-c)>0):
    $:=_angle(d-c)-_angle(b-a);
    if ($>180): $:=$-360; fi
    $
  elseif (_angle(b-a)>0) and (_angle(d-c)<0):
    $:=_angle(d-c)-_angle(b-a);
    if ($<-180): $:=$+360; fi
    $
  else:
    $:=_angle(d-c)-_angle(b-a);
    $
  fi
enddef;
%%-------------------------------------------------------
%%%%=== Ringjoonte raadiused================================
%% Ringjoone raadius.
%% Ringjoon $c$.
%% Ringjoone raadius.
%% radius(c)
%%-------------------------------------------------------
vardef radius(expr a) =
  save $; numeric $;
  if iscircle(a) :
    $:=dist(center(a), .5[llcorner a, lrcorner a]);
    $
  elseif (pair a) :
    $:=64 * ((xpart a / 64) ++ (ypart a / 64));
    $
  else :
    errmessage "Illegal parameters for radius";
  fi
enddef;
%%-------------------------------------------------------
%% Kolmnurga ümberringjoone raadius.
%% Kolm punkti $A$, $B$, $C$.
%% Kolmnurga $ABC$ ümberringjoone raadius.
%% circumradius(A,B,C)
%% radius(circle(A,B,C))
%%-------------------------------------------------------
vardef circumradius(expr a,b,c) =
  save $; numeric $;
  if (pair a) and (pair b) and (pair c):
    $:=dist(a, circumcenter(a,b,c));
    $
  else: errmessage "Illegal parameters for circumradius";
  fi
enddef;
%%-------------------------------------------------------
%% Kolmnurga siseringjoone raadius.
%% Kolm punkti $A$, $B$, $C$.
%% Kolmnurga $ABC$ siseringjoone raadius.
%% inradius(A,B,C)
%%-------------------------------------------------------
vardef inradius(expr a, b, c) =
  save $,p; numeric $; pair p;
  if (pair a) and (pair b) and (pair c):
    p:=incenter(a,b,c);
    $:=dist (p,p Projected(a,b));
    $
  else: errmessage "Illegal parameters for inradius";
  fi
enddef;
%%-------------------------------------------------------
%% Kolmnurga külgringjoone raadius.
%% Kolm punkti $A$, $B$, $C$, järjekorranumber [$n$].
%% Kolmnurga $ABC$ järjekorras $n$-nda tipu vastas asuva
%% külgringjoone raadius.
%% exradius(A,B,C,1)
%% exradius(A,B,C,2)
%% exradius(A,B,C,3)
%% exradius(A,B,C)
%%-------------------------------------------------------
vardef exradius(text t)=
  save $,_npairn,_nnumericn,_nothern;
  numeric $; _npairn:=0; _nnumericn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=3) and (_nnumericn=1) and (_nothern=0):
      save P,Q,R,exc;
      pair P,Q,R,exc;
      P:=_t1; Q:=_t2; R:=_t3;
      if     (_n1=1): exc:=excenter(P,Q,R); $:=dist(exc,exc Projected(Q,R)); $
      elseif (_n1=2): exc:=excenter(Q,P,R); $:=dist(exc,exc Projected(P,R)); $
      elseif (_n1=3): exc:=excenter(R,P,Q); $:=dist(exc,exc Projected(P,Q)); $
      else: errmessage "Illegal parameters for exradius";
      fi
    elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
      save P,Q,R,exc;
      pair P,Q,R,exc;
      P:=_t1; Q:=_t2; R:=_t3;
      exc:=excenter(P,Q,R);
      $:=dist(exc,exc Projected(Q,R));
      $
    else: errmessage "Illegal parameters for exradius";
    fi
enddef;
%%-------------------------------------------------------
%%%%=== PUNKTID =================================================
%%%%=== Punkt polaarkoordinaatide järgi
%% Punkt polaarkoordinaatide järgi.
%% Poolus [$O$], raadius $r$ (võib olla negatiivne), punkt [$A$],
%%       nurk [$a$].
%% Punkt, mille polaarkoordinaadid pooluse $O$ ja polaartelje
%%       $OA$ suhtes on $(r,a)$.
%% polarpoint(O,r,A,a)
%% polarpoint(O,r,A)
%% polarpoint(O,r,a)
%% polarpoint(O,r)
%% polarpoint(r,A,a)
%% polarpoint(r,A)
%% polarpoint(r,a)
%% polarpoint(r)

%% Punkt ringjoonel.
%% Ringjoon $c$, punkt [$A$], nurk [$a$].}
%% Ringjoone $c$ punkt, mille polaarnurk ringjoone
%%           keskpunkti suhtes kiirest $OA$ alustades on $a$.
%% polarpoint(c,A,a)
%% polarpoint(c,A)
%% polarpoint(c,a)
%% polarpoint(c)
%%-------------------------------------------------------
vardef polarpoint(text t)=
  save $,_npairn,_npathn,_nnumericn,_nothern,_coco;
  pair $; _npairn:=0; _npathn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    else:                     fnumeric[_coco]:=4;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=1) and (_nnumericn=2) and (_nothern=0) and (fnumeric2=1):
      save r,A,a;
      pair A;
      numeric r,a;
      A:=_t1; r:=_n1; a:=_n2;
      $:=(r,0) rotated (angle(A)+a);
      $
    elseif (_npairn=0) and (_nnumericn=2) and (_nothern=0):
      save r,a;
      numeric r,a;
      r:=_n1; a:=_n2;
      $:=(r,0) rotated a;
      $
    elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1):
      save O,r;
      pair O;
      numeric r;
      O:=_t1; r:=_n1;
      $:=(r,0) shifted O;
      $
    elseif (_npairn=0) and (_npathn=1) and (_nnumericn=0) and (_nothern=0):
      save c;
      path c;
      c:=_c1;
      if (iscircle(c)):
        $:=center(c) shifted (radius(c),0);
        $
      else: errmessage "Illegal parameters for polarpoint";
      fi
    elseif (_npairn=0) and (_npathn=1) and (_nnumericn=1) and (_nothern=0):
      save c,a;
      path c;
      numeric a;
      c:=_c1; a:=_n1;
      if (iscircle(c)):
        $:=(radius(c),0) rotated a shifted center(c);
        $
      else: errmessage "Illegal parameters for polarpoint";
      fi
    elseif (_npairn=1) and (_npathn=1) and (_nnumericn=0) and (_nothern=0) and (fnumeric2=1):
      save c,A;
      pair A;
      path c;
      A:=_t1; c:=_c1;
      if (iscircle(c)):
        $:=(radius(c),0) rotated angle(A-center(c)) shifted center(c);
        $
      else: errmessage "Illegal parameters for polarpoint";
      fi
    elseif (_npairn=1) and (_npathn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=2) and (fnumeric2=1):
      save c,A,a;
      pair A;
      path c;
      numeric a;
      A:=_t1; c:=_c1; a:=_n1;
      if (iscircle(c)):
        $:=(radius(c),0) rotated (a+angle(A-center(c))) shifted center(c);
        $
      else: errmessage "Illegal parameters for polarpoint";
      fi
    elseif (_npairn=0) and (_nnumericn=1) and (_nothern=0):
      save r;
      numeric r;
      r:=_n1;
      $:=(r,0);
      $
    elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric2=1):
      save A,r;
      pair A;
      numeric r;
      A:=_t1; r:=_n1;
      $:=(r,0) rotated angle(A);
      $
    elseif (_npairn=2) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1):
      save O,r,A;
      pair O,A;
      numeric r;
      O:=_t1; A:=_t2; r:=_n1;
      $:=(r,0) rotated angle(A-O) shifted O;
      $
    elseif (_npairn=2) and (_nnumericn=2) and (_nothern=0) and (fnumeric1=1) and (fnumeric3=1):
      save O,r,A,a;
      pair O,A;
      numeric r,a;
      O:=_t1; A:=_t2; r:=_n1; a:=_n2;
      $:=(r,0) rotated (angle(A-O)+a) shifted O;
      $
    elseif (_npairn=1) and (_nnumericn=2) and (_nothern=0) and (fnumeric1=1):
      save O,r,a;
      pair O;
      numeric r,a;
      O:=_t1; r:=_n1; a:=_n2;
      $:=(r,0) rotated a shifted O;
      $
    else: errmessage "Illegal parameters for polarpoint";
    fi
enddef;
%%-------------------------------------------------------
%%%%=== Kolmnurga tipu konstrueerimine
%%  Üldkujuline kolmnurk.
%%  Tipp A ja tema juures nurk a v~oi küljepikkus x, tipp B
%%     ja tema juures nurk b v~oi küljepikkus y, järjekorranumber [n].
%%  Kolmnurga kolmas tipp C nii, et 6 CAB = a, 6 CBA = b,
%%     |AC| = x, |BC| = y. Kui ühe tipu juures on antud nurk ja
%%     teise juures külg, siis näitab n nurgaga tipu juures tipu C
%%     v~oimaliku asukoha järjekorranumbrit nurgaga tipust alates.
% triangle(A,a)(B,b)
% triangle(x,A)(B,b)
% triangle(x,A)(B,b,1)
% triangle(x,A)(B,b,2)
% triangle(A,a)(y,B)
% triangle(A,a,1)(y,B)
% triangle(A,a,2)(y,B)
% triangle(x,A)(y,B)

%Selleks, et eristada nurga suurust küljepikkusest, kirjutatakse küljepikkus alati enne ja nurga suurus pärast tipu tähist.
%Antud Tipp A ja tema juures nurk a, küljepikkus x, kordaja [k] v~oi tipp B ja tema juures nurk b, küljepikkus y, kordaja [l].
%Tulemus Kolmnurga kolmas tipp C, mille korral 6 CAB = a, |AC| = x v~oi 6 CBA = b, |BC| = y. Kui on antud kordaja k v~oi l, siis lähtutakse külje AB punktist, mis jääb külje vastavast otspunktist k v~oi l osa v~orra küljepikkusest teise otspunkti poole.

% triangle(x,A,a,k)(B)
% triangle(x,A,a)(B)
% triangle(A)(y,B,b,l)
% triangle(A)(y,B,b)
%%-------------------------------------------------------
vardef arcsind primary x = angle((1+-+x,x)) enddef;
%%-------------------------------------------------------
vardef triangle(text t)(text d)=
  save $,_npairn,_nnumericn,_nothern,_coco;
  save   _dpairn,_dnumericn,_dothern,_dcoco;
  pair $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;
          _dpairn:=0; _dnumericn:=0; _dothern:=0; _dcoco:=0;
  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (numeric _stexts): fnumeric[_coco]:=2;
    else:                     fnumeric[_coco]:=3;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  for _dtexts=d:
    _dcoco:=_dcoco+1;
    if     (pair _dtexts):    dnumeric[_dcoco]:=1;
    elseif (numeric _dtexts): dnumeric[_dcoco]:=2;
    else:                     dnumeric[_dcoco]:=3;
    fi

    if (pair _dtexts): _dpairn:=_dpairn+1; _tt[_dpairn]:=_dtexts;
    elseif (numeric _dtexts): _dnumericn:=_dnumericn+1; _nn[_dnumericn]:=_dtexts;
    else: _dothern:=_dothern+1;
    fi
  endfor;

  if (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1) and
     (_dpairn=1) and (_dnumericn=1) and (_dothern=0) and (dnumeric1=1):
    save A,a,B,b;
    pair A,B;
    numeric a,b;
    A:=_t1; a:=_n1; B:=_tt1; b:=_nn1;
    if (abs(a)<>0) and (abs(b)<>0) and (dist(A,B)>0):
      $:=whatever[A,polarpoint(A,1,B,a)]=whatever[B,polarpoint(B,1,A,-b)];
      $
    else: errmessage "Illegal parameters for triangle";
    fi
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=2) and
         (_dpairn=1) and (_dnumericn=1) and (_dothern=0) and (dnumeric1=1):
    save x,A,B,b ,c;
    pair A,B;
    numeric x,b,c;
    A:=_t1; x:=_n1; B:=_tt1; b:=_nn1;
    c:=(dist(A,B)/x)*(sind b);
    if (b<>0) and (dist(A,B)>0) and (x>0) and (abs(c)<=1):
      $:=polarpoint(A,x,B,180-b-(180-arcsind c));
      $
    else: errmessage "Illegal parameters for triangle";
    fi
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and
         (_dpairn=1) and (_dnumericn=2) and (_dothern=0):
    save x,A,B,b,n ,c;
    pair A,B;
    numeric x,b,n,c;
    A:=_t1; x:=_n1; B:=_tt1; b:=_nn1; n:=_nn2;
    c:=(dist(A,B)/x)*(sind b);
    if (b<>0) and (dist(A,B)>0) and (x>0) and (abs(c)<=1) and (n=1):
      $:=polarpoint(A,x,B,180-b-(180-arcsind c));
      $
    elseif (b<>0) and (abs(b)<180) and (dist(A,B)>0) and (x>0) and (abs(c)<=1) and (n=2):
      $:=polarpoint(A,x,B,(180-b-arcsind c));
      $
    else: errmessage "Illegal parameters for triangle";
    fi
  elseif (_npairn=1) and (_nnumericn=2) and (_nothern=0) and
         (_dpairn=1) and (_dnumericn=0) and (_dothern=0):
    save x,A,a,B;
    pair A,B;
    numeric x,a;
    A:=_t1; x:=_n1; B:=_tt1; a:=_n2;
    if (a<>0) and (dist(A,B)>0) and (x>0) :
      $:=polarpoint(A,x,B,a);
      $
    else: errmessage "Illegal parameters for triangle";
    fi
  elseif (_npairn=1) and (_nnumericn=3) and (_nothern=0) and
         (_dpairn=1) and (_dnumericn=0) and (_dothern=0):
    save x,A,a,k,B;
    pair A,B;
    numeric x,a,k;
    A:=_t1; x:=_n1; a:=_n2; k:=_n3; B:=_tt1;
    if (a<>0) and (dist(A,B)>0) and (x>0):
      $:=polarpoint((A+k*(B-A)),x,B,a);
      $
    else: errmessage "Illegal parameters for triangle";
    fi
  elseif (_npairn=1) and (_nnumericn=0) and (_nothern=0) and
         (_dpairn=1) and (_dnumericn=3) and (_dothern=0):
    save A,y,B,b,l;
    pair A,B;
    numeric y,b,l;
    A:=_t1; y:=_nn1; b:=_nn2; l:=_nn3; B:=_tt1;
    if (b<>0) and (dist(A,B)>0) and (y>0):
      $:=polarpoint((B+l*(A-B)),y,A,-b);
      $
    else: errmessage "Illegal parameters for triangle";
    fi
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1) and
         (_dpairn=1) and (_dnumericn=1) and (_dothern=0) and (dnumeric2=1):
    save A,a,y,B ,c;
    pair A,B;
    numeric a,y,c;
    A:=_t1; a:=_n1; B:=_tt1; y:=_nn1;
    c:=(dist(A,B)/y)*(sind a);
    if (a<>0) and (dist(A,B)>0) and (y>0) and (abs(c)<=1):
      $:=polarpoint(B,y,A,-1*(180-a-(180-arcsind c)));
      $
    else: errmessage "Illegal parameters for triangle";
    fi
  elseif (_npairn=1) and (_nnumericn=2) and (_nothern=0) and
         (_dpairn=1) and (_dnumericn=1) and (_dothern=0):
    save A,a,n,y,B ,c;
    pair A,B;
    numeric a,n,y,c;
    A:=_t1; a:=_n1; n:=_n2; B:=_tt1; y:=_nn1;
    c:=(dist(A,B)/y)*(sind a);
    if (a<>0) and (dist(A,B)>0) and (y>0) and (abs(c)<=1) and (n=1):
      $:=polarpoint(B,y,A,-1*(180-a-(180-arcsind c)));
      $
    elseif (a<>0) and (dist(A,B)>0) and (y>0) and (abs(c)<=1) and (n=2):
      $:=polarpoint(B,y,A,-1*(180-a-arcsind c));
      $
    else: errmessage "Illegal parameters for triangle";
    fi
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=2) and
         (_dpairn=1) and (_dnumericn=1) and (_dothern=0) and (dnumeric1=2):
    save x,A,y,B;
    pair A,B;
    numeric x,y;
    A:=_t1; x:=_n1; B:=_tt1; y:=_nn1;
    if (x>0) and (dist(A,B)>0) and (y>0):
      $:=intersection(circle(A,x),circle(B,y),2);
      $
    else: errmessage "Illegal parameters for triangle";
    fi
  elseif (_npairn=1) and (_nnumericn=0) and (_nothern=0) and
         (_dpairn=1) and (_dnumericn=2) and (_dothern=0) :
    save A,y,B,b;
    pair A,B;
    numeric x,a;
    A:=_t1; y:=_nn1; B:=_tt1; b:=_nn2;
    if (b<>0) and (dist(A,B)>0) and (y>0) :
      $:=polarpoint(B,y,A,-b);
      $
    else: errmessage "Illegal parameters for triangle";
    fi
  else: errmessage "Illegal parameters for triangle";
  fi
enddef;
%%-------------------------------------------------------
% V~ordhaarne kolmnurk.
% Tipud A ja B, alusnurk a v~oi haara pikkus x.
% Kolmnurga kolmas tipp C nii, et 6 CAB = 6 CBA = a ja |AC| = |BC| = x.
% isosceles(x,A)(B)
% isosceles(A,a)(B)
% isosceles(A)(x,B)
% isosceles(A)(B,a)
%%-------------------------------------------------------
vardef isosceles(text t)(text d)=
  save $,_npairn,_nnumericn,_nothern,_coco;
  save   _dpairn,_dnumericn,_dothern,_dcoco;
  pair $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;
          _dpairn:=0; _dnumericn:=0; _dothern:=0; _dcoco:=0;
  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (numeric _stexts): fnumeric[_coco]:=2;
    else:                     fnumeric[_coco]:=3;
    fi

    if (pair _stexts):
      _npairn:=_npairn+1;
      _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  for _dtexts=d:
    _dcoco:=_dcoco+1;
    if     (pair _dtexts):    dnumeric[_dcoco]:=1;
    elseif (numeric _dtexts): dnumeric[_dcoco]:=2;
    else:                     dnumeric[_dcoco]:=3;
    fi

    if (pair _dtexts): _dpairn:=_dpairn+1; _tt[_dpairn]:=_dtexts;
    elseif (numeric _dtexts): _dnumericn:=_dnumericn+1; _nn[_dnumericn]:=_dtexts;
    else: _dothern:=_dothern+1;
    fi
  endfor;

  if (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric2=1) and
     (_dpairn=1) and (_dnumericn=0) and (_dothern=0):
    save x,A,B;
    pair A,B;
    numeric x;
    A:=_t1; x:=_n1; B:=_tt1;
    if (x>0) and (dist(A,B)>0):
      $:=triangle(.5[A,B],90,2)(x,B);
      $
    else: errmessage "Illegal arguments for isosceles";
    fi
  elseif (_npairn=1) and (_nnumericn=0) and (_nothern=0) and
     (_dpairn=1) and (_dnumericn=1) and (_dothern=0) and (dnumeric2=1):
    save A,y,B;
    pair A,B;
    numeric y;
    A:=_t1; y:=_nn1; B:=_tt1;
    if (y>0) and (dist(A,B)>0):
      $:=triangle(.5[A,B],90,2)(y,B);
      $
    else: errmessage "Illegal arguments for isosceles";
    fi
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1) and
         (_dpairn=1) and (_dnumericn=0) and (_dothern=0):
    save A,a,B;
    pair A,B;
    numeric a;
    A:=_t1; a:=_n1; B:=_tt1;
    if (a<>0) and (abs(a)<180) and (dist(A,B)>0):
      $:=triangle(A,a)(B,a);
      $
    else: errmessage "Illegal arguments for isosceles";
    fi
  elseif (_npairn=1) and (_nnumericn=0) and (_nothern=0) and
         (_dpairn=1) and (_dnumericn=1) and (_dothern=0) and (dnumeric1=1):
    save A,B,b;
    pair A,B;
    numeric b;
    A:=_t1; b:=_nn1; B:=_tt1;
    if (b<>0) and (abs(b)<180) and (dist(A,B)>0):
      $:=triangle(A,b)(B,b);
      $
    else: errmessage "Illegal arguments for isosceles";
    fi
  else: errmessage "Illegal arguments for isosceles";
  fi
enddef;
%%-------------------------------------------------------
%  Täisnurkne kolmnurk.
% Tipud A ja B, kaateti ja hüpotenuusi vaheline nurk a v~oi kaateti pikkus x.
% Kolmnurga kolmas tipp C nii, et 6 ACB = 90? ning vastavast tipust lähtuva kaateti nurk on a v~oi pikkus x.
% righttriangle(x,A)(B)
% righttriangle(A,a)(B)
% righttriangle(A)(x,B)
% righttriangle(A)(B,x)
%%-------------------------------------------------------
vardef pytminus(expr a, b)=
  save $; numeric $;
  if (a>=b): $:=64*((a/64)+-+(b/64)); $
  else: $:=64*((b/64)+-+(a/64)); $
  fi
enddef;
%%-------------------------------------------------------
vardef righttriangle(text t)(text d)=
  save $,_npairn,_nnumericn,_nothern,_coco;
  save   _dpairn,_dnumericn,_dothern,_dcoco;
  pair $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;
          _dpairn:=0; _dnumericn:=0; _dothern:=0; _dcoco:=0;
  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (numeric _stexts): fnumeric[_coco]:=2;
    else:                     fnumeric[_coco]:=3;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  for _dtexts=d:
    _dcoco:=_dcoco+1;
    if     (pair _dtexts):    dnumeric[_dcoco]:=1;
    elseif (numeric _dtexts): dnumeric[_dcoco]:=2;
    else:                     dnumeric[_dcoco]:=3;
    fi

    if (pair _dtexts):
      _dpairn:=_dpairn+1;
      _tt[_dpairn]:=_dtexts;
    elseif (numeric _dtexts): _dnumericn:=_dnumericn+1; _nn[_dnumericn]:=_dtexts;
    else: _dothern:=_dothern+1;
    fi
  endfor;

  if (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric2=1) and
     (_dpairn=1) and (_dnumericn=0) and (_dothern=0):
    save x,A,B;
    pair A,B;
    numeric x;
    A:=_t1; x:=_n1; B:=_tt1;
    if (dist(A,B)>0) and (x<dist(A,B)) and (x>0):
      $:=triangle(x,A,)(pytminus(dist(A,B),x),B);
      $
    else: errmessage "Argument x must be positive and less than length of AB";
    fi
  elseif (_npairn=1) and (_nnumericn=0) and (_nothern=0) and
     (_dpairn=1) and (_dnumericn=1) and (_dothern=0) and (dnumeric2=1):
    save A,y,B;
    pair A,B;
    numeric y;
    A:=_t1; y:=_nn1; B:=_tt1;
    if (dist(A,B)>0) and (y<dist(A,B)) and (y>0):
      $:=triangle(pytminus(dist(A,B),y),A)(y,B);
      $
    else: errmessage "Argument y must be positive and less than length of AB";
    fi
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1) and
         (_dpairn=1) and (_dnumericn=0) and (_dothern=0):
    save A,a,B;
    pair A,B;
    numeric a;
    A:=_t1; a:=_n1; B:=_tt1;
    if (dist(A,B)>0) and (a>0) and (a<90):
      $:=triangle(A,a)(B,90-a);
      $
    elseif (dist(A,B)>0) and (a<0) and (a>-90):
      $:=triangle(A,a)(B,-90-a);
      $
    else: errmessage "Argument a must be between -90 and 0 or between 0 and 90 degrees";
    fi
  elseif (_npairn=1) and (_nnumericn=0) and (_nothern=0) and
         (_dpairn=1) and (_dnumericn=1) and (_dothern=0) and (dnumeric1=1):
    save A,B,b;
    pair A,B;
    numeric b;
    A:=_t1; b:=_nn1; B:=_tt1;
    if (dist(A,B)>0) and (b>0) and (b<90):
      $:=triangle(A,90-b)(B,b);
      $
    elseif (dist(A,B)>0) and (b<0) and (b>-90):
      $:=triangle(A,-90-b)(B,b);
      $
    else: errmessage "Argument b must be between -90 and 0 or between 0 and 90 degrees";
    fi
  else: errmessage "Illegal arguments for righttriangle";
  fi
enddef;
%%-------------------------------------------------------
% V~ordkülgne kolmnurk.
% Tipud A ja B.
% Kolmnurga kolmas tipp C nii, et ABC on v~ordkülgne.
% equilateral(A)(B)
%%-------------------------------------------------------
vardef equilateral(expr A,B)=
  if (pair(A)) and (pair(B)):
    save $; pair $;
    $:=polarpoint(A,dist(A,B),B,60);
    $
  else: errmessage "Illegal arguments for equilateral";
  fi
enddef;
%%-------------------------------------------------------
% Hulknurga tipu konstrueerimine
%
%  Rööpküliku neljas tipp kolme tipu järgi.
%  Kolm punkti $A$, $B$, $C$.}
%  Punkt $D$, mille korral $ABCD$ on rööpkülik.
%  parallelogram(A,B,C)
%%-------------------------------------------------------
vardef parallelogram (expr a, b, c) =
  save $; pair $;
  if (pair a) and (pair b) and (pair c): $:=a+c-b; $
  else: errmessage "Illegal arguments for parallelogram";
  fi
enddef;
%%-------------------------------------------------------
% Massikese.
% Punkt P1, mass [m1], punkt P2, mass [m2], . . . , punkt Pn, mass [mn].
% Punktisüsteemi P1, P2, . . . , Pn massikese.
% barycenter(P1,m1,P2,m2,...,Pn,mn)
% barycenter(P1,P2,...,Pn)
%%-------------------------------------------------------
vardef barycenter(text t) =
  save $,_npairn,_nnumericn,_nothern;
  pair $; _npairn:=0; _nnumericn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts):
      _npairn:=_npairn+1;
      _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn>0) and (_nnumericn=0) and (_nothern=0):
    $:=origin;
    for i=1 upto _npairn:
      $:=$+_t[i];
    endfor;
    $:=$/_npairn;
    $
  elseif (_npairn>0) and (_nnumericn>0) and (_npairn=_nnumericn) and (_nothern=0):
    save wsum; wsum:=0;
    $:=origin;
    for i=1 upto _npairn:
      $:=$+_t[i]*_n[i];
      wsum:=wsum+_n[i];
    endfor;
    $:=$/wsum;
    $
  else: errmessage "Illegal arguments for barycenter";
  fi
enddef;
%%-------------------------------------------------------
%% Sirge või ringjoonega seotud punktid
%  Lõigu otspunktid.
%  Lõik (või suvaline lahtine joon) $l$.
%  Lõigu $l$ alguspunkt.
%  startingpoint(l)
%%-------------------------------------------------------
vardef startingpoint(expr a)=
  save $; pair $;
  if (path a): $:=point 0 of a; $
  else: errmessage "Illegal arguments for startingpoint";
  fi
enddef;
%%-------------------------------------------------------
%  Lõik (või suvaline lahtine joon) $l$.
%  Lõigu $l$ lõpp-punkt.
%  endpoint(l)
%%-------------------------------------------------------
vardef endpoint(expr a)=
  save $; pair $;
  if (path a): $:=point length(a) of a; $
  else: errmessage "Illegal arguments for endpoint";
  fi
enddef;
%%-------------------------------------------------------
%  Lõigu keskpunkt.
%  Kaks punkti $A$ ja $B$.
%  Lõigu $AB$ keskpunkt.
%  midpoint(A,B)

%  Lõik (või suvaline lahtine joon) $l$.
%  Lõigu $l$ keskpunkt.
%  midpoint(l)
%%-------------------------------------------------------
vardef midpoint(text t)=
  save $,_npairn,_npathn,_nothern;
  pair $; _npairn:=0; _npathn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif iscircle(_stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    elseif (path _stexts) and (not (cycle _stexts)): _npathn:=_npathn+1;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=2) and (_npathn=0) and (_nothern=0):
      save P,Q;
      pair P,Q;
      P:=_t1; Q:=_t2;
      $:=.5[P,Q]; % case: midpoint(A,B)
      $
    elseif (_npairn=0) and (_npathn=1) and (_nothern=0):
      $:=point (arctime (arclength t)/2 of t) of t; % case: midpoint(path) - joone keskpunkt
      $
    else: errmessage "Illegal parameters for midpoint";
    fi
enddef;
%%-------------------------------------------------------
%  Ringjoone keskpunkt.
%  Ringjoon $c$.
%  Ringjoone keskpunkt.
%  center(c)
%%-------------------------------------------------------
vardef center(text t)=
  save $,_npairn,_npathn,_nothern;
  pair $; _npairn:=0; _npathn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts):
      _npairn:=_npairn+1;
      _t[_npairn]:=_stexts;   % Probleem: paht, pen ja picture ???
    elseif (path _stexts) or (pen _stexts) or (picture _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=0) and (_npathn=1) and (_nothern=0):
      save w;
      path w;
      w:=_c1;
      $:=.5[llcorner w, urcorner w]; % case: MetaPost center
      $
    elseif (_npairn=2) and (_npathn=0) and (_nothern=0):
      save P,Q;
      pair P,Q;
      P:=_t1; Q:=_t2;
      $:=.5[P,Q]; % case: center(point,point)
      $
    else: errmessage "Illegal parameters for center";
    fi
enddef;
%%-------------------------------------------------------
%%%% Kolmnurgaga seotud punktid ====================
%%  Kolmnurga ümberringjoone keskpunkt.
%%  Kolm punkti $A$, $B$, $C$.}
%%  Kolmnurga $ABC$ ümberringjoone keskpunkt.
%%  circumcenter(A,B,C)
%%  center(circle(A,B,C))
%%-------------------------------------------------------
vardef circumcenter(expr a, b ,c) =
    save $; pair $;
    if (pair a) and (pair b) and (pair c):
      $ - .5[a,b] = whatever * (b-a) rotated 90;
      $ - .5[b,c] = whatever * (c-b) rotated 90;
      $
    else: errmessage "Illegal parameters for mycircumcenter";
    fi
enddef;
%%-------------------------------------------------------
%%  Kolmnurga siseringjoone keskpunkt ehk nurgapoolitajate
%%        lõikepunkt.
%%  Kolm punkti $A$, $B$, $C$.
%%  Kolmnurga $ABC$ siseringjoone keskpunkt.
%%  incenter(A,B,C)
%%-------------------------------------------------------
vardef incenter(expr A,B,C)=
  save $,a,b,c; numeric a,b,c; pair $;
  if (pair A) and (pair B) and (pair C):
    a := dist(B,C); b := dist(C,A); c := dist(A,B);
    $:=a/(a+b+c)*A+b/(a+b+c)*B+c/(a+b+c)*C;
    $
  else: errmessage "Illegal parameters for incenter";
  fi
enddef;
%%-------------------------------------------------------
%  Kolmnurga külgringjoone keskpunkt.
%  Kolm punkti $A$, $B$, $C$, järjekorranumber [$n$].
%  Kolmnurga $ABC$ järjekorras $n$-nda tipu vastas asuva
%         külgringjoone keskpunkt.
%  excenter(A,B,C,1)
%  excenter(A,B,C)}
%%-------------------------------------------------------
vardef excenter(text t) =
  save $,_npairn,_nnumericn,_nothern;
  pair $; _npairn:=0; _nnumericn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=3) and (_nnumericn=1) and (_nothern=0):
      save P,Q,R,I,n;
      pair P,Q,R,I;
      numeric n;
      P:=_t1; Q:=_t2; R:=_t3; I:=incenter(P,Q,R); n:=_n1;
      if     (n=1): $:=whatever[I rotatedaround (Q,90),Q]=whatever[I rotatedaround (R,90),R]; $
      elseif (n=2): $:=whatever[I rotatedaround (P,90),P]=whatever[I rotatedaround (R,90),R]; $
      elseif (n=3): $:=whatever[I rotatedaround (P,90),P]=whatever[I rotatedaround (Q,90),Q]; $
      else: errmessage "Illegal parameters for excenter";
      fi
    elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
      save P,Q,R,I;
      pair P,Q,R,I;
      P:=_t1; Q:=_t2; R:=_t3; I:=incenter(P,Q,R);
      $:=whatever[I rotatedaround (Q,90),Q]=whatever[I rotatedaround (R,90),R];
      $
    else: errmessage "Illegal parameters for excenter";
    fi
enddef;
%%-------------------------------------------------------
%  Kolmnurga mediaanide lõikepunkt.
%  Kolm punkti $A$, $B$, $C$.
%  Kolmnurga $ABC$ mediaanide lõikepunkt.
%  mediancenter(A,B,C)
%%-------------------------------------------------------
vardef mediancenter(expr a, b, c) =
  save $; pair $;
  if (pair a) and (pair b) and (pair c): $:=(a+b+c)/3; $
  else: errmessage "Illegal arguments for mediancenter";
  fi
enddef;
%%-------------------------------------------------------
%  Kolmnurga kõrguste lõikepunkt.
%  Kolm punkti $A$, $B$, $C$.
%  Kolmnurga $ABC$ kõrguste lõikepunkt.
%  orthocenter(A,B,C)
%%-------------------------------------------------------
vardef orthocenter(expr a, b, c) =
  save $,O; pair $,O;
  if (pair a) and (pair b) and (pair c):
    O:=circumcenter(A,B,C);
    ($-O)=(A-O)+(B-O)+(C-O);
    $
  else: errmessage "Illegal arguments for orthocenter";
  fi
enddef;
%%-------------------------------------------------------
%  Mediaani aluspunkt.
%  Kolm punkti $A$, $B$, $C$, järjekorranumber [$n$].
%  Kolmnurga $ABC$ $n$-ndast tipust vastasküljele tõmmatud
%         mediaani aluspunkt.
%  medianfoot(A,B,C,1)
%  medianfoot(A,B,C)
%%-------------------------------------------------------
vardef medianfoot(text t)=
  save $,_npairn,_nnumericn,_nothern;
  pair $; _npairn:=0; _nnumericn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=3) and (_nnumericn=1) and (_nothern=0):
      save P,Q,R,n;
      pair P,Q,R;
      numeric n;
      P:=_t1; Q:=_t2; R:=_t3; n:=_n1;
      if     (n=1): $:=.5[Q,R]; $
      elseif (n=2): $:=.5[P,R]; $
      elseif (n=3): $:=.5[P,Q]; $
      else: errmessage "Illegal parameters for medianfoot";
      fi
    elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
      save P,Q,R;
      pair P,Q,R;
      P:=_t1; Q:=_t2; R:=_t3;
      $:=.5[Q,R];
      $
    else: errmessage "Illegal parameters for medianfoot";
    fi
enddef;
%%-------------------------------------------------------
%  Kõrguse aluspunkt.
%  Kolm punkti $A$, $B$, $C$.}
%  Kolmnurga $ABC$ $n$-ndast tipust vastasküljele tõmmatud kõrguse
%         aluspunkt; isegi juhul, kui see asub kolmnurgast $ABC$ väljas.
%  heightfoot(A,B,C,1)
%  heightfoot(A,B,C)
%%-------------------------------------------------------
vardef heightfoot(text t)=
  save $,_npairn,_nnumericn,_nothern;
  pair $; _npairn:=0; _nnumericn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=3) and (_nnumericn=1) and (_nothern=0):
      save P,Q,R,n;
      pair P,Q,R;
      numeric n;
      P:=_t1; Q:=_t2; R:=_t3; n:=_n1;
      if     (n=1): $:=P Projected(Q,R); $
      elseif (n=2): $:=Q Projected(P,R); $
      elseif (n=3): $:=R Projected(P,Q); $
      else: errmessage "Illegal parameters for heightfoot";
      fi
    elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
      save P,Q,R;
      pair P,Q,R;
      P:=_t1; Q:=_t2; R:=_t3;
      $:=P Projected(Q,R);
      $
    else: errmessage "Illegal parameters for heightfoot";
    fi
enddef;
%%-------------------------------------------------------
%  Nurgapoolitaja aluspunkt.
%  Kolm punkti $A$, $B$, $C$.
%  Kolmnurga $ABC$ $n$-ndast tipust vastasküljele $BC$ tõmmatud
%         nurgapoolitaja aluspunkt.
%  bisectorfoot(A,B,C,1)
%  anglebisectorfoot(A,B,C,1)
%  bisectorfoot(A,B,C)
%%-------------------------------------------------------
vardef bisectorfoot(text t)=
save $,_npairn,_nnumericn,_nothern;
  pair $; _npairn:=0; _nnumericn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=3) and (_nnumericn=1) and (_nothern=0):
      save P,Q,R,n;
      pair P,Q,R;
      numeric n;
      P:=_t1; Q:=_t2; R:=_t3; n:=_n1;
      if     (n=1): $:=whatever[incenter(P,Q,R),P]=whatever[Q,R]; $
      elseif (n=2): $:=whatever[incenter(P,Q,R),Q]=whatever[Q,R]; $
      elseif (n=3): $:=whatever[incenter(P,Q,R),R),_t1]=whatever[Q,R]; $
      else: errmessage "Illegal parameters for heightfoot";
      fi
    elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
      save P,Q,R;
      pair P,Q,R;
      P:=_t1; Q:=_t2; R:=_t3;
      $:=whatever[incenter(P,Q,R),P]=whatever[Q,R];
      $
    else: errmessage "Illegal parameters for bisectorfoot";
    fi
enddef;
%%-------------------------------------------------------
def anglebisectorfoot = bisectorfoot enddef;
%%-------------------------------------------------------
%%%% Lõikepunktid =======================================
%  Kahe sirge lõikepunkt.
%  Punktid $A$, $B$, $C$, $D$.
%  Sirgete $AB$ ja $CD$ lõikpunkt (isegi kui see ei asu lõikudel
%         $AB$ või $CD$).
%  intersection(A,B,C,D)

%  Punktid $A$, $B$, lõik $l$.
%  Sirge $AB$ ja lõigu $l$ lõikpunkt (isegi kui see ei asu antud joontel
%         $AB$ või $l$).
%  intersection(A,B,l)

%  Lõigud $l_1$, $l_2$.
%  Lõikude $l_1$ ja $l_2$ lõikpunkt (isegi kui see ei asu antud lõikudel
%         $l_1$ või $l_2$).
%  intersection(l1,l2)

%  Sirge ja ringjoone lõikepunktid.
%  Punktid $A$ ja $B$ ning ringjoon $c$, järjekorranumber [$n$].
%  Sirge $AB$ ja ringjoone $c$ järjekorras $n$-s lõikepunkt sirge
%         suuna mõttes; suund sirgel määratakse punktide $A$ ja $B$
%         järjekorraga.
%   intersection(c,A,B,1)
%   intersection(c,A,B,2)
%   intersection(A,B,c,1)
%   intersection(A,B,c,2)
%   intersection(c,A,B)
%   intersection(A,B,c)

%  Kahe ringjoone lõikepunktid.
%  Ringjooned $c_1$ ja $c_2$, järjekorranumber [$n$].
%  Ringjoonte $c_1$ ja $c_2$ järjekorras $n$-s lõikepunkt
%         ringjoone $c_1$ kaarel, mis jääb ringjoone $c_2$ sisse. Kaare
%         suunda loetakse vastupäeva.
%  intersection(c1,c2,1)
%  intersection(c1,c2,2)
%  intersection(c1,c2)
%%-------------------------------------------------------
vardef intersection(text t)=
  save $,_npairn,_npathn,_nnumericn,_nothern,_coco;
  pair $; _npairn:=0; _npathn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    else:                     fnumeric[_coco]:=4;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=4) and (_nnumericn=0) and (_nothern=0):
      save A,B,C,D;
      pair A,B,C,D;
      A:=_t1; B:=_t2; C:=_t3; D:=_t4;
      if (A<>B) and (C<>D):
        if (dist(C,A,B)<>dist(D,A,B)):
          $:=whatever[A,B]=whatever[C,D];
          $
        else: errmessage "The given lines do not intersect";
        fi
      else: errmessage "Can't construct two lines";
      fi
    elseif (_npairn=2) and (_npathn=1) and (_nnumericn<=1) and (_nothern=0):
      save d,A,B,mid,ad,c;
      pair A,B,mid,ad;
      path c;
      numeric d;
      A:=_t1; B:=_t2; c:=_c1;
      if (iscircle(c)):
        if (A<>B) and (dist(center(c),A,B)<=radius(c)+0.0009):
          d:=dist(center(c),A,B);
          mid:=center(c) Projected(A,B);
          ad:=pytminus(radius(c), dist(center(c),mid)) / (radius(B-A)) * (A-B);
          $:=mid if (_nnumericn=0) : +
	         elseif (_n1 mod 2 = 1) : +
	         else : -
	         fi
  	       ad;
          $
        else: errmessage "The circle and line do not intersect";
        fi
      elseif (issegment(c)):
        $:=intersection(A,B,startingpoint(c),endpoint(c));
        $
      else: errmessage "Illegal arguments for intersection";
      fi
    elseif (_npairn=0) and (_npathn=2) and (_nnumericn=0) and (_nothern=0):
      save p,b,a,mid,ca,cb;
      pair p,b,mid;
      path ca,cb;
      numeric a;
      ca:=_c1; cb:=_c2;
      if (iscircle(ca)) and (iscircle(cb)):
        if (dist(center(ca),center(cb))<=(radius(ca)+radius(cb))):
          p:=ca intersectionpoint cb;
          b:=p Reflected(center(ca),center(cb));
          a:=(dirangle(b,center(ca),p));
          if (a<0): a:=(a+360)/2
          else: a:=a/2
          fi;
          mid:=polarpoint(center(ca),radius(ca),b,a);
          $:=if (dist(center(cb),mid) < radius(cb)): b
             else: p
	           fi;
          $
  	    else: errmessage "Illegal argument for intersection";
	      fi
      elseif (issegment(ca)) and (issegment(cb)):
        $:=intersection(startingpoint(ca),endpoint(ca),startingpoint(cb),endpoint(cb));
        $
      else: errmessage "Illegal argument for intersection";
      fi
    elseif (_npairn=0) and (_npathn=2) and (_nnumericn=1) and (_nothern=0) and (fnumeric3=3):
      save p,b,a,mid,ca,cb,nr;
      pair p,b,mid;
      path ca,cb;
      numeric a,nr;
      ca:=_c1; cb:=_c2; nr:=_n1;
      if (iscircle(ca)) and (iscircle(cb)):
        if (dist(center(ca),center(cb))<=(radius(ca)+radius(cb))):
          p:=ca intersectionpoint cb;
          b:=p Reflected(center(ca),center(cb));
          a:=(dirangle(b,center(ca),p));
          if (a<0): a:=(a+360)/2
          else: a:=a/2
          fi;
          mid:=polarpoint(center(ca),radius(ca),b,a);
          $:= if ((nr=1) and (dist(center(cb),mid) < radius(cb)))
                or ((nr=2) and (dist(center(cb),mid) > radius(cb))) : b
              else: p
              fi;
          $
        else: errmessage "The circles do not intersect";
        fi
      else: errmessage "Illegal parameters for intersection";
      fi
    else: errmessage "Illegal parameters for intersection";
    fi
enddef;
%%-------------------------------------------------------
%  Kahe ringjoone radikaaltelje ja keskpunkte ühendava
%        sirge lõikepunkt.
%  Ringjooned $c_1$ ja $c_2$.
%  Radikaaltelje punkt.
%  radicalpoint(c1,c2)
%%-------------------------------------------------------
vardef radicalpoint (expr a, b) =
  save $,r;
  pair $;
  numeric r;
  if (iscircle(a)) and (iscircle(b)):
    r:=(dist(center(a),center(b))**2+radius(a)**2-radius(b)**2)/(2*dist(center(a),center(b)));
    $:=polarpoint(center(a),r,center(b));
    $
  else: errmessage "Illegal parameters for radicalpoint";
  fi
enddef;
%%-------------------------------------------------------
%Selliste definitsioonide korral on nii sirge ja ringjoone lõikepunkti
%kui ka kahe ringjoone lõikepunkti leidmise makrol omadus, et vahetades
%parameetrite järjekorra, saame esimese lõikepunkti asemel teise ja
%vastupidi.

%%%% Puutepunktid} ===========================================
%%%%
%  Sirge ja ringjoone puutepunkt.
%  Punkt $A$, ringjoon $c$, järjekorranumber [$n$].
%  Punktist $A$ ringjoonele $c$ tõmmatud järjekorras $n$-nda
%         puutuja puutepunkt ringjoonega. Järjekord määratakse nii, et
%         pöörates esimest puutujat ümber punkti $A$ vastupäeva, saame
%         teise puutuja.
%  tangency(A,c,1)
%  tangency(A,c,2)
%  tangency(A,c)

%  Ringjoonte ühine samapoolne puutuja.
%  Ringjooned $c_1$ ja $c_2$, järjekorranumber [$n$].
%  Ringjoonte $c_1$ ja $c_2$ järjekorras $n$-nda ühise puutuja,
%         millest ringjooned asuvad samal pool, puutepunkt
%         ringjoonega $c_2$. Puutepunktide järjekord määratakse nii, et
%         pöörates ringjoone $c_2$ keskpunktist tõmmatud kiirt esimesest
%         puutepunktist vastupäeva teiseni, ei läbi kiir ringjoone $c_1$
%         keskpunkti.
%  tangency(c1,c2,1)
%  tangency(c1,c2,2)
%  tangency(c1,c2)
%  Puutuva sirge teine punkt on \texttt{tangency(c2,c1,2)}.
%%-------------------------------------------------------
vardef tangency(text t)=
  save $,_npairn,_npathn,_nnumericn,_nothern,_coco;
  pair $; _npairn:=0; _npathn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    else:                     fnumeric[_coco]:=4;
    fi
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=1) and (_npathn=1) and (_nnumericn=0) and (fnumeric1=1) and (_nothern=0):
      save A,c;
      pair A;
      path c;
      A:=_t1; c:=_c1;
      if (iscircle(c)):
        if (dist(A,center(c))>radius(c)):
          $:=intersection(c,circledia(center(c),A),2);
          $
        else: errmessage "Given point must be outside of circle";
        fi
      else: errmessage "Given path must be circle";
      fi
    elseif (_npairn=1) and (_npathn=1) and (_nnumericn=1) and (fnumeric1=1) and (fnumeric2=2) and (_nothern=0):
      save A,c,nr;
      pair A;
      path c;
      numeric nr;
      A:=_t1; c:=_c1; nr:=_n1;
      if (iscircle(c)):
        if (dist(A,center(c))>radius(c)):
          if (nr=1):
            $:=intersection(c,circledia(center(c),A),2);
            $
          elseif (nr=2):
            $:=intersection(c,circledia(center(c),A),1);
            $
          else: errmessage "Illegal sequence number given as argument";
          fi
        else: errmessage "Given point must be outside of circle";
        fi
      else: errmessage "Given path must be circle";
      fi
    elseif (_npairn=0) and (_npathn=2) and (_nnumericn=0) and (_nothern=0):
      save ca,cb,c,ra,rb,ang,mid,tan;
      pair mid,tan;
      path ca,cb,c;
      numeric ang,ra,rb;
      ca:=_c1; cb:=_c2;
      ra:=radius(ca);
      rb:=radius(cb);
      if (iscircle(ca)) and (iscircle(cb)):
        if (dist(center(ca),center(cb))>abs(ra-rb)):
          if (ra-rb=0):
            ang:=angle(center(cb)-center(ca))-90;
            $:=polarpoint(cb,ang);
            $
          else:
            c:=circle(if(ra>rb): center(ca),ra-rb else: center(cb),rb-ra fi);
            mid:=tangency(if(ra>rb): center(cb) else: center(ca) fi, c);
            tan:=if(ra>rb): polarpoint(center(ca),ra,mid) else: polarpoint(center(cb),rb,mid) fi;
            $:=if(ra>rb): center(cb)+mid-tan else: tan fi;
            $
          fi
        else: errmessage "Given circles do not have common tangent";
        fi
      else: errmessage "Given must be two circles";
      fi
    elseif (_npairn=0) and (_npathn=2) and (_nnumericn=1) and (_nothern=0):
      save ca,cb,c,ra,rb,ang,mid,tan,nr;
      pair mid,tan;
      path ca,cb,c;
      numeric ang,ra,rb,nr;
      ca:=_c1; cb:=_c2; nr:=_n1;
      ra:=radius(ca);
      rb:=radius(cb);
      if (iscircle(ca)) and (iscircle(cb)):
        if (dist(center(ca),center(cb))>abs(ra-rb)):
          if (ra-rb=0):
            if (nr=1):
              ang:=angle(center(cb)-center(ca))-90;
              $:=polarpoint(cb,ang);
              $
            elseif (nr=2):
              ang:=angle(center(cb)-center(ca))+90;
              $:=polarpoint(cb,ang);
              $
            else: errmessage "Illegal sequence number given as argument";
            fi
          else:
            c:=circle(if(ra>rb): center(ca),ra-rb else: center(cb),rb-ra fi);
            mid:=tangency(if(ra>rb): center(cb) else: center(ca) fi, c);
            tan:=if(ra>rb): polarpoint(center(ca),ra,mid) else: polarpoint(center(cb),rb,mid) fi;
            if (nr=1):
            $:=if(ra>rb): center(cb)+mid-tan else: tan fi;
              $
            elseif (nr=2):
               $:=(if(ra>rb): center(cb)+mid-tan else: tan fi) Reflected(center(ca),center(cb));
              $
            else: errmessage "Illegal sequence number given as argument";
            fi
          fi
        else: errmessage "Given circles do not have common tangent";
        fi
      else: errmessage "Given must be two circles";
      fi
    else: errmessage "Illegal parameters for tangency";
    fi
enddef;
%%-------------------------------------------------------
%  Ringjoonte ühine eripoolne puutuja.
%  Ringjooned $c_1$ ja $c_2$, järjekorranumber [$n$].
%  Ringjoonte $c_1$ ja $c_2$ järjekorras $n$-nda ühise puutuja,
%         millest ringjooned asuvad erineval pool, puutepunkt
%         ringjoonega $c_2$. Puutepunktide järjekord määratakse samamoodi
%         nagu eelnevas.
%  intangency(c1,c2,1)
%  intangency(c1,c2,2)
%  intangency(c1,c2)
%        Puutuva sirge teine punkt on \texttt{intangency(c2,c1,2)}.
%
%        Viimased kaks definitsiooni on tehtud arvestusega, et kui
%        ringjoon $c_1$ kahaneb oma keskpunktiks, siis saame samapidise
%        järjekorra nagu ühest punktist ringjoonele tõmmatud puutujate
%        puhul. Samapoolse puutuja puhul peab ringjoonte keskpunktide
%        kaugus olema suurem kui raadiuste vahe, eripoolse puutuja puhul
%        aga suurem kui raadiuste summa.
%%-------------------------------------------------------
vardef intangency(text t)=
  save $,_npairn,_npathn,_nnumericn,_nothern,_coco;
  pair $; _npairn:=0; _npathn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    else:                     fnumeric[_coco]:=4;
    fi
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=0) and (_npathn=2) and (_nnumericn=0) and (_nothern=0):
      save ca,cb,c,ra,rb,ang,mid,tan;
      pair mid,tan;
      path ca,cb,c;
      numeric ang,ra,rb;
      ca:=_c1; cb:=_c2;
      ra:=radius(ca);
      rb:=radius(cb);
      if (iscircle(ca)) and (iscircle(cb)):
        if (dist(center(ca),center(cb))>(ra+rb)):
          c:=circle(if(ra>=rb): center(ca),ra+rb else: center(cb),rb+ra fi);
          mid:=tangency(if(ra>=rb): center(cb) else: center(ca) fi, c);
          tan:=if(ra>=rb): polarpoint(center(ca),ra,mid) else: polarpoint(center(cb),rb,mid) fi;
          $:=if(ra>=rb): center(cb)+tan-mid else: tan fi;
          $
        else: errmessage "Given circles do not have common tangent";
        fi
      else: errmessage "Given must be two circles";
      fi
    elseif (_npairn=0) and (_npathn=2) and (_nnumericn=1) and (_nothern=0):
      save ca,cb,c,ra,rb,ang,mid,tan,nr;
      pair mid,tan;
      path ca,cb,c;
      numeric ang,ra,rb,nr;
      ca:=_c1; cb:=_c2; nr:=_n1;
      ra:=radius(ca);
      rb:=radius(cb);
      if (iscircle(ca)) and (iscircle(cb)):
        if (dist(center(ca),center(cb))>=(ra+rb)):
          c:=circle(if(ra>=rb): center(ca),ra+rb else: center(cb),rb+ra fi);
          mid:=tangency(if(ra>=rb): center(cb) else: center(ca) fi, c);
          tan:=if(ra>=rb): polarpoint(center(ca),ra,mid) else: polarpoint(center(cb),rb,mid) fi;
          if (nr=1):
            $:=if(ra>=rb): center(cb)+tan-mid else: tan fi;
            $
          elseif (nr=2):
            $:=(if(ra>=rb): center(cb)+tan-mid else: tan fi) Reflected(center(ca),center(cb));
            $
          else: errmessage "Illegal sequence number given as argument";
          fi
        else: errmessage "Given circles do not have common tangent";
        fi
      else: errmessage "Given must be two circles";
      fi
    else: errmessage "Illegal parameters for intangency";
    fi
enddef;
%%-------------------------------------------------------
%  Kahe ringjoone puutepunkt.
%  Punkt $A$, ringjoon $c$, järjekorranumber [$n$].
%  Järjekorras $n$-nda ringjoone, mille keskpunkt on $A$,
%         puutepunkt ringjoonega $c$. Puutepunktide järjekord määratakse
%         suunaga ringjoonte keskpunkte ühendaval sirgel, see suund on
%         punktist $A$ teise ringjoone keskpunkti poole.
%  circtangency(c,A)
%  circtangency(c,A,1)
%  circtangency(c,A,2)
%%-------------------------------------------------------
vardef circtangency(text t)=
  save $,_npairn,_npathn,_nnumericn,_nothern,_coco;
  pair $; _npairn:=0; _npathn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    else:                     fnumeric[_coco]:=4;
    fi
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=1) and (_npathn=1) and (_nnumericn=0) and (_nothern=0):
      save c,A;
      pair A;
      path c;
      A:=_t1; c:=_c1;
      if (iscircle(c)):
        if (dist(A,center(c))>radius(c)):
          $:=intersection(c,A,center(c),1);
          $
        else: errmessage "Given point must be outside of circle";
        fi
      else: errmessage "Given must be a circle";
      fi
    elseif (_npairn=1) and (_npathn=1) and (_nnumericn=1) and (_nothern=0):
      save c,A,nr;
      pair A;
      path c;
      numeric nr;
      A:=_t1; c:=_c1; nr:=_n1;
      if (iscircle(c)):
        if (dist(A,center(c))>radius(c)):
          if (nr=1):
            $:=intersection(c,A,center(c),1);
            $
          elseif (nr=2):
            $:=intersection(c,A,center(c),2);
            $
          else: errmessage "Illegal sequence number given as argument";
          fi
        else: errmessage "Given point must be outside of circle";
        fi
      else: errmessage "Given must be a circle";
      fi
    else: errmessage "Illegal parameters for circtangency";
    fi
enddef;
%%-------------------------------------------------------
%%%%=== Lõigud================================================
%%%%
%  Lõik etteantud punktide järgi.
%  Punkt $A$, pikkus [$x$], punkt $B$, pikkus [$y$].
%  Lõik punktide $A$ ja $B$ vahel, ulatub punktidest $A$ ja $B$
%         üle vastavalt $x$ ja $y$ võrra.}
%  segment(A,x,B,y)
%  segment(A,x,B)
%  segment(A,B,y)
%  segment(A,B)

%  Antud lõigu pikendamine.
%  Lõik $l$, pikkus [$x$].
%  Lõike, mille lõpp-punkti on nihutatud kaugemale $y$ võrra.
%  segment(l,y)
%  segment(l)
%%-------------------------------------------------------
vardef segment(text t)=
  save $,_npairn,_npathn,_nnumericn,_nothern,_coco;
  path $; _npairn:=0; _npathn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    else:                     fnumeric[_coco]:=4;
    fi
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=2) and (_npathn+_nothern+_nnumericn=0):
      save A,B;
      pair A,B;
      A:=_t1; B:=_t2;
      $:=A--B;
      $
    elseif (_npairn=2) and (_nnumericn=1) and (fnumeric3=3) and (_npathn+_nothern=0):
      save A,B,y;
      pair A,B;
      numeric y;
      A:=_t1; B:=_t2; y:=_n1;
      $:=A--A+(dist(A,B)+y)/dist(A,B)*(B-A);
      $
    elseif (_npairn=2) and (_nnumericn=1) and (fnumeric2=3) and (_npathn+_nothern=0):
      save A,B,x;
      pair A,B;
      numeric x;
      A:=_t1; B:=_t2; x:=_n1;
      $:=B+(dist(A,B)+x)/dist(A,B)*(A-B)--B;
      $
    elseif (_npairn=2) and (_nnumericn=2) and (fnumeric2=3) and (fnumeric4=3) and (_npathn+_nothern=0):
      save A,B,x,y;
      pair A,B;
      numeric x,y;
      A:=_t1; B:=_t2; x:=_n1; y:=_n2;
      $:=B+(dist(A,B)+x)/dist(A,B)*(A-B)--A+(dist(A,B)+y)/dist(A,B)*(B-A);
      $
    elseif (_npathn=1) and (issegment(_c1)) and (_nnumericn=1) and (fnumeric2=3) and (_npairn+_nothern=0):
      save l,y,A,B;
      pair A,B;
      path l;
      numeric y;
      l:=_c1; y:=_n1; A:=startingpoint(l); B:=endpoint(l);
      $:=A--A+(dist(A,B)+y)/dist(A,B)*(B-A);
      $
    elseif (_npathn=1) and (issegment(_c1)) and (_nnumericn+_npairn+_nothern=0):
      save l;
      path l;
      l:=_c1;
      $:=startingpoint(l)--endpoint(l);
      $
    else: errmessage "Illegal parameters for segment";
    fi
enddef;
%%-------------------------------------------------------
%  Antud lõiguga paralleelne lõik.
%  Punktid $A$, $B$, $C$.
%  Punktist $A$ lähtuv lõiguga $BC$ paralleelne, sama pikk ja
%         samasuunaline lõik.
%  parallel(A,B,C)

%  Punkt $A$, lõik $l$.
%  Punktist $A$ lähtuv lõiguga $l$ paralleelne, sama pikk ja
%         samasuunaline lõik.
%  parallel(A,l)
%%-------------------------------------------------------
vardef parallel(text t)=
  save $,_npairn,_npathn,_nothern;
  path $; _npairn:=0; _npathn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=1) and (_npathn=1) and (_nothern=0):
      save P,w;
      pair P;
      path w;
      P:=_t1; w:=_c1;
      if (issegment(w)):
        $:=P--(P+endpoint(w)-startingpoint(w));
	      $
      else: errmessage "Illegal parameters for parallel";
      fi
    elseif (_npairn=3) and (_npathn=0) and (_nothern=0):
      save P,Q,R;
      pair P,Q,R;
      P:=_t1; Q:=_t2; R:=_t3;
      $:=P--(P+R-Q);
      $
    else: errmessage "Illegal parameters for parallel";
    fi
enddef;
%%-------------------------------------------------------
%%  Antud lõiguga ristuv lõik.
%  Punktid $A$, $B$, pikkus [$d$].
%  Lõik, mis algab lõigu $AB$ keskpunktist ja kulgeb risti lõiguga
%      	$AB$ ning lõigu pikkus on $d$ (vaikimisi $d=1$).
%  midperp(A,B,d)

%  Lõik $l$, kaugus $d$.
%  Lõik, mis algab lõigu $l$ alguspunktist ja kulgeb temaga risti
%	      ning lõigu pikkus on $d$.
%  midperp(l,d)
%%-------------------------------------------------------
vardef midperp(text t)=
  save $,_npairn,_nnumericn,_npathn,_nothern;
  path $; _npairn:=0; _nnumericn:=0; _npathn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=2) and (_nnumericn=1) and (_npathn+_nothern=0):
      save A,B,d;
      pair A,B;
      numeric d;
      A:=_t1; B:=_t2; d:=_n1;
      $:=perpendicular(A,B,.5,d);
      $
    elseif (_npathn=1) and (_nnumericn=1) and (_npairn+_nothern=0):
      save l,d;
      numeric d;
      path l;
      l:=_c1; d:=_n1;
      $:=perpendicular(startingpoint(l),endpoint(l),.5,d);
      $
    else: errmessage "Illegal parameters for parallel";
    fi
enddef;
%%-------------------------------------------------------
%  Punktid $A$, $B$, $C$.
%  Punktist $A$ lähtuv lõiguga $BC$ ristuv lõik, mis lõpeb lõigul
%         $BC$.
%  perpendicular(A,B,C)

%  Punktid $A$, lõik $l$.
%  Punktist $A$ lähtuv lõiguga $l$ ristuv lõik, mis lõpeb lõigul
%         $l$.
%  perpendicular(A,l)

%  Punktid $A$, $B$, kordaja [k], pikkus $d$.
%  Lõik, mis algab lõigu $AB$ punktist $k$ osa pikkuse võrra punkti $A$
%	      poolt ja kulgeb risti lõiguga $AB$ ning lõigu pikkus on $d$.
%  perpendicular(A,B,k,d)
%  perpendicular(A,B,d)

%  Lõik $l$, kordaja [$k$], kaugus $d$.
%  Lõik, mis algab lõigu $l$ alguspunktist $k$ osa pikkuse võrra lõigu $l$
%	       alguspunkti poolt ja kulgeb risti lõiguga $l$ ning lõigu pikkus on $d$.
%  perpendicular(l,k,d)
%  perpendicular(l,d)
%%-------------------------------------------------------
vardef perpendicular(text t)=
  save $,_npairn,_npathn,_nothern,_nnumericn;
  path $; _npairn:=0; _npathn:=0; _nothern:=0; _nnumericn:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=1) and (_npathn=1) and (_nnumericn+_nothern=0):
      save P,w;
      pair P;
      path w;
      P:=_t1; w:=_c1;
      if (issegment(w)):
        $:=P--P Projected(startingpoint(w),endpoint(w));
	      $
      else: errmessage "Illegal parameters for perpendicular";
      fi
    elseif (_npairn=3) and (_npathn=0) and (_nnumericn+_nothern=0):
      save P,Q,R;
      pair P,Q,R;
      P:=_t1; Q:=_t2; R:=_t3;
      $:=P--P Projected(Q,R);
      $
    elseif (_npairn=2) and (_nnumericn=2) and (_npathn+_nothern=0):
      save A,B,k,d;
      pair A,B;
      numeric k,d;
      A:=_t1; B:=_t2; k:=_n1; d:=_n2;
      if (d<>0):
        save M; pair M;
        M:=(A+k*(B-A));
        if (d>0):
          $:=M--triangle(d,M,90)(B);
          $
        else:
          $:=M--triangle(B)(abs(d),M,90);
          $
        fi
      else: errmessage "Illegal parameter for distance";
      fi
    elseif (_npairn=2) and (_nnumericn=1) and (_npathn+_nothern=0):
      save A,B,d;
      pair A,B;
      numeric d;
      A:=_t1; B:=_t2; d:=_n1;
      if (d<>0):
        if (d>0):
          $:=A--triangle(d,A,90)(B);
          $
        else:
          $:=A--triangle(B)(abs(d),A,90);
          $
        fi
      else: errmessage "Illegal parameter for distance";
      fi
    elseif (_npathn=1) and (_nnumericn=2) and (_npairn+_nothern=0):
      save l,k,d;
      path l;
      numeric k,d;
      l:=_c1; k:=_n1; d:=_n2;
      $:=perpendicular(startingpoint(l),endpoint(l),k,d);
      $
    elseif (_npathn=1) and (_nnumericn=1) and (_npairn+_nothern=0):
      save l,d;
      path l;
      numeric d;
      l:=_c1; d:=_n1;
      $:=perpendicular(startingpoint(l),endpoint(l),d);
      $
    else: errmessage "Illegal parameters for perpendicular";
    fi
enddef;
%%-------------------------------------------------------
%%  Kolmnurga kesklõik.
%  Kolm punkti $A$, $B$, $C$, järjekorranumber [$n$].
%  Kolmnurga $ABC$ järjekorras $n$-ndat tippu eraldav kesklõik
%  midline(A,B,C,1)
%  midline(A,B,C,2)
%  midline(A,B,C,3)
%  midline(A,B,C)
%%-------------------------------------------------------
vardef midline(text t)=
  save $,_npairn,_nnumericn,_nothern;
  path $; _npairn:=0; _nnumericn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=3) and (_nnumericn=1) and (_nothern=0):
      save P,Q,R,n;
      pair P,Q,R;
      numeric n;
      P:=_t1; Q:=_t2; R:=_t3; n:=_n1;
      if     (n=1): $:=.5[P,Q]--.5[P,R]; $
      elseif (n=2): $:=.5[Q,P]--.5[Q,R]; $
      elseif (n=3): $:=.5[R,P]--.5[R,Q]; $
      else: errmessage "Illegal parameters for midline";
      fi
    elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
      save P,Q,R;
      pair P,Q,R;
      P:=_t1; Q:=_t2; R:=_t3;
      $:=.5[P,Q]--.5[P,R];
      $
    else: errmessage "Illegal parameters for midline";
    fi
enddef;
%%-------------------------------------------------------
%% Kolmnurga mediaan.
%  Kolm punkti $A$, $B$, $C$, järjekorranumber [$n$].
%  Kolmnurga $ABC$ $n$-ndast tipust vastasküljele tõmmatud
%         mediaan.
%  median(A,B,C,1)
%  median(A,B,C,2)
%  median(A,B,C,3)
%  median(A,B,C)
%%-------------------------------------------------------
vardef median(text t)=
  save $,_npairn,_nnumericn,_nothern;
  path $; _npairn:=0; _nnumericn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=3) and (_nnumericn=1) and (_nothern=0):
      save P,Q,R,n;
      pair P,Q,R;
      numeric n;
      P:=_t1; Q:=_t2; R:=_t3; n:=_n1;
      if     (n=1): $:=P--medianfoot(P,Q,R); $
      elseif (n=2): $:=Q--medianfoot(Q,R,P); $
      elseif (n=3): $:=R--medianfoot(R,P,Q); $
      else: errmessage "Illegal parameters for median";
      fi
    elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
      save P,Q,R;
      pair P,Q,R;
      P:=_t1; Q:=_t2; R:=_t3;
      $:=P--medianfoot(P,Q,R);
      $
    else: errmessage "Illegal parameters for median";
    fi
enddef;
%%-------------------------------------------------------
%% Kõrgus.
%  Kolm punkti $A$, $B$, $C$, järjekorranumber [$n$].
%  Kolmnurga $ABC$ $n$-ndast tipust vastasküljele tõmmatud
%         kõrgus.
%  height(A,B,C,1)
%  height(A,B,C)
%%-------------------------------------------------------
vardef height(text t)=
  save $,_npairn,_nnumericn,_nothern;
  path $; _npairn:=0; _nnumericn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=3) and (_nnumericn=1) and (_nothern=0):
      save P,Q,R,n;
      pair P,Q,R;
      numeric n;
      P:=_t1; Q:=_t2; R:=_t3; n:=_n1;
      if     (n=1): $:=P--heightfoot(P,Q,R); $
      elseif (n=2): $:=Q--heightfoot(Q,P,R); $
      elseif (n=3): $:=R--heightfoot(R,P,Q); $
      else: errmessage "Illegal parameters for height";
      fi
    elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
      save P,Q,R;
      pair P,Q,R;
      P:=_t1; Q:=_t2; R:=_t3;
      $:=P--heightfoot(P,Q,R);
      $
    else: errmessage "Illegal parameters for height";
    fi
enddef;
%%-------------------------------------------------------
%% Nurgapoolitaja.
%  Kolm punkti $A$, $B$, $C$, järjekorranumber [$n$].
%  Kolmnurga $ABC$ $n$-ndast tipust vastasküljele tõmmatud
%         nurgapoolitaja.
%  bisector(A,B,C,1)
%  bisector(A,B,C)
%  anglebisector(A,B,C,1)
%  anglebisector(A,B,C)
%%-------------------------------------------------------
vardef bisector(text t)=
  save $,_npairn,_nnumericn,_nothern;
  path $; _npairn:=0; _nnumericn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=3) and (_nnumericn=1) and (_nothern=0):
      save P,Q,R,n;
      pair P,Q,R;
      numeric n;
      P:=_t1; Q:=_t2; R:=_t3; n:=_n1;
      if     (n=1): $:=P--bisectorfoot(P,Q,R); $
      elseif (n=2): $:=Q--bisectorfoot(Q,P,R); $
      elseif (n=3): $:=R--bisectorfoot(R,P,Q); $
      else: errmessage "Illegal parameters for bisector";
      fi
    elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
      save P,Q,R;
      pair P,Q,R;
      P:=_t1; Q:=_t2; R:=_t3;
      $:=P--bisectorfoot(P,Q,R);
      $
    else: errmessage "Illegal parameters for bisector";
    fi
enddef;
%%-------------------------------------------------------
def anglebisector = bisector enddef;
%%-------------------------------------------------------
%=== Ringjooned =====================================================
%%%% Ringjoone konstrueerimine
%% Ringjoone tavapärasemad konstrueerimisviisid.
%  Punkt [$O$] ja arv $r$.
%  Ringjoon keskpunktiga $O$ ja raadiusega $r$.
%  circle(O,r)
%  circle(r)

%  Punkt [$O$] ja punkt $A$.
%  Ringjoon, mille keskpunkt on $O$ ja mis läbib punkti $A$.
%  circle(O,A)
%  circle(A)
%
%  Punktid $A$, $B$ ja $C$.
%  Ringjoon, mis läbib punkte $A$, $B$, $C$ (kolmnurga $ABC$
%        ümberringjoon).
%  circle(A,B,C)
%  circumcircle(A,B,C)
%%-------------------------------------------------------
def circumcircle = circle enddef;
vardef circle(text t)=
  save $,_npairn,_nnumericn,_nothern,_coco;
  path $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (numeric _stexts): fnumeric[_coco]:=2;
    else:                     fnumeric[_coco]:=3;
    fi
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1):
      save O,r;
      pair O;
      numeric r;
      O:=_t1; r:=_n1;
      $:=fullcircle scaled (2*r) shifted O;
      $
    elseif (_nnumericn=1) and (_npairn+_nothern=0):
      save r;
      numeric r;
      r:=_n1;
      $:=fullcircle scaled (2*r);
      $
    elseif (_npairn=2) and (_nnumericn+_nothern=0):
      save O,A;
      pair O,A;
      O:=_t1; A:=_t2;
      $:=fullcircle scaled (2*dist(O,A)) shifted O;
      $
    elseif (_npairn=1) and (_nnumericn+_nothern=0):
      save A;
      pair A;
      A:=_t1;
      $:=fullcircle scaled (2*dist(A));
      $
    elseif (_npairn=3) and (_nnumericn+_nothern=0):
      save A,B,C;
      pair A,B,C;
      A:=_t1; B:=_t2; C:=_t3;
      $:=fullcircle scaled (2*circumradius(A,B,C)) shifted circumcenter(A,B,C);
      $
    else: errmessage "Illegal parameters for circle";
    fi
enddef;
%%-------------------------------------------------------
%% Ringjoone konstrueerimine diameetri järgi.
%  Kaks punkti [$A$] ja $B$.
%  Ringjoon, mille diameeter on $AB$.
%  circledia(A,B)
%  circledia(B)

%  Lõik $l$.
%  Ringjoon, mille diameeter on lõik $l$.
%  circledia(l)
%%-------------------------------------------------------
vardef circledia(text t)=
  save $,_npairn,_npathn,_nothern,_coco;
  path $; _npairn:=0; _npathn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    else:                     fnumeric[_coco]:=3;
    fi
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=2) and (_npathn+_nothern=0):
      save A,B;
      pair A,B;
      A:=_t1; B:=_t2;
      $:=fullcircle scaled (dist(A,B)) shifted (.5[A,B]);
      $
    elseif (_npairn=1) and (_npathn+_nothern=0):
      save B;
      pair B;
      B:=_t1;
      $:=fullcircle scaled (dist(B)) shifted (.5[origin,B]);
      $
    elseif (_npathn=1) and (_npairn+_nothern=0):
      if (issegment(_c1)):
        save l;
        path l;
        l:=_c1;
        $:=fullcircle scaled (dist(startingpoint(l),endpoint(l))) shifted (.5[startingpoint(l),endpoint(l)]);
        $
      else: errmessage "Illegal parameters for circledia";
      fi
    else: errmessage "Illegal parameters for circledia";
    fi
enddef;
%%-------------------------------------------------------
%%%% Kaare konstrueerimine ==============================
%  Keskpunkti, antud punkti ja kesknurga järgi.
%  Punkt [$O$], punkt $A$, kesknurk $b$.
%  Kaar ringjoonel keskpunktiga $O$, algab punktist $A$ ja lõpeb
%         kesknurgal $b$.
%  arc(O,A,b)
%  arc(A,b)

%  Keskpunkti, antud punkti ja teise punkti järgi.
%  Punkt [$O$], punkt $A$, punkt $B$, suunaindikaator
%         [$n$].
%  Kaar ringjoonel keskpunktiga $O$, algab punktist $A$ ja lõpeb
%         kiirel $OB$. Suunda loetakse vastupäeva, kui $n=true$, ja
%         päripäeva, kui $n=false$.
%  arc(O,A,B)
%  arc(A,B)
%  arc(O,A,B,true)
%  arc(A,B,true)
%  arc(O,A,B,false)
%  arc(A,B,false)
%%-------------------------------------------------------
vardef arc(text t)=
  save $,_npairn,_npathn,_nnumericn,_nbooleann,_nothern,_coco;
  path $; _npairn:=0; _npathn:=0; _nnumericn:=0; _nbooleann:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (boolean _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    elseif (boolean _stexts): _nbooleann:=_nbooleann+1; _bo[_nbooleann]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=2) and (_nbooleann=0) and (_npathn=0) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1) and (fnumeric2=1):
      save O,A,b;
      save a,c;
      pair O,A;
      path c;
      numeric b,a;
      O:=_t1; A:=_t2; b:=_n1;
      if (O<>A):
        a:=angle(A-O); c:=circle(O,A);
        $:=(c cutafter circle(polarpoint(O,radius(c),b),0.01)) rotatedaround(O,a);
        $
      else: errmessage "Illegal parameters for arc";
      fi
    elseif (_npairn=1) and (_npathn=0) and (_nbooleann=0) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1):
      save A,b;
      pair A;
      numeric b;
      A:=_t1; b:=_n1;
      $:=arc(origin,A,b);
      $
    elseif (_npairn=3) and (_npathn+_nnumericn+_nothern=0) and (_nbooleann=0):
      save O,A,B;
      pair O,A,B;
      O:=_t1; A:=_t2; B:=_t3;
      $:=arc(O,A,dirangle(A,O,B));
      $
    elseif (_npairn=3) and (_nnumericn+_npathn+_nothern=0) and (_nbooleann=1) and (fnumeric4=4):
      save O,A,B,nr;
      pair O,A,B;
      boolean nr;
      O:=_t1; A:=_t2; B:=_t3; nr:=_bo1;
      if (nr=true):
        $:=arc(O,A,dirangle(A,O,B));
        $
      elseif(nr=false):
        $:=arc(O,polarpoint(O,dist(O,A),B),dirangle(B,O,A));
        $
      fi
    elseif (_npairn=2) and (_npathn+_nnumericn+_nothern=0) and (_nbooleann=0):
      save A,B;
      pair A,B;
      A:=_t1; B:=_t2;
      $:=arc(origin,A,dirangle(A,origin,B));
      $
    elseif (_npairn=2) and (_nbooleann=1) and (_nnumericn+_npathn+_nothern=0) and (fnumeric3=4):
      save A,B,nr;
      pair A,B;
      boolean nr;
      A:=_t1; B:=_t2; nr:=_bo1;
      if (nr=true):
        $:=arc(origin,A,dirangle(A,origin,B));
        $
      elseif(nr=false):
        $:=arc(origin,polarpoint(origin,dist(A),B),dirangle(B,origin,A));
        $
      fi
    else: errmessage "Illegal parameters for arc";
    fi
enddef;
%%-------------------------------------------------------
%% Ringjoonest lõikamise abil.
%  Ringjoon $c$, nurgad [$a$] ja $b$, suunaindikaator [$n$].
%  Ringjoone $c$ kaar polaarnurgast $a$ polaarnurgani $b$. Suunda
%         loetakse vastupäeva, kui $n=true$, ja päripäeva, kui $n=false$.
%  circlearc(c,a,b)
%  circlearc(c,b)
%  circlearc(c,a,b,true)
%  circlearc(c,b,true)
%  circlearc(c,a,b,false)
%  circlearc(c,b,false)

%  Ringjoon $c$, punktid [$A$] ja $B$, suunaindikaator [$n$].
%  Ringjoone $c$ kaar kiirest $OA$ kiireni $OB$, kus
%         $O$ on ringjoone keskpunkt. Suund määratakse samamoodi nagu
%         enne.
%  circlearc(c,A,B)
%  circlearc(c,B)
%  circlearc(c,A,B,true)
%  circlearc(c,B,true)
%  circlearc(c,A,B,false)
%  circlearc(c,B,false)

%  Punkt [$O$], raadius $r$, nurgad [$a$] ja $b$, suunaindikaator
%         [$n$].
%  Keskpunkti $O$ ja raadiusega $r$ antud ringjoone kaar
%         polaarnurgast $a$ polaarnurgani $b$. Suund
%         määratakse samamoodi nagu enne.
%  circlearc(O,r,a,b)
%  circlearc(O,r,b)
%  circlearc(r,a,b)
%  circlearc(r,b)
%  circlearc(O,r,a,b,true)
%  circlearc(O,r,b,true)
%  circlearc(r,a,b,true)
%  circlearc(r,b,true)
%  circlearc(O,r,a,b,false)
%  circlearc(O,r,b,false)
%  circlearc(r,a,b,false)
%  circlearc(r,b,false)

%  Punkt [$O$], raadius $r$, punktid [$A$] ja $B$, suunaindikaator
%         [$n$].
%  Keskpunkti $O$ ja raadiusega $r$ antud ringjoone kaar kiirest
%         $OA$ kiireni $OB$. Suund määratakse samamoodi nagu
%         enne.
%  circlearc(O,r,A,B)
%  circlearc(O,r,B)
%  circlearc(r,A,B)
%  circlearc(r,B)
%  circlearc(O,r,A,B,true)
%  circlearc(O,r,B,true)
%  circlearc(r,A,B,true)
%  circlearc(r,B,true)
%  circlearc(O,r,A,B,false)
%  circlearc(O,r,B,false)
%  circlearc(r,A,B,false)
%  circlearc(r,B,false)
%%-------------------------------------------------------
vardef circlearc(text t)=
  save $,_npairn,_npathn,_nnumericn,_nbooleann,_nothern,_coco;
  path $; _npairn:=0; _npathn:=0; _nnumericn:=0; _nbooleann:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (boolean _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    elseif (boolean _stexts): _nbooleann:=_nbooleann+1; _bo[_nbooleann]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npathn=1) and (_nnumericn=2) and (_npairn+_nbooleann+_nothern=0) and (fnumeric1=2):
      save c,a,b;
      path c;
      numeric a,b;
      c:=_c1; a:=_n1; b:=_n2;
      if (b<a): b:=b+360; fi
      $:=arc(center(c),polarpoint(c,a),b-a);
      $
    elseif (_npathn=1) and (_nnumericn=2) and (_nbooleann=1) and (_npairn+_nothern=0) and (fnumeric1=2) and (fnumeric2=3):
      save c,a,b,nr;
      path c;
      numeric a,b;
      boolean nr;
      c:=_c1; a:=_n1; b:=_n2; nr:=_bo1;
      if (nr=true):
        $:=circlearc(c,a,b);
        $
      elseif(nr=false):
        if (b<a): b:=b+360; fi
        if (iscircle(c)):
          $:=arc(center(c),polarpoint(c,b),360-b+a);
          $
        else: errmessage "Illegal parameters for circlearc";
        fi
      else: errmessage "Illegal sequence number given as argument";
      fi
    elseif (_npathn=1) and (_nnumericn=1) and (_nbooleann+_npairn+_nothern=0) and (fnumeric1=2):
      save c,b;
      path c;
      numeric b;
      c:=_c1; b:=_n1;
      $:=arc(center(c),polarpoint(c),b);
      $
    elseif (_npathn=1) and (_nnumericn=1) and (_nbooleann=1) and (_npairn+_nothern=0) and (fnumeric1=2) and (fnumeric2=3):
      save c,b,nr;
      path c;
      numeric b;
      boolean nr;
      c:=_c1; b:=_n1; nr:=_bo1;
      if (nr=true):
        $:=circlearc(c,b);
        $
      elseif(nr=false):
        $:=circlearc(c,0,b,nr);
        $
      fi
    elseif (_npairn=2) and (_npathn=1) and (_nbooleann+_nnumericn+_nothern=0) and (fnumeric1=2):
      save c,A,B;
      pair A,B;
      path c;
      A:=_t1; B:=_t2; c:=_c1;
      $:=arc(center(c),polarpoint(c,A),dirangle(A,center(c),B));
      $
    elseif (_npairn=2) and (_nbooleann=1) and (_npathn=1) and (_nnumericn+_nothern=0) and (fnumeric1=2) and (fnumeric2=1) and (fnumeric3=1):
      save c,A,B,nr;
      pair A,B;
      path c;
      boolean nr;
      A:=_t1; B:=_t2; nr:=_bo1; c:=_c1;
      if (nr=true):
        $:=circlearc(c,A,B);
        $
      elseif(nr=false):
        $:=arc(center(c),polarpoint(c,B),dirangle(B,center(c),A));
        $
      else: errmessage "Illegal sequence number given as argument";
      fi
    elseif (_npairn=1) and (_npathn=1) and (_nbooleann+_nnumericn+_nothern=0) and (fnumeric1=2):
      save c,B;
      pair B;
      path c;
      B:=_t1; c:=_c1;
      $:=arc(center(c),polarpoint(c),polarangle(center(c),B));
      $
    elseif (_npairn=1) and (_nbooleann=1) and (_npathn=1) and (_nnumericn+_nothern=0) and (fnumeric1=2) and (fnumeric2=1):
      save c,B,nr;
      pair B;
      path c;
      boolean nr;
      B:=_t1; nr:=_bo1; c:=_c1;
      if (nr=true):
        $:=circlearc(c,B);
        $
      elseif(nr=false):
        $:=arc(center(c),polarpoint(c,B),360-polarangle(center(c),B));
        $
      fi
    elseif (_npairn=1) and (_nnumericn=3) and (_nbooleann+_npathn+_nothern=0) and (fnumeric1=1):
      save O,r,a,b;
      pair O;
      O:=_t1; r:=_n1; a:=_n2; b:=_n3;
      save c; path c; c:=circle(O,r);
      $:=circlearc(c,a,b);
      $
    elseif (_npairn=1) and (_nnumericn=3) and (_nbooleann=1) and (_npathn+_nothern=0) and (fnumeric1=1):
      save O,r,a,b,nr;
      pair O;
      numeric r,a,b;
      boolean nr;
      O:=_t1; r:=_n1; a:=_n2; b:=_n3; nr:=_bo1;
      if (nr=true):
        $:=circlearc(O,r,a,b);
        $
      elseif(nr=false):
        save c; path c; c:=circle(O,r);
        $:=circlearc(c,a,b,nr);
        $
      fi
    elseif (_npairn=1) and (_nnumericn=2) and (_nbooleann+_npathn+_nothern=0) and (fnumeric1=1):
      save O,r,b;
      pair O;
      numeric r,b;
      O:=_t1; r:=_n1; b:=_n2;
      save c; path c; c:=circle(O,r);
      $:=circlearc(c,b);
      $
    elseif (_npairn=1) and (_nnumericn=2) and (_nbooleann=1) and (_npathn+_nothern=0) and (fnumeric1=1) and (fnumeric2=3) and (fnumeric3=3):
      save O,r,b,nr;
      pair O;
      numeric r,b;
      boolean nr;
      O:=_t1; r:=_n1; b:=_n2; nr:=_bo1;
      save c; path c; c:=circle(O,r);
      if (nr=true):
        $:=circlearc(c,b);
        $
      elseif(nr=false):
        $:=circlearc(c,b,nr);
        $
      fi
    elseif (_nnumericn=3) and (_nbooleann+_npairn+_npathn+_nothern=0):
      save r,a,b;
      r:=_n1; a:=_n2; b:=_n3;
      $:=circlearc(origin,r,a,b);
      $
    elseif (_nnumericn=3) and (_nbooleann=1) and (_npairn+_npathn+_nothern=0):
      save r,a,b,nr;
      numeric r,a,b;
      boolean nr;
      r:=_n1; a:=_n2; b:=_n3; nr:=_bo1;
      if (nr=true):
        $:=circlearc(origin,r,a,b,nr);
        $
      elseif(nr=false):
        $:=circlearc(origin,r,a,b,nr);
        $
      fi
    elseif (_nnumericn=2) and (_nbooleann+_npairn+_npathn+_nothern=0):
      save r,b;
      r:=_n1; b:=_n2;
      $:=circlearc(r,0,b);
      $
    elseif (_nnumericn=2) and (_nbooleann=1) and (_npairn+_npathn+_nothern=0) and (fnumeric2=3):
      save r,b,nr;
      numeric r,b;
      boolean nr;
      r:=_n1; b:=_n2; nr:=_bo1;
      if (nr=true):
        $:=circlearc(r,b);
        $
      elseif(nr=false):
        $:=circlearc(r,0,b,nr);
        $
      fi
    elseif (_npairn=3) and (_nnumericn=1) and (_nbooleann+_npathn+_nothern=0) and (fnumeric2=3):
      save O,r,A,B;
      pair O,A,B;
      numeric r;
      O:=_t1; A:=_t2; B:=_t3; r:=_n1;
      save c; path c; c:=circle(O,r);
      $:=circlearc(c,A,B);
      $
    elseif (_npairn=3) and (_nnumericn=1) and (_nbooleann=1) and (_npathn+_nothern=0) and (fnumeric1=1) and (fnumeric2=3):
      save O,r,A,B,nr;
      pair O,A,B;
      numeric r;
      boolean nr;
      O:=_t1; A:=_t2; B:=_t3; r:=_n1; nr:=_bo1;
      if (nr=true):
        $:=circlearc(O,r,A,B);
        $
      elseif(nr=false):
        save c; path c; c:=circle(O,r);
        $:=circlearc(c,A,B,nr);
        $
      fi
    elseif (_npairn=2) and (_nnumericn=1) and (_nbooleann+_npathn+_nothern=0) and (fnumeric2=3):
      save O,r,B;
      pair O,B;
      numeric r;
      O:=_t1; B:=_t2; r:=_n1;
      save c; path c; c:=circle(O,r);
      $:=circlearc(c,B);
      $
    elseif (_npairn=2) and (_nnumericn=1) and (_nbooleann=1) and (_npathn+_nothern=0) and (fnumeric2=3) and (fnumeric3=1):
      save O,r,B,nr;
      pair O,B;
      numeric r;
      boolean nr;
      O:=_t1; B:=_t2; r:=_n1; nr:=_bo1;
      if (nr=true):
        $:=circlearc(O,r,B);
        $
      elseif(nr=false):
        save c; path c; c:=circle(O,r);
        $:=circlearc(c,B,nr);
        $
      fi
    elseif (_npairn=2) and (_nnumericn=1) and (_nbooleann+_npathn+_nothern=0) and (fnumeric1=3):
      save r,A,B;
      pair A,B;
      numeric r;
      A:=_t1; B:=_t2; r:=_n1;
      save c; path c; c:=circle(r);
      $:=circlearc(c,A,B);
      $
    elseif (_npairn=2) and (_nnumericn=1) and (_nbooleann=1) and (_npathn+_nothern=0) and (fnumeric1=3) and (fnumeric3=1):
      save r,A,B,nr;
      pair A,B;
      numeric r;
      boolean nr;
      A:=_t1; B:=_t2; r:=_n1; nr:=_bo1;
      if (nr=true):
        $:=circlearc(origin,r,A,B);
        $
      elseif(nr=false):
        save c; path c; c:=circle(r);
        $:=circlearc(c,A,B,nr);
        $
      fi
    elseif (_npairn=1) and (_nnumericn=1) and (_nbooleann+_npathn+_nothern=0) and (fnumeric1=3):
      save r,B;
      pair B;
      numeric r;
      B:=_t1; r:=_n1;
      save c; path c; c:=circle(r);
      $:=circlearc(c,B);
      $
    elseif (_npairn=1) and (_nnumericn=1) and (_nbooleann=1) and (_npathn+_nothern=0) and (fnumeric2=1):
      save r,B,nr;
      pair B;
      numeric r;
      boolean nr;
      B:=_t1; r:=_n1; nr:=_bo1;
      if (nr=true):
        $:=circlearc(r,B);
        $
      elseif(nr=false):
        save c; path c; c:=circle(r);
        $:=circlearc(c,B,nr);
        $
      fi
    else: errmessage "Illegal parameters for circlearc";
    fi
enddef;
%%-------------------------------------------------------
%% Poolringjoon diameetri järgi.
%  Punktid $A$ ja $B$, suunaindikaator [$n$].
%  Poolringjoon diameetriga $AB$. Asub diameetri kohal, kui $n=true$,
%         ja diameetri all, kui $n=false$.
%  semicircle(A,B)
%  semicircle(A,B,n)

%  Lõik $l$, suunaindikaator [$n$].
%  Poolringjoon diameetriga $l$. Järjekorranumbri tähendus on sama
%         nagu eelnevas.
%  semicircle(l)
%  semicircle(l,true)
%  semicircle(l,false)

%  Poolringjoon ringjoonest lõikamise abil.
%  Ringjoon $c$, nurk $a$, suunaindikaator [$n$].
%  Ringjoonest $c$ punktist, mille polaarnurk on $a$, lähtuv
%         poolringjoone kaar. Kulgeb vastupäeva, kui $n=true$, ja päripäeva,
%         kui $n=false$.
%  semicircle(c,a)
%  semicircle(c,a,true)
%  semicircle(c,a,false)

%  Ringjoon $c$, punkt $A$, suunaindikaator [$n$].
%  Ringjoone $c$ ja tema keskpunktist punkti $A$ suunduva kiire
%         lõikepunktist lähtuv poolringjoon. Kulgemissuund sama nagu
%         enne.
%  semicircle(c,A)
%  semicircle(c,A,true)
%  semicircle(c,A,false)

%  Punkt [$O$], raadius $r$, nurk $a$, suunaindikaator [$n$].
%  Keskpunktiga $O$ ja raadiusega $r$ määratud poolringjoone kaar,
%         mis algab polaarnurgalt $a$. Kulgemissuund sama nagu enne.}
%  semicircle(O,r,a)
%  semicircle(r,a)
%  semicircle(O,r,a,true)
%  semicircle(r,a,true)
%  semicircle(O,r,a,false)
%  semicircle(r,a,false)

%  Punkt [$O$], raadius $r$, punkt $A$, suunaindikaator [$n$].
%  Keskpunktiga $O$ ja raadiusega $r$ määratud poolringjoone kaar,
%         mis algab kiirelt $OA$. Kulgemissuund sama nagu enne.
%  semicircle(O,r,A)
%  semicircle(r,A)
%  semicircle(O,r,A,true)
%  semicircle(r,A,true)
%  semicircle(O,r,A,false)
%  semicircle(r,A,false)
%%-------------------------------------------------------
vardef semicircle(text t)=
  save $,_npairn,_npathn,_nnumericn,_nbooleann,_nothern,_coco;
  path $; _npairn:=0; _npathn:=0; _nnumericn:=0; _nbooleann:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (boolean _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    elseif (boolean _stexts): _nbooleann:=_nbooleann+1; _bo[_nbooleann]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

    if (_npairn=2) and (_npathn+_nnumericn+_nbooleann+_nothern=0):
      save A,B;
      path c;
      pair A,B;
      A:=_t1; B:=_t2;
      if (A<>B):
        save O; pair O; O:=.5[A,B];
        if (xpart A = xpart B) and (ypart A < ypart B):
          $:=arc(O,A,180);
          $
        elseif (xpart A = xpart B):
          $:=arc(O,B,180);
          $
        elseif (xpart A < xpart B):
          $:=arc(O,B,180);
          $
        else:
          $:=arc(O,A,180);
          $
        fi
      else: errmessage "Illegal parameters for semicircle";
      fi
    elseif (_npairn=2) and (_nbooleann=1) and (_nnumericn+_npathn+_nothern=0) and (fnumeric1=1) and (fnumeric2=1):
      save A,B,nr;
      pair A,B;
      boolean nr;
      A:=_t1; B:=_t2; nr:=_bo1;
      if (nr=true):
        $:=semicircle(A,B);
        $
      elseif(nr=false):
        if (A<>B):
          save O; pair O; O:=.5[A,B];
          if (xpart A = xpart B) and (ypart A < ypart B):
            $:=arc(O,B,180);
            $
          elseif (xpart A = xpart B):
            $:=arc(O,A,180);
            $
          elseif (xpart A < xpart B):
            $:=arc(O,A,180);
            $
          else:
            $:=arc(O,B,180);
            $
          fi
        else: errmessage "Illegal parameters for semicircle";
        fi
      else: errmessage "Illegal parameters for semicircle";
      fi
    elseif (_npathn=1) and (_nnumericn+_nbooleann+_npairn+_nothern=0):
      save l;
      path l;
      l:=_c1;
      if (issegment(l)):
        $:=semicircle(startingpoint(l),endpoint(l));
        $
      else: errmessage "Given parameter is not a segment";
      fi
    elseif (_npathn=1) and (_nbooleann=1) and (_nnumericn+_npairn+_nothern=0) and (fnumeric1=2):
      save l,nr;
      path l;
      boolean nr;
      l:=_c1; nr:=_bo1;
      if (nr=true):
        $:=semicircle(l);
        $
      elseif(nr=false):
        if (issegment(l)):
          $:=semicircle(startingpoint(l),endpoint(l),nr);
          $
        else: errmessage "Given parameter is not a segment";
        fi
      fi
    elseif (_npathn=1) and (_nnumericn=1) and (_nbooleann+_npairn+_nothern=0) and (fnumeric1=2):
      save c,a;
      path c;
      numeric a;
      c:=_c1; a:=_n1;
      if (iscircle(c)):
        save A; pair A; A:=polarpoint(c,a);
        save B; pair B; B:=polarpoint(c,a+180);
        $:=semicircle(A,B);
        $
      else: errmessage "Given parameter is not a circle";
      fi
    elseif (_npathn=1) and (_nnumericn=1) and (_nbooleann=1) and (_npairn+_nothern=0) and (fnumeric1=2) and (fnumeric2=3):
      save c,a,nr;
      path c;
      numeric a;
      boolean nr;
      c:=_c1; a:=_n1; nr:=_bo1;
      if (nr=true):
        $:=semicircle(c,a);
        $
      elseif(nr=false):
        if (iscircle(c)):
          save A; pair A; A:=polarpoint(c,a);
          save B; pair B; B:=polarpoint(c,a+180);
          $:=semicircle(A,B,nr);
          $
        else: errmessage "Given parameter is not a circle";
        fi
      fi
    elseif (_npathn=1) and (_npairn=1) and (_nnumericn+_nbooleann+_nothern=0) and (fnumeric1=2):
      save c,A;
      path c;
      pair A;
      c:=_c1; A:=_t1;
      if (iscircle(c)):
        save a; numeric a; a:=polarangle(center(c),A);
        $:=semicircle(c,a);
        $
      else: errmessage "Given parameter is not a circle";
      fi
    elseif (_npathn=1) and (_npairn=1) and (_nbooleann=1) and (_nnumericn+_nothern=0) and (fnumeric1=2) and (fnumeric2=1):
      save c,A,nr;
      path c;
      pair A;
      boolean nr;
      c:=_c1; A:=_t1; nr:=_bo1;
      if (nr=true):
        $:=semicircle(c,A);
        $
      elseif(nr=false):
        if (iscircle(c)):
          save a; numeric a; a:=polarangle(center(c),A);
          $:=semicircle(c,a,nr);
          $
        else: errmessage "Given parameter is not a circle";
        fi
      fi
    elseif (_npairn=1) and (_nnumericn=2) and (_npathn+_nbooleann+_nothern=0) and (fnumeric1=1):
      save O,r,a;
      pair O;
      numeric r,a;
      O:=_t1; r:=_n1; a:=_n2;
      if (r>0):
        save c; path c; c:=circle(O,r);
        $:=semicircle(c,a);
        $
      else: errmessage "Given radius is illegal";
      fi
    elseif (_nnumericn=2) and (_npairn=1) and (_nbooleann=1) and (_npathn+_nothern=0) and (fnumeric1=1) and (fnumeric2=3):
      save O,r,a,nr;
      pair O;
      numeric r,a;
      boolean nr;
      O:=_t1; r:=_n1; a:=_n2; nr:=_bo1;
      if (r>0):
        save c; path c; c:=circle(O,r);
        if (nr=true):
          $:=semicircle(c,a);
          $
        elseif(nr=false):
            $:=semicircle(c,a,nr);
            $
        fi
      else: errmessage "Given radius is illegal";
      fi
    elseif (_nnumericn=2) and (_npairn+_npathn+_nbooleann+_nothern=0):
      save r,a;
      numeric r,a;
      r:=_n1; a:=_n2;
      $:=semicircle(origin,r,a);
      $
    elseif (_nnumericn=2) and (_nbooleann=1) and (_npairn+_npathn+_nothern=0) and (fnumeric1=3) and (fnumeric2=3):
      save r,a,nr;
      numeric r,a;
      boolean nr;
      r:=_n1; a:=_n2; nr:=_bo1;
      if (nr=true):
        $:=semicircle(r,a);
        $
      elseif(nr=false):
          $:=semicircle(origin,r,a,nr);
          $
      fi
    elseif (_npairn=2) and (_nnumericn=1) and (_npathn+_nbooleann+_nothern=0) and (fnumeric2=3):
      save O,r,A;
      pair O,A;
      numeric r;
      O:=_t1; A:=_t2; r:=_n1;
      if (r>0):
        save c; path c; c:=circle(O,r);
        $:=semicircle(c,A);
        $
      else: errmessage "Given radius is illegal";
      fi
    elseif (_nnumericn=1) and (_npairn=2) and (_nbooleann=1) and (_npathn+_nothern=0) and (fnumeric1=1) and (fnumeric2=3):
      save O,r,A,nr;
      pair O,A;
      numeric r;
      boolean nr;
      O:=_t1; A:=_t2; r:=_n1; nr:=_bo1;
      if (r>0):
        save c; path c; c:=circle(O,r);
        if (nr=true):
          $:=semicircle(c,A);
          $
        elseif(nr=false):
            $:=semicircle(c,A,nr);
            $
        fi
      else: errmessage "Given radius is illegal";
      fi
    elseif (_nnumericn=1) and (_npairn=1) and (_npathn+_nbooleann+_nothern=0) and (fnumeric2=1):
      save r,A;
      pair A;
      numeric r;
      r:=_n1; A:=_t1;
      $:=semicircle(origin,r,A);
      $
    elseif (_nnumericn=1) and (_nbooleann=1) and (_npairn=1) and (_npathn+_nothern=0) and (fnumeric1=3) and (fnumeric2=1):
      save r,A,nr;
      pair A;
      numeric r;
      boolean nr;
      r:=_n1; A:=_t1; nr:=_bo1;
      if (nr=true):
        $:=semicircle(r,A);
        $
      elseif(nr=false):
          $:=semicircle(origin,r,A,nr);
          $
      fi
    else: errmessage "Illegal parameters for circlearc";
    fi
enddef;
%%-------------------------------------------------------
%% Kolmnurgaga seotud ringjooned ========================
%  Ümberringjoon.
%  Kolm punkti $A$, $B$, $C$.
%  Kolmnurga $ABC$ ümberringjoon joonena
%  circumcircle(A,B,C)
%  circle(A,B,C)

%  Kolm punkti $A$, $B$, $C$.
%  Kolmnurga $ABC$ siseringjoon
%  incircle(A,B,C)
%%-------------------------------------------------------
def incircle(expr a, b, c) =
  circle (incenter(a,b,c), inradius(a,b,c))
enddef;
%%-------------------------------------------------------
%  Külgringjoon.
%  Kolm punkti $A$, $B$, $C$.
%  Kolmnurga $ABC$ külgringjoon, mis puutub külge $BC$.
%  excircle(A,B,C)
%%-------------------------------------------------------
def excircle(expr a, b, c) =
  circle (excenter(a,b,c), exradius(a,b,c))
enddef;
%%-------------------------------------------------------
%=== Hulknurgad =========================================
%% Hulknurk küljepikkuste ja sisenurkade järgi.
%  Küljepikkuste ja sisenurkade järjend $a_1$,
%         $\phi_1$, $a_2$, $\phi_2$, \dots, $a_{n-1}$.
%  Hulknurk (kinnine joon), mille esimene tipp on $A_1 = (0,0)$, esimene
%         külg on paralleelne $x$-teljega ning ülejäänud tipud on
%         arvutatud.
%  polygon($a_1$,$\phi_1$, \ldots, $a_{n-1}$)
%%-------------------------------------------------------
vardef polygon (text a) =
  vertices.A(a);
  for i=1 upto A.n: A[i]-- endfor cycle
enddef;
%%-------------------------------------------------------
%  Hulknurga tippude nimekiri küljepikkuste ja sisenurkade järgi.
%  Küljepikkuste ja sisenurkade järjend $a_1$,
%         $\phi_1$, $a_2$, $\phi_2$, \dots, $a_{n-1}$. Massiivi nimi $A$.
%  Hulknura tippude järjend massivis, esimene tipp on $A_1 = (0,0)$, esimene
%         külg on paralleelne $x$-teljega ning ülejäänud tipud on $A_2\ldots A_n$.
%         Hulknurga tippude arv on muutujas $A.n$
%  vertices.$A$($a_1$,$\phi_1$, \ldots, $a_{n-1}$
%%-------------------------------------------------------
vardef vertices@# (text a) =
  save ang,cnt;
  numeric @#.n, ang, cnt;
  pair @#[];
  @#1 := (0,0);
  ang := 0;
  @#.n := 1;
  cnt := 1;
  for s = a:
    if (cnt=1) :
		  @#.n := (@#.n)+1;
    	@#[(@#.n)] := polarpoint (@#[(@#.n)-1],s, ang);
	  else:
		  ang := 180 - s + ang;
	  fi
	cnt:= 1-cnt;
  endfor
enddef;
%%-------------------------------------------------------
%  Korrapärane hulknurk.
%  Hulknurga nurkade arv $n$, keskpunkt [$O$] ja küljepikkus [$x$].
%  Korrapärane $n$-nurk (kinnise joonena), mille alumine külg on paralleelne
%         $x$-teljega. Külje pikkus on vaikimisi $x=1$
%  regularpolygon(n,O,x)
%  regularpolygon(n,O)
%  regularpolygon(n,x)
%  regularpolygon(n)
%%-------------------------------------------------------
vardef regularpolygon(text t) =
  save $,_npairn,_nnumericn,_nothern, _coco;
  path $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (numeric _stexts): fnumeric[_coco]:=2;
    else:                     fnumeric[_coco]:=3;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn=1) and (_nnumericn=2) and (_nothern=0) and (fnumeric2=1):
    save n,O,x;
    pair O,tmppair[];
    numeric n,x;
    O:=_t1; n:=_n1; x:=_n2;
    if ((n>1) and (n=round(n))):
      if (x>0):
        save ang,r,rr;
        numeric ang,r,rr;
        ang:=360/n; rr:=x/2/sind(180/n); r:=rr*cosd(180/n);
        tmppair[1]:=O shifted(x/2,-r);
        for i=2 upto n:
          tmppair[i]:=polarpoint(O,rr,tmppair[i-1],ang);
        endfor

        for i=1 upto n:
          tmppair[i]--
        endfor
        cycle
      else: errmessage "Illegal side length for regularpolygon";
      fi
    else: errmessage "Illegal sides number for regularpolygon";
    fi
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric2=1):
    save n,O, x;
    pair O,tmppair[];
    numeric n,x;
    O:=_t1; n:=_n1; x:=1;
    if ((n>1) and (n=round(n))):
      if (x>0):
        save ang,r,rr;
        numeric ang,r,rr;
        ang:=360/n; rr:=x/2/sind(180/n); r:=rr*cosd(180/n);
        tmppair[1]:=O shifted(x/2,-r);
        for i=2 upto n:
          tmppair[i]:=polarpoint(O,rr,tmppair[i-1],ang);
        endfor

        for i=1 upto n:
          tmppair[i]--
        endfor
        cycle
      else: errmessage "Illegal side length for regularpolygon";
      fi
    else: errmessage "Illegal sides number for regularpolygon";
    fi
  elseif (_npairn=0) and (_nnumericn=2) and (_nothern=0):
    save n,x, O;
    pair O,tmppair[];
    numeric n,x;
    O:=origin; n:=_n1; x:=_n2;
    if ((n>1) and (n=round(n))):
      if (x>0):
        save ang,r,rr;
        numeric ang,r,rr;
        ang:=360/n; rr:=x/2/sind(180/n); r:=rr*cosd(180/n);
        tmppair[1]:=O shifted(x/2,-r);
        for i=2 upto n:
          tmppair[i]:=polarpoint(O,rr,tmppair[i-1],ang);
        endfor

        for i=1 upto n:
          tmppair[i]--
        endfor
        cycle
      else: errmessage "Illegal side length for regularpolygon";
      fi
    else: errmessage "Illegal sides number for regularpolygon";
    fi
  elseif (_npairn=0) and (_nnumericn=1) and (_nothern=0):
    save n, O,x;
    pair O,tmppair[];
    numeric n,x;
    O:=origin; n:=_n1; x:=1;
    if ((n>1) and (n=round(n))):
      if (x>0):
        save ang,r,rr;
        numeric ang,r,rr;
        ang:=360/n; rr:=x/2/sind(180/n); r:=rr*cosd(180/n);
        tmppair[1]:=O shifted(x/2,-r);
        for i=2 upto n:
          tmppair[i]:=polarpoint(O,rr,tmppair[i-1],ang);
        endfor

        for i=1 upto n:
          tmppair[i]--
        endfor
        cycle
      else: errmessage "Illegal side length for regularpolygon";
      fi
    else: errmessage "Illegal sides number for regularpolygon";
    fi
  else: errmessage "Illegal arguments for regularpolygon";
  fi
enddef;
%%-------------------------------------------------------
%=== Teisendused =================================================
% Metapostis on olemas tüüp \texttt{transform}, kõik teisendused, mis
% võimalik, tuleks defineerida seda tüüpi objektidena.
%
% Kui käsus asub mõni antud punkt nurksulgudes, siis võib selle punkti ära
% jätta, sellisel juhul võetakse tema rolli koordinaatide alguspunkt.
%
%% Põhiteisendused
%  Lüke.
%  Punkt [$A$] ja punkt $B$.
%  Lüke, mis teisendab punkti $A$ punktiks $B$.
%  shift(A,B)
%  shift(B)

%  Punkt [$A$], punkt $B$ ja pikkus $d$.
%  Lüke vektori $\vek{AB}$ suunas pikkuse $d$ võrra
%  shift(A,B,d)
%  shift(B,d)

%  Käsu \texttt{transformed shift} lühikuju on \texttt{Shifted}.
%%-------------------------------------------------------
def Shifted = transformed shift enddef;
vardef shift(text t)=
  save $,_npairn,_nnumericn,_nothern,_coco;
  transform $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (picture _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn=1) and (_nnumericn=0) and (_nothern=0):
    save P;
    pair P;
    P:=_t1;
    $:=identity shifted(P);
    $
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric2=3):
    save P,w;
    pair P;
    numeric w;
    P:=_t1; w:=_n1;
    $:=identity shifted(w*unitvector(P));
    $
  elseif (_npairn=2) and (_nnumericn=0) and (_nothern=0):
    save P,Q;
    pair P,Q;
    P:=_t1; Q:=_t2;
    $:=identity shifted(Q-P);
    $
  elseif (_npairn=2) and (_nnumericn=1) and (_nothern=0) and (fnumeric3=3):
    save P,Q,w;
    pair P,Q;
    numeric w;
    P:=_t1; Q:=_t2; w:=_n1;
    $:=identity shifted(w*unitvector(Q-P));
    $
  else: errmessage "Illegal parameters for shift";
  fi
enddef;
%%-------------------------------------------------------
%  Pööre.
%  Punkt [$O$] ja nurk $a$.
%  Pööre ümber punkti $O$ nurga $a$ võrra.
%  rotation(O,a)
%  rotation(a)

%  Punkt [$O$] ning kaks punkti $A$ ja $B$.
%  Pööre vastupäeva ümber punkti $O$ nii, et kiir $OA$ teiseneb
%         kiireks $OB$.
%  rotation(O,A,B)
%  rotation(A,B)

%  Käsu \texttt{transformed rotation} lühikuju on \texttt{Rotated}.
%%-------------------------------------------------------
def Rotated = transformed rotation enddef;
vardef rotation(text t)=
  save $,_npairn,_nnumericn,_nothern,_coco;
  transform $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (picture _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn=0) and (_nnumericn=1) and (_nothern=0):
    save p;
    numeric p;
    p:=_n1;
    $:=identity rotated(p);
    $
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1):
    save O,a;
    pair O;
    numeric a;
    O:=_t1; a:=_n1;
    $:=identity rotatedaround(O,a);
    $
  elseif (_npairn=2) and (_nnumericn=0) and (_nothern=0):
    save P,Q;
    pair P,Q;
    P:=_t1; Q:=_t2;
    $:=identity rotatedaround(origin,dirangle(P,origin,Q));
    $
  elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
    save P,Q,R;
    pair P,Q,R;
    P:=_t1; Q:=_t2; R:=_t3;
    $:=identity rotatedaround(P,dirangle(Q,P,R));
    $
  else: errmessage "Illegal parameters for rotation";
  fi
enddef;
%%-------------------------------------------------------
%  Peegeldus.
%  Sirge punktid [$A$] ja $B$.
%  Peegeldus sirgest $AB$.
%  reflection(A,B)
%  reflection(B)

%    Käsu \texttt{transformed reflection} lühikuju on \texttt{Reflected}.
%%-------------------------------------------------------
def Reflected = transformed reflection enddef;
vardef reflection(text t)=
  save $,_npairn,_nothern;
  transform $; _npairn:=0; _nothern:=0;

  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn=1) and (_nothern=0):
    save B;
    pair B;
    B:=_t1;
    $:=identity reflectedabout(origin,B);
    $
  elseif (_npairn=2) and (_nothern=0):
    save P,Q;
    pair P,Q;
    P:=_t1; Q:=_t2;
    $:=identity reflectedabout(P,Q);
    $
  else: errmessage "Illegal parameters for reflection";
  fi
enddef;
%%-------------------------------------------------------
%  Punkt $O$.
%  Peegeldus punktist $O$.
%  creflection(O)

%    See on samaväärne nii pöördega $180^\circ$ võrra kui ka homoteetiaga
%    punkti $O$ suhtes teguriga $-1$.
%
%    Käsu \texttt{transformed creflection} lühikuju on
%    \texttt{CReflected}.
%%-------------------------------------------------------
def CReflected = transformed creflection enddef;
def creflection(expr o)=
 if (pair o):
   rotation(o,180)
 else: errmessage "Illegal parameters for creflection";
 fi
enddef;
%%-------------------------------------------------------
%  Venitus (kokkusurumine).
%  Selles käsus võib nurksulgudes märgitud pikkuse $d$ ära jätta,
%    sellisel juhul loetakse $d=0$.
%
%  Punkt [$O$], nurk $a$, tegur $k$, pikkus [$d$].
%  Venitusteisendus, mille puhul suvalise punktist $O$ lähtuva
%         vektori nurga $a$ sihiline komponent suureneb $k$ korda ja
%         sellega ristuv (parempoolne) komponent $d$ võrra.
%  stretching(O,a,k)
%  stretching(a,k)
%  stretching(O,a,k,d)
%  stretching(a,k,d)

%  Punktid [$O$] ja $A$, tegur $k$, pikkus [$d$].
%  Venitusteisendus, mille puhul venitus $k$ korda on määratud
%        vektoriga $\vek{OA}$ ning järgnev lüke $d$ võrra on määratud
%        ristuva vektoriga.
%  stretching(O,A,k)
%  stretching(O,A,k,d)

%  Punktid [$O$], $A$ ja $B$.
%  Venitusteisendus koos paralleellükkega: vektori $OA$ alguspunkt
%         jääb punkti $O$ läbivale ristsirgele ning lõpp-punkt teiseneb
%         punktiks $B$.
%  stretching(O,A,B)
%  stretching(A,B)

%    Käsu \texttt{transformed stretching} lühikuju on \texttt{Stretched}.
%%-------------------------------------------------------
def Stretched = transformed stretching enddef;
vardef stretching(text t)=
  save $,_npairn,_nnumericn,_nothern,_coco;
  transform $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (picture _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn=1) and (_nnumericn=3) and (_nothern=0) and (fnumeric1=1):
    save O,a,k,d;
    pair O;
    numeric a,k,d;
    O:=_t1; a:=_n1; k:=_n2; d:=_n3;
    $:=identity shifted (origin-O) rotatedaround(origin,-a) xscaled k shifted (0,-d) rotatedaround(origin,a) shifted (O-origin);
    $
  elseif (_npairn=1) and (_nnumericn=2) and (_nothern=0) and (fnumeric1=1):
    save O,a,k;
    pair O;
    numeric a,k;
    O:=_t1; a:=_n1; k:=_n2;
    $:=stretching(O,a,k,0);
    $
  elseif (_npairn=0) and (_nnumericn=2) and (_nothern=0):
    save a,k;
    numeric a,k;
    a:=_n1; k:=_n2;
    $:=stretching(origin,a,k,0);
    $
  elseif (_npairn=0) and (_nnumericn=3) and (_nothern=0):
    save a,k,d;
    numeric a,k,d;
    a:=_n1; k:=_n2; d:=_n3;
    $:=stretching(origin,a,k,d);
    $
  elseif (_npairn=2) and (_nnumericn=2) and (_nothern=0) and (fnumeric1=1) and (fnumeric2=1):
    save O,A,k,d;
    pair O,A;
    numeric k,d;
    O:=_t1; A:=_t2; k:=_n1; d:=_n2;
    if (O<>A):
      $:=identity shifted (origin-O) rotatedaround(origin,-angle(A-O)) xscaled k shifted (0,-d) rotatedaround(origin,angle(A-O)) shifted (O-origin);
      $
    else: errmessage "Illegal parameters for stretching";
    fi
  elseif (_npairn=2) and (_nnumericn=1) and (_nothern=0) and (fnumeric3=3):
    save O,A,k;
    pair O,A;
    numeric k;
    O:=_t1; A:=_t2; k:=_n1;
    $:=stretching(O,A,k,0);
    $
  elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
    save O,A,B;
    save BB,k,d;
    pair O,A,B,BB;
    numeric k,d;
    O:=_t1; A:=_t2; B:=_t3;
    if (O<>A):
      BB:=B Projected(O,A); k:=dist(O,BB)/dist(O,A); d:=dist(B,BB);
      $:=identity shifted (origin-O) rotatedaround(origin,-angle(A-O)) xscaled k shifted (0,-d) rotatedaround(origin, angle(A-O)) shifted (O-origin);
      $
    else: errmessage "Illegal parameters for stretching";
    fi
  elseif (_npairn=2) and (_nnumericn=0) and (_nothern=0):
    save A,B;
    pair A,B;
    A:=_t1; B:=_t2;
    $:=stretching(origin,A,B);
    $
  else: errmessage "Illegal parameters for stretching";
  fi
enddef;
%%-------------------------------------------------------
%  Punktid [$A$] ja $B$, tegur $k$, pikkus [$d$].
%  Venitusteisendus, mille puhul iga tasandipunkti kaugus sirgest
%         $AB$ suureneb $k$ korda, sellele lisandub nihe sirge $AB$
%         suunas $d$ võrra.
%  orthostretching(A,B,k)
%  orthostretching(A,B,k,d)

%  Punkt [$A$], nurk $a$, tegur $k$, pikkus [$d$].
%  Venitusteisendus, mille puhul iga tasandipunkti kaugus sirgest,
%         mis läbib punkti $A$ nurga all $a$, suureneb $k$ korda, sellele
%         lisandub nihe sirge $AB$ suunas $d$ võrra.
%  orthostretching(A,a,k)
%  orthostretching(a,k)
%  orthostretching(A,a,k,d)
%  orthostretching(a,k,d)

%  Punktid [$A$] ja $B$ ning punktid $X$ ja $Y$.
%  Venitusteisendus sirge $AB$ suhtes koos paralleellükkega, mille
%         käigus punkt $X$ teiseneb punktiks $Y$.
%  orthostretching(A,B,X,Y)
%  orthostretching(B,X,Y)

%  Käsu \texttt{transformed orthostretching} lühikuju on
%    \texttt{Orthostretched}.
%%-------------------------------------------------------
def Orthostretched = transformed orthostretching enddef;
vardef orthostretching(text t)=
  save $,_npairn,_nnumericn,_nothern,_coco;
  transform $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (picture _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn=2) and (_nnumericn=2) and (_nothern=0) and (fnumeric1=1) and (fnumeric2=1):
    save A,B,k,d;
    pair A,B;
    numeric k,d;
    A:=_t1; B:=_t2; k:=_n1; d:=_n2;
    if (A<>B):
      $:=identity shifted (origin-A) rotatedaround(origin,-angle(B-A)) yscaled k shifted(d,0) rotatedaround(origin,angle(B-A)) shifted (A-origin);
      $
    else: errmessage "Illegal parameters for orthostretching";
    fi
  elseif (_npairn=2) and (_nnumericn=1) and (_nothern=0) and (fnumeric3=3):
    save A,B,k;
    pair A,B;
    numeric k;
    A:=_t1; B:=_t2; k:=_n1;
    $:=orthostretching(A,B,k,0);
    $
  elseif (_npairn=1) and (_nnumericn=3) and (_nothern=0) and (fnumeric1=1):
    save A,a,k,d;
    pair A;
    numeric a,k,d;
    A:=_t1; a:=_n1; k:=_n2; d:=_n3;
    $:=identity shifted (origin-A) rotatedaround(origin,-a) yscaled k shifted (d,0) rotatedaround(origin,a) shifted (A-origin);
    $
  elseif (_npairn=0) and (_nnumericn=3) and (_nothern=0):
    save a,k,d;
    numeric a,k,d;
    a:=_n1; k:=_n2; d:=_n3;
    $:=orthostretching(origin,a,k,d);
    $
  elseif (_npairn=1) and (_nnumericn=2) and (_nothern=0) and (fnumeric1=1):
    save A,a,k;
    pair A;
    numeric a,k;
    A:=_t1; a:=_n1; k:=_n2;
    $:=orthostretching(A,a,k,0);
    $
  elseif (_npairn=0) and (_nnumericn=2) and (_nothern=0):
    save a,k;
    numeric a,k;
    a:=_n1; k:=_n2;
    $:=orthostretching(origin,a,k,0);
    $
  elseif (_npairn=4) and (_nnumericn=0) and (_nothern=0):
    save P,Q,R,S;
    pair P,Q,R,S;
    P:=_t1; Q:=_t2; R:=_t3; S:=_t4;
    R                  transformed $ = S;
    (R Projected(P,Q)) transformed $ = (S Projected(P,Q));
    (S Projected(P,Q)) transformed $ = (S Projected(P,Q))+((S Projected(P,Q))-(R Projected(P,Q)));
    $
  elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
    save Q,R,S;
    pair Q,R,S;
    Q:=_t1; R:=_t2; S:=_t3;
    R                       transformed $ = S;
    (R Projected(origin,Q)) transformed $ = (S Projected(origin,Q));
    (S Projected(origin,Q)) transformed $ = (S Projected(origin,Q))+((S Projected(origin,Q))-(R Projected(origin,Q)));
    $
  else: errmessage "Illegal parameters for orthostretching";
  fi
enddef;
%%-------------------------------------------------------
%  Homoteetia ja pöördehomoteetia.
%  Homoteetsuskeskpunkt [$O$] ja tegur $k$.
%  Homoteetsusteisendus.
%  homothety(O,k)
%  homothety(k)

%  See on kompositsioon teisendustest \texttt{scaled} ja
%    \texttt{shifted}. Teiselt poolt on see pöördehomoteetia erijuht, kus
%    pöördenurk on $0^\circ$.

%  Homoteetsuskeskpunkt [$O$], tegur $k$, nurk $a$.
%  Pöördehomoteetia, mille keskpunkt on $O$ ja tegur $k$ ning mis
%         lisaks pöörab kujutist nurga $a$ võrra ümber punkti $O$.
%  homothety(O,k,a)
%  homothety(k,a)

%  Homoteetsuskeskpunkt [$O$], punktid $A$ ja $B$.
%  Pöördehomoteetia, mille keskpunkt on $O$ ja mis viib punkti $A$
%         punktiks $B$.
%  homothety(O,A,B)
%  homothety(A,B)

%  Käsu \texttt{transformed homothety} lühikuju on
%    \texttt{Scaled}.
%%-------------------------------------------------------
def Scaled = transformed homothety enddef;
vardef homothety(text t)=
  save $,_npairn,_nnumericn,_nothern,_coco;
  transform $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (picture _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn=0) and (_nnumericn=1) and (_nothern=0):
    save k;
    numeric k;
    k:=_n1;
    $:=identity scaled k shifted origin;
    $
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0) and (fnumeric1=1):
    save O,k;
    pair O;
    numeric k;
    O:=_t1; k:=_n1;
    $:=identity shifted -O scaled k shifted O;
    $
  elseif (_npairn=1) and (_nnumericn=2) and (_nothern=0) and (fnumeric1=1):
    save O,k,a;
    pair O;
    numeric k,a;
    O:=_t1; k:=_n1; a:=_n2;
    $:=identity shifted -O scaled k shifted O rotatedaround(O,a);
    $
  elseif (_npairn=0) and (_nnumericn=2) and (_nothern=0):
    save k,a;
    numeric k,a;
    k:=_n1; a:=_n2;
    $:=identity scaled k shifted origin rotated(a);
    $
  elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
    save P,Q,R;
    pair P,Q,R;
    P:=_t1; Q:=_t2; R:=_t3;
    $:=identity shifted -P scaled (dist(P,R)/dist(P,Q)) shifted P rotatedaround(P,angle(Q,P,R));
    $
  elseif (_npairn=2) and (_nnumericn=0) and (_nothern=0):
    save P,Q;
    pair P,Q;
    P:=_t1; Q:=_t2;
    $:=identity shifted -origin scaled (dist(origin,Q)/dist(origin,P)) shifted origin rotatedaround(origin,angle(P,origin,Q));
    $
  else: errmessage "Illegal parameters for homothety";
  fi
enddef;
%%-------------------------------------------------------
%  Paralleelprojektsioon.
%  Sirge punktid [$A$] ja $B$.
%  Ristprojektsioon sirgele $AB$.
%  projection(A,B)
%  projection(B)

%  Sirge punktid [$A$] ja $B$ ning nurk $a$.
%  Kaldprojektsioon, mis projekteerib tasandi punktid
%        sirgele $AB$ suunanurgaga $a$.
%  projection(A,B,a)
%  projection(B,a)

%  Erijuhul, kui $a=90^\circ$, saame ristprojektsiooni.

%  Sirge punktid [$A$] ja $B$ ning projektsiooni sihti näitava
%        vektori otspunktid $C$ ja $D$.
%  Projektsiooniteisendus, mis projekteerib tasandi punktid
%        sirgele $AB$ vektori $CD$ sihis.
%  projection(A,B,C,D)
%  projection(B,C,D)

%    Käsu \texttt{transformed projection} lühikuju on \texttt{Projected}.
%%-------------------------------------------------------
def Projected = transformed projection enddef;
vardef projection(text t)=
  save $,_npairn,_nnumericn,_nothern,_coco;
  transform $; _npairn:=0; _nnumericn:=0; _nothern:=0; _coco:=0;

  for _stexts=t:
    _coco:=_coco+1;
    if     (pair _stexts):    fnumeric[_coco]:=1;
    elseif (path _stexts):    fnumeric[_coco]:=2;
    elseif (numeric _stexts): fnumeric[_coco]:=3;
    elseif (picture _stexts): fnumeric[_coco]:=4;
    else:                     fnumeric[_coco]:=5;
    fi

    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_npairn=1) and (_nnumericn=0) and (_nothern=0):  % orthogonal projection(B)
    save P;
    pair P;
    P:=_t1;
    (0,1) transformed $ = whatever[P,origin]=whatever[(0,1),(0,1) reflectedabout(P,origin)];
    (1,1) transformed $ = whatever[P,origin]=whatever[(1,1),(1,1) reflectedabout(P,origin)];
    (1,0) transformed $ = whatever[P,origin]=whatever[(1,0),(1,0) reflectedabout(P,origin)];
    $
  elseif (_npairn=2) and (_nnumericn=0) and (_nothern=0): % orthogonal projection(A,B)
    save P,Q;
    pair P,Q;
    P:=_t1; Q:=_t2;
    (0,1) transformed $ = whatever[P,Q]=whatever[(0,1),(0,1) reflectedabout(P,Q)];
    (1,1) transformed $ = whatever[P,Q]=whatever[(1,1),(1,1) reflectedabout(P,Q)];
    (1,0) transformed $ = whatever[P,Q]=whatever[(1,0),(1,0) reflectedabout(P,Q)];
    $
  elseif (_npairn=2) and (_nnumericn=1) and (_nothern=0): % parallel projection(A,B,a)
    save P,Q,T,a;
    pair P,Q,T;
    numeric a;
    P:=_t1; Q:=_t2; a:=_n1;
    T:=(cosd(a),sind(a));
    (0,1) transformed $ = whatever[P,Q]=whatever[(0,1),(0,1)+T];
    (1,1) transformed $ = whatever[P,Q]=whatever[(1,1),(1,1)+T];
    (1,0) transformed $ = whatever[P,Q]=whatever[(1,0),(1,0)+T];
    $
  elseif (_npairn=1) and (_nnumericn=1) and (_nothern=0): % parallel projection(B,a)
    save P,T,a;
    pair P,T;
    numeric a;
    P:=_t1; a:=_n1;
    T:=(cosd(a),sind(a));
    (0,1) transformed $ = whatever[P,origin]=whatever[(0,1),(0,1)+T];
    (1,1) transformed $ = whatever[P,origin]=whatever[(1,1),(1,1)+T];
    (1,0) transformed $ = whatever[P,origin]=whatever[(1,0),(1,0)+T];
    $
  elseif (_npairn=3) and (_nnumericn=0) and (_nothern=0):
    save P,Q,R;
    pair P,Q,R;
    P:=_t1; Q:=_t2; R:=_t3;
    (0,1) transformed $ = whatever[origin,P]=whatever[(0,1),(0,1)+R-Q];
    (1,1) transformed $ = whatever[origin,P]=whatever[(1,1),(1,1)+R-Q];
    (1,0) transformed $ = whatever[origin,P]=whatever[(1,0),(1,0)+R-Q];
    $
  elseif (_npairn=4) and (_nnumericn=0) and (_nothern=0):
    save P,Q,R,S;
    pair P,Q,R,S;
    P:=_t1; Q:=_t2; R:=_t3; S:=_t4;
    (0,1) transformed $ = whatever[P,Q]=whatever[(0,1),(0,1)+S-R];
    (1,1) transformed $ = whatever[P,Q]=whatever[(1,1),(1,1)+S-R];
    (1,0) transformed $ = whatever[P,Q]=whatever[(1,0),(1,0)+S-R];
    $
  else: errmessage "Illegal parameters for projection";
  fi
enddef;
%%-------------------------------------------------------
%%  Tsentraalprojektsioon.
%   Et tsentraalprojektsioon ei kuulu Metaposti \texttt{transform}-tüüpi
%    teisenduste hulka, siis saab teda realiseerida ainult makrona, mis
%    arvutab välja iga etteantud punkti kujutise.
%
%  Projektsioonikeskpunkt [$O$], sirge punktid $A$ ja $B$, tasandi
%         punkt $X$.
%  Punkti $X$ kujutis projektsioonil punktist $O$ sirgele $AB$.
%  X CProjected from(O,A,B)
%  X CProjected from(A,B)
%%-------------------------------------------------------
vardef from(text t)=
  save _npairn,_npathn,_nnumericn,_nothern,$;
  path $;
  _npairn:=0; _npathn:=0; _nnumericn:=0; _nothern:=0;
  for _stexts=t:
    if (pair _stexts): _npairn:=_npairn+1; _t[_npairn]:=_stexts;
    elseif (numeric _stexts): _nnumericn:=_nnumericn+1; _n[_nnumericn]:=_stexts;
    elseif (path _stexts): _npathn:=_npathn+1; _c[_npathn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;
  if (_npairn=3) and (_npathn+_nnumericn+_nothern=0):
    save O,A,B;
    pair O,A,B;
    O:=_t1; A:=_t2; B:=_t3;
    $:=O--A--B;
    $
  elseif (_npairn=2) and (_npathn+_nnumericn+_nothern=0):
    save A,B;
    pair A,B;
    A:=_t1; B:=_t2;
    $:=A--B;
    $
  elseif (_npairn=1) and (_npathn+_nnumericn+_nothern=0):
    save A;
    pair A;
    A:=_t1;
    if (radius(A)>0):
      $:=fullcircle scaled 2*polarradius(A) shifted A;
      $
    else: errmessage "Illegal parameters for from";
    fi
  elseif (_npairn=1) and (_nnumericn=1) and (_npathn+_nothern=0):
    save O,r;
    pair O;
    numeric r;
    O:=_t1; r:=_n1;
    if (r>0):
      $:=circle(O,r);
      $
    else: errmessage "Given radius must be greater than 0";
    fi
  elseif (_npairn=0) and (_nnumericn=1) and (_npathn+_nothern=0):
    save r;
    numeric r;
    r:=_n1;
    if (r>0):
      $:=circle(origin,r);
      $
    else: errmessage "Given radius must be greater than 0";
    fi
  elseif (_npairn=0) and (_npathn=1) and (_nnumericn=0) and (_nothern=0):
    save p;
    path p;
    p:=_c1;
    if (iscircle(p)):
      $:=p;
      $
    else: errmessage "Given parameter is not a circle";
    fi
  else: errmessage "Illegal parameters for from";
  fi
enddef;
%%-------------------------------------------------------
secondarydef X CProjected Y =
begingroup
  if (length Y =2):
    save O,A,B,$;
    pair O,A,B,$;
    O:=point 0 of Y; A:=point 1 of Y; B:=point 2 of Y;
    if (dist(O,A,B)>0):
      $:=whatever[A,B]=whatever[O,X];
      $
    else: errmessage "Illegal parameters for center of projection";
    fi
  elseif (length Y =1):
    save O,A,B,$;
    pair O,A,B,$;
    O:=origin; A:=point 0 of Y; B:=point 1 of Y;
    if (dist(O,A,B)>0):
      $:=whatever[A,B]=whatever[O,X];
      $
    else: errmessage "Illegal parameters for CProjected";
    fi
  else: errmessage "Illegal parameters for CProjected";
  fi
endgroup
enddef;
%%-------------------------------------------------------
%  Inversioon.
%  Punkt [$O$], arv $r$, punkt või joon $X$.
%  Punkti või joone $X$ kujutis inversioonil, mille keskpunkt on
%        $O$ ja raadius $r$.
%  X Inverted from(O,r)
%  X Inverted from(r)

%  Punkt [$O$], punkt $A$, punkt või joon $X$.
%  Punkti või joone $X$ kujutis inversioonil, mille keskpunkt on
%        $O$ ja raadius $|OA|$.
%  X Inverted from(O,A)
%  X Inverted from(A)

%  Ringjoon $c$, punkt või joon $X$.
%  Punkti või joone $X$ kujutis inversioonil ringjoone $c$ suhtes.}
%  X Inverted from(c)
%%-------------------------------------------------------
secondarydef X Inverted Y =
begingroup
  if (iscircle(Y)):
    save O,r,$;
    pair O;
    path $;
    O:=center(Y); r:=radius(Y);
    $:=inversion(O,r,X);
    $
  elseif (length Y =1):
    save O,r,$;
    pair O;
    path $;
    O:=point 0 of Y; r:=dist(point 0 of Y,point 1 of Y);
    if (r>0):
      if pair X:
        pair $;
        $:=inversion(O,r,X);
        $
      elseif path X:
        path $;
        $:=inversion(O,r,X);
        $
      fi
    else: errmessage "Illegal parameters for Inverted";
    fi
  else: errmessage "Illegal parameters for Inverted";
  fi
endgroup
enddef;
%%-------------------------------------------------------
vardef inversion(expr O,r,P)=
  if pair P:
    if (P<>O):
      O+((r/abs(P-O))**2)*(P-O)
    else: errmessage "Illegal parameters for Inverted";
    fi
  elseif path P:
    for i=0 step 1/100 until (length(P)):
       if abs(i-round(i))<0.01:
        inversion(O,r,point i of P) --
      else:
        inversion(O,r,point i of P) ..
      fi
    endfor
    inversion(O,r,(point length(P) of P))
  else: errmessage "Illegal parameters for Inverted";
  fi
enddef;
%%-------------------------------------------------------
%%%% Tehted teisendustega ===============================
%  Teisenduste kompositsioon.
%  Teisendused $T_1$, $T_2$, \dots, $T_n$.
%  Teisenduste $T_1$, $T_2$, \dots, $T_n$ kompositsioon selles
%        järjekorras.}
%  composition(T1,T2,...,Tn)
%%-------------------------------------------------------
vardef composition(text t) =
  save $,_ntransformn,_nothern;
  transform $; _ntransformn:=0; _nothern:=0;

  for _stexts=t:
    if (transform _stexts): _ntransformn:=_ntransformn+1; _tf[_ntransformn]:=_stexts;
    else: _nothern:=_nothern+1;
    fi
  endfor;

  if (_ntransformn>1) and (_nothern=0):
    $:=_tf[1] transformed _tf[2];
    if (_ntransformn>2):
      for i=3 upto _ntransformn:
        $:=$ transformed _tf[i];
      endfor;
    fi
    $
  else: errmessage "Illegal parameters for composition";
  fi

enddef;
%%-------------------------------------------------------
%  Teisenduste summa.
%  Teisendused $T_1$ ja $T_2$.
%  Teisenduste $T_1$ ja $T_2$ summa.
%  T1 tradd T2

%  Makro \texttt{tradd} on kahekohaline ja tüüpi 'secondary'.
%%-------------------------------------------------------
secondarydef t tradd u =
begingroup
  save $;
  transform $;
  if (transform t) and (transform u):
    xxpart $=xxpart t + xxpart u;
    yypart $=yypart t + yypart u;
    xypart $=xypart t + xypart u;
    yxpart $=yxpart t + yxpart u;
    xpart  $=xpart t  + xpart u;
    ypart  $=ypart t  + ypart u;
    $
  else: errmessage "Illegal parameters for tradd";
  fi
endgroup
enddef;
%%-------------------------------------------------------
%  Teisenduste vahe.
%  Teisendused $T_1$ ja $T_2$.
%  Teisenduste $T_1$ ja $T_2$ vahe.
%  T1 trsub T2

%  Makro \texttt{trsub} on kahekohaline ja tüüpi 'secondary'.
%%-------------------------------------------------------
secondarydef t trsub u =
begingroup
  save $;
  transform $;
  if (transform t) and (transform u):
    xxpart $=xxpart t - xxpart u;
    yypart $=yypart t - yypart u;
    xypart $=xypart t - xypart u;
    yxpart $=yxpart t - yxpart u;
    xpart  $=xpart t  - xpart u;
    ypart  $=ypart t  - ypart u;
    $
  else: errmessage "Illegal parameters for trsub";
  fi
endgroup
enddef;
%%-------------------------------------------------------
%  Teisenduse korrutamine arvuga.
%  Arv $k$ ja teisendus $T$.
%  Teisendus $kT$.
%  k trmul T

%  Makro \texttt{trmul} on kahekohaline ja tüüpi 'primary'.
%%-------------------------------------------------------
primarydef k trmul t =
begingroup
  save $;
  transform $;
  if (numeric k) and (transform t):
    xxpart $=xxpart t * k;
    yypart $=yypart t * k;
    xypart $=xypart t * k;
    yxpart $=yxpart t * k;
    xpart  $=xpart t  * k;
    ypart  $=ypart t  * k;
    $
  else: errmessage "Illegal parameters for trmul";
  fi
endgroup
enddef;
%%-------------------------------------------------------
%  Vastandteisendus.
%  Teisendus $T$.
%  Teisenduse $T$ vastandteisendus.
%  trneg T

%  Makro \texttt{trneg} on ühekohaline ja tüüpi 'primary'.
%%-------------------------------------------------------
vardef trneg(expr u)  =
begingroup
  save $;
  transform $;
  if (transform u):
    xxpart $=-xxpart u;
    yypart $=-yypart u;
    xypart $=-xypart u;
    yxpart $=-yxpart u;
    xpart  $=-xpart u;
    ypart  $=-ypart u;
    $
  else: errmessage "Illegal parameters for trneg";
  fi
endgroup
enddef;
%%-------------------------------------------------------
%  Nullteisendus.
%  Mitte midagi.
%  Teisendus, mis kujutab kõik punktid nulliks.
%  zerotransform
%%-------------------------------------------------------
vardef zerotransform  =
  save $;
  transform $;
    xxpart $=0;
    yypart $=0;
    xypart $=0;
    yxpart $=0;
    xpart  $=0;
    ypart  $=0;
    $
enddef;
%%-------------------------------------------------------
%Pöördteisenduse leidmiseks on juba olemas Metaposti makro
%\texttt{inverse}.
%%-------------------------------------------------------

endinput