On Pomax's Primer on Bézier Curves this "fairly funky image" appears:

This is related to the fact that every cubic Bézier curve can be put in a "canonical form" by an affine transformation that maps its first three control points to (0,0), (0,1) and (1,1) respectively. Where the fourth and last control point lies after the transformation then determines the curve's nature – suppose it lies at \$(x,y)\$, then

  • If \$y\ge1\$ the curve has a single inflection point (green region in the image).
  • If \$y\le1\$ but \$y\ge\frac{-x^2+2x+3}4\$ and \$x\le1\$ the curve has two inflection points.
  • If \$y\le\frac{-x^2+3x}3\$ and \$x\le0\$ or \$y\le\frac{\sqrt{3(4x-x^2)}-x}2\$ and \$0\le x\le1\$ or \$y\le1\$ and \$x\ge1\$ the curve is a simple arch with no inflection points.
  • In all other cases the curve has a loop (red region in the image).


Given the coordinates of the transformed curve's fourth point \$(x,y)\$ in any reasonable format, output the curve's type, which is exactly one of "arch", "single inflection", "double inflection" or "loop". If \$(x,y)\$ is on the boundary between two or more regions you may output the type corresponding to any of those regions. You may also use any four distinct values to represent the curve types.

This is ; fewest bytes wins.

Test cases

(x,y) -> type(s)
(2,2) -> single
(-1,2) -> single
(2,0) -> arch
(1,-2) -> arch
(-1,-2) -> arch
(-2,0) -> double
(-3,-1) -> double
(-1,-1) -> loop
(-3,-4) -> loop
(0,1) -> single or double
(-1,0) -> double or loop
(-3,-3) -> double or loop
(0,0) -> arch or loop
(2,1) -> arch or single
(1,1) -> single or double or arch or loop

2 Answers 2


JavaScript (ES6), 55 bytes

-2 thanks to @Neil

Returns \$false\$, \$true\$, \$2\$ or \$3\$ for double, loop, arch and single respectively.


Try it online!


  • If \$y>1\$, return \$3\$ (single inflection)
  • If \$y<x-x^2/3\$ or \$y^2<x(3-x-y)\$ or \$x>1\$, return \$2\$ (simple arch)
  • If \$4y<3-x^2+2x\$, return \$true\$ (loop)
  • Otherwise, return \$false\$ (double inflection)

Graphical output

Invoking the above function for each pixel in a 320x240 canvas.


for(ctx = document.getElementById('c').getContext('2d'), Y = 0; Y < 240; Y++) for(X = 0; X < 320; X++) { y = (Y - 80) / 100; x = (X - 160) / 100; ctx.fillStyle = X == 160 || Y == 80 || X % 100 == 60 && Y & 2 || Y == 180 && X & 2 ? "#000" : [ "#8cf", "#f44", "#fe4", "#999" ][+f(x)(y)]; ctx.fillRect(X, Y, 1, 1); }
<canvas id="c" width=320 height=240></canvas>

  • 1
    \$\begingroup\$ x=>y=>y>1?3:y<x-x*x/3|y*y<x*(3-x-y)|1<x?2:4*y<3-x*x+2*x is only 55 bytes although it gives different answers. (I think it's 2, true, 3, false respectively?) \$\endgroup\$
    – Neil
    Mar 5, 2023 at 1:41

Charcoal, 50 bytes


Try it online! Link is to verbose version of code. Outputs one of A, D, S or L. Explanation:


Input the coordinates.


Check for a single inflection.


Check for a simple arch.


Distinguish between a double inflection and a loop.

Here's an SVG I wrote because the original image was drawn on a canvas for some reason:

<svg viewbox=-3,-6,5,8><path d=M2,2H-3V-6H2 fill=#f44 /><path d=M2,2H-3V1H2 fill=#999 /><path d=M-3,1V-3Q-1,1,1,1Z fill=#8cf /><path d=M-3,-6Q-1.5,-1.5,0,0A2.449489742783178,1.4142135623730951,135,0,0,1,1H3V-6Z fill=#fe4 />


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.