Superellipse: Difference between revisions
SqrtNegInf (talk | contribs) (→{{header|Raku}}: simplified) |
SqrtNegInf (talk | contribs) m (→{{header|Raku}}: redundant 'flat's) |
||
Line 1,313: | Line 1,313: | ||
# y in terms of x |
# y in terms of x |
||
sub y ($x) { floor b × (1 - ($x |
sub y ($x) { floor b × (1 - ($x/a).abs ** n ) ** (1/n) } |
||
# find point pairs for one quadrant |
# find point pairs for one quadrant |
||
Line 1,320: | Line 1,320: | ||
my $out = open('superellipse.svg', :w); |
my $out = open('superellipse.svg', :w); |
||
$out.print: [~] qq|<svg height="{b×2}" width="{a×2}" xmlns="http://www.w3.org/2000/svg">\n|, |
$out.print: [~] qq|<svg height="{b×2}" width="{a×2}" xmlns="http://www.w3.org/2000/svg">\n|, |
||
pline( |
pline( @q ), |
||
pline( |
pline( @q «×» < 1 -1> ), # flip and mirror |
||
pline( |
pline( @q «×» <-1 -1> ), # for the other |
||
pline( |
pline( @q «×» <-1 1> ), # three quadrants |
||
'</svg>' |
'</svg>'; |
||
; |
|||
sub pline (@q) { |
sub pline (@q) { |
Revision as of 17:59, 30 July 2022
You are encouraged to solve this task according to the task description, using any language you may know.
A superellipse is a geometric figure defined as the set of all points (x, y) with
where n, a, and b are positive numbers.
- Task
Draw a superellipse with n = 2.5, and a = b = 200
Action!
<lang Action!>INCLUDE "D2:REAL.ACT" ;from the Action! Tool Kit
PROC Superellipse(INT x0 BYTE y0 REAL POINTER n BYTE a)
INT ARRAY f(100) REAL ar,xr,tmp1,tmp2,tmp3,one,invn INT x
IntToReal(1,one) RealDiv(one,n,invn) ;1/n IntToReal(a,ar) Power(ar,n,tmp1) ;a^n
Plot(x0,y0-a) FOR x=0 TO a DO IntToReal(x,xr) Power(xr,n,tmp2) ;x^n RealSub(tmp1,tmp2,tmp3) ;a^n-x^n Power(tmp3,invn,tmp2) ;(a^n-x^n)^(1/n) f(x)=RealToInt(tmp2) DrawTo(x0+x,y0-f(x)) OD
x=a WHILE x>=0 DO DrawTo(x0+x,y0+f(x)) x==-1 OD
FOR x=0 TO a DO DrawTo(x0-x,y0+f(x)) OD
x=a WHILE x>=0 DO DrawTo(x0-x,y0-f(x)) x==-1 OD
RETURN
PROC Main()
BYTE CH=$02FC,COLOR1=$02C5,COLOR2=$02C6 REAL n
Graphics(8+16) Color=1 COLOR1=$0C COLOR2=$02
ValR("2.5",n) Superellipse(160,96,n,80)
DO UNTIL CH#$FF OD CH=$FF
RETURN</lang>
- Output:
Screenshot from Atari 8-bit computer
Ada
Brute force calculation.
<lang Ada>with Ada.Numerics.Elementary_Functions;
with SDL.Video.Windows.Makers; with SDL.Video.Renderers.Makers; with SDL.Events.Events;
procedure Superelipse is
Width : constant := 600; Height : constant := 600; A : constant := 200.0; B : constant := 200.0; N : constant := 2.5;
Window : SDL.Video.Windows.Window; Renderer : SDL.Video.Renderers.Renderer; Event : SDL.Events.Events.Events;
procedure Draw_Superelipse is use type SDL.C.int; use Ada.Numerics.Elementary_Functions; Xx, Yy : Float; subtype Legal_Range is Float range 0.980 .. 1.020; begin for Y in 0 .. Height loop for X in 0 .. Width loop Xx := Float (X - Width / 2); Yy := Float (Y - Height / 2); if (abs (Xx / A)) ** N + (abs (Yy / B)) ** N in Legal_Range then Renderer.Draw (Point => (X => Width / 2 + SDL.C.int (Xx), Y => Height / 2 - SDL.C.int (Yy))); end if;
end loop; end loop; end Draw_Superelipse;
procedure Wait is use type SDL.Events.Event_Types; begin loop while SDL.Events.Events.Poll (Event) loop if Event.Common.Event_Type = SDL.Events.Quit then return; end if; end loop; delay 0.100; end loop; end Wait;
begin
if not SDL.Initialise (Flags => SDL.Enable_Screen) then return; end if;
SDL.Video.Windows.Makers.Create (Win => Window, Title => "Superelipse", Position => SDL.Natural_Coordinates'(X => 10, Y => 10), Size => SDL.Positive_Sizes'(Width, Height), Flags => 0); SDL.Video.Renderers.Makers.Create (Renderer, Window.Get_Surface); Renderer.Set_Draw_Colour ((0, 0, 0, 255)); Renderer.Fill (Rectangle => (0, 0, Width, Height)); Renderer.Set_Draw_Colour ((0, 220, 0, 255));
Draw_Superelipse; Window.Update_Surface;
Wait; Window.Finalize; SDL.Finalise;
end Superelipse;</lang>
AutoHotkey
Requires Gdip Library <lang AutoHotkey>n := 2.5 a := 200 b := 200 SuperEllipse(n, a, b) return
SuperEllipse(n, a, b){
global pToken := Gdip_Startup() π := 3.141592653589793, oCoord := [], oX := [], oY := [] nn := 2/n loop 361 { t := (A_Index-1) * π/180 ; https://en.wikipedia.org/wiki/Superellipse x := abs(cos(t))**nn * a * sgn(cos(t)) y := abs(sin(t))**nn * b * sgn(sin(t)) oCoord[A_Index] := [x, y] oX[Floor(x)] := true, oY[Floor(y)] := true } dx := 0 - oX.MinIndex() + 10 dy := 0 - oY.MinIndex() + 10 w := oX.MaxIndex()-oX.MinIndex() + 20 h := oY.MaxIndex()-oY.MinIndex() + 20
Gdip1(w, h) pPen := Gdip_CreatePen("0xFF00FF00", 2) for i, obj in oCoord { x2 := obj.1+dx, y2 := obj.2+dy if i>1 Gdip_DrawLine(G, pPen, x1, y1, x2, y2) x1 := x2, y1 := y2 } UpdateLayeredWindow(hwnd, hdc)
}
- ----------------------------------------------------------------
sgn(n){
return (n>0?1:n<0?-1:0)
}
- ----------------------------------------------------------------
Gdip1(w:=0, h:=0){
global w := w ? w : A_ScreenWidth h := h ? h : A_ScreenHeight x := A_ScreenWidth/2 - w/2 y := A_ScreenHeight/2 - h/2 Gui, gdip1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop Gui, gdip1: Show, w%w% h%h% x%x% y%y% hwnd := WinExist() hbm := CreateDIBSection(w, h) hdc := CreateCompatibleDC() obm := SelectObject(hdc, hbm) G := Gdip_GraphicsFromHDC(hdc) Gdip_SetSmoothingMode(G, 4) pBrush := Gdip_BrushCreateSolid("0xFF000000") Gdip_FillRoundedRectangle(G, pBrush, 0, 0, w, h, 5) Gdip_DeleteBrush(pBrush) UpdateLayeredWindow(hwnd, hdc) OnMessage(0x201, "WM_LBUTTONDOWN")
}
- ----------------------------------------------------------------
Gdip2(){
global SelectObject(hdc, obm) DeleteObject(hbm) DeleteDC(hdc) Gdip_DeleteGraphics(G) Gdip_Shutdown(pToken)
}
- ----------------------------------------------------------------
WM_LBUTTONDOWN(){
PostMessage, 0xA1, 2
}
- ----------------------------------------------------------------
Exit: gdip2() ExitApp Return
- ----------------------------------------------------------------</lang>
C
Interactive program to draw a SuperEllipse. Requires the WinBGIm library. <lang C>
- include<graphics.h>
- include<stdio.h>
- include<math.h>
- define pi M_PI
int main(){
double a,b,n,i,incr = 0.0001;
printf("Enter major and minor axes of the SuperEllipse : "); scanf("%lf%lf",&a,&b);
printf("Enter n : "); scanf("%lf",&n);
initwindow(500,500,"Superellipse");
for(i=0;i<2*pi;i+=incr){ putpixel(250 + a*pow(fabs(cos(i)),2/n)*(pi/2<i && i<3*pi/2?-1:1),250 + b*pow(fabs(sin(i)),2/n)*(pi<i && i<2*pi?-1:1),15); }
printf("Done. %lf",i);
getch();
closegraph(); }</lang>
EchoLisp
Link to the super-ellipse image. <lang scheme> (lib 'plot) (define (eaxpt x n) (expt (abs x) n)) (define (Ellie x y) (+ (eaxpt (// x 200) 2.5) (eaxpt (// y 200) 2.5) -1))
(plot-xy Ellie -400 -400)
→ (("x:auto" -400 400) ("y:auto" -400 400))
</lang>
FreeBASIC
<lang freebasic>' version 23-10-2016 ' compile with: fbc -s console
Const scr_x = 800 ' screen 800 x 800 Const scr_y = 600 Const m_x = scr_x \ 2 ' middle of screen Const m_y = scr_y \ 2
Sub superellipse(a As Long, b As Long, n As Double)
ReDim As Long y(0 To a) Dim As Long x
y(0) = b ' value for x = 0 y(a) = 0 ' value for x = a
'(0,0) is in upper left corner
PSet (m_x, m_y - y(0)) ' set starting point
For x = 1 To a-1 y(x) = Int( Exp( Log(1 - ((x / a) ^ n)) / n ) * b ) Line - ((m_x + x), (m_y - y(x))) Next
For x = a To 0 Step -1 Line - ((m_x + x), (m_y + y(x))) Next
For x = 0 To a Line - ((m_x - x), (m_y + y(x))) Next
For x = a To 0 Step -1 Line - ((m_x - x), (m_y - y(x))) Next
End Sub
' ------=< MAIN >=------
ScreenRes scr_x, scr_y, 32
Dim As Long a = 200 Dim As Long b = 150 Dim As Double n = 2.5
superellipse(a, b, n)
' empty keyboard buffer While Inkey <> "" : Wend Print : Print "hit any key to end program" Sleep End</lang>
Go
<lang go>package main
import (
"github.com/fogleman/gg" "math"
)
/* assumes a and b are always equal */ func superEllipse(dc *gg.Context, n float64, a int) {
hw := float64(dc.Width() / 2) hh := float64(dc.Height() / 2)
// calculate y for each x y := make([]float64, a+1) for x := 0; x <= a; x++ { aa := math.Pow(float64(a), n) xx := math.Pow(float64(x), n) y[x] = math.Pow(aa-xx, 1.0/n) }
// draw quadrants for x := a; x >= 0; x-- { dc.LineTo(hw+float64(x), hh-y[x]) } for x := 0; x <= a; x++ { dc.LineTo(hw+float64(x), hh+y[x]) } for x := a; x >= 0; x-- { dc.LineTo(hw-float64(x), hh+y[x]) } for x := 0; x <= a; x++ { dc.LineTo(hw-float64(x), hh-y[x]) }
dc.SetRGB(1, 1, 1) // white ellipse dc.Fill()
}
func main() {
dc := gg.NewContext(500, 500) dc.SetRGB(0, 0, 0) // black background dc.Clear() superEllipse(dc, 2.5, 200) dc.SavePNG("superellipse.png")
}</lang>
- Output:
Image similar to J entry.
Haskell
Use the ghcjs compiler to compile to JavaScript that runs in a browser. The reflex-dom library is used to help with SVG rendering and input. <lang haskell>{-# LANGUAGE OverloadedStrings, RankNTypes #-} import Reflex import Reflex.Dom import Data.Text (Text, pack, unpack) import Data.Map (Map, fromList, empty) import Text.Read (readMaybe)
width = 600 height = 500
type Point = (Float,Float) type Segment = (Point,Point)
data Ellipse = Ellipse {a :: Float, b :: Float, n :: Float}
toFloat :: Text -> Maybe Float toFloat = readMaybe.unpack
toEllipse :: Maybe Float -> Maybe Float -> Maybe Float -> Maybe Ellipse toEllipse (Just a) (Just b) (Just n) =
if a < 1.0 || b <= 1.0 || n <= 0.0 -- not all floats are valid then Nothing else Just $ Ellipse a b n
toEllipse _ _ _ = Nothing
showError :: Maybe a -> String showError Nothing = "invalid input" showError _ = ""
reflect45 pts = pts ++ fmap (\(x,y) -> ( y, x)) (reverse pts) rotate90 pts = pts ++ fmap (\(x,y) -> ( y, -x)) pts rotate180 pts = pts ++ fmap (\(x,y) -> (-x, -y)) pts scale a b = fmap (\(x,y) -> ( a*x, b*y )) segments pts = zip pts $ tail pts
toLineMap :: Maybe Ellipse -> Map Int ((Float,Float),(Float,Float)) toLineMap (Just (Ellipse a b n)) =
let f p = (1 - p**n)**(1/n) dp = iterate (*0.9) 1.0 ip = map (\p -> 1.0 -p) dp points s = if n > 1.0 then (\p -> zip p (map f p)) ip else (\p -> zip (map f p) p) dp
in fromList $ -- changes list to map (for listWithKey) zip [0..] $ -- annotates segments with index segments $ -- changes points to line segments scale a b $ rotate180 $ -- doubles the point count rotate90 $ -- doubles the point count reflect45 $ -- doubles the point count takeWhile (\(x,y) -> x < y ) $ -- stop at 45 degree line points 0.9
toLineMap Nothing = empty
lineAttrs :: Segment -> Map Text Text lineAttrs ((x1,y1), (x2,y2)) =
fromList [ ( "x1", pack $ show (width/2+x1)) , ( "y1", pack $ show (height/2+y1)) , ( "x2", pack $ show (width/2+x2)) , ( "y2", pack $ show (height/2+y2)) , ( "style", "stroke:brown;stroke-width:2") ]
showLine :: MonadWidget t m => Int -> Dynamic t Segment -> m () showLine _ dSegment = do
elSvgns "line" (lineAttrs <$> dSegment) $ return () return ()
main = mainWidget $ do
elAttr "h1" ("style" =: "color:brown") $ text "Superellipse" ta <- el "div" $ do text "a: " textInput def { _textInputConfig_initialValue = "200"}
tb <- el "div" $ do text "b: " textInput def { _textInputConfig_initialValue = "200"}
tn <- el "div" $ do text "n: " textInput def { _textInputConfig_initialValue = "2.5"} let ab = zipDynWith toEllipse (toFloat <$> value ta) (toFloat <$> value tb) dEllipse = zipDynWith ($) ab (toFloat <$> value tn) dLines = fmap toLineMap dEllipse dAttrs = constDyn $ fromList [ ("width" , pack $ show width) , ("height", pack $ show height) ] elAttr "div" ("style" =: "color:red") $ dynText $ fmap (pack.showError) dEllipse el "div" $ elSvgns "svg" dAttrs $ listWithKey dLines showLine return ()
-- At end to avoid Rosetta Code unmatched quotes problem. elSvgns :: forall t m a. MonadWidget t m => Text -> Dynamic t (Map Text Text) -> m a -> m (El t, a) elSvgns = elDynAttrNS' (Just "http://www.w3.org/2000/svg")</lang>
Link to live demo: https://dc25.github.io/superEllipseReflex/
J
We will fill the ellipse so that we do not have to worry about the size and shape of our pixels:
<lang J>selips=: 4 :0
'n a b'=. y 1 >: ((n^~a%~]) +&|/ n^~b%~]) i:x
)
require'viewmat' viewmat 300 selips 2.5 200 200</lang>
Java
<lang java>import java.awt.*; import java.awt.geom.Path2D; import static java.lang.Math.pow; import java.util.Hashtable; import javax.swing.*; import javax.swing.event.*;
public class SuperEllipse extends JPanel implements ChangeListener {
private double exp = 2.5;
public SuperEllipse() { setPreferredSize(new Dimension(650, 650)); setBackground(Color.white); setFont(new Font("Serif", Font.PLAIN, 18)); }
void drawGrid(Graphics2D g) { g.setStroke(new BasicStroke(2)); g.setColor(new Color(0xEEEEEE));
int w = getWidth(); int h = getHeight(); int spacing = 25;
for (int i = 0; i < w / spacing; i++) { g.drawLine(0, i * spacing, w, i * spacing); g.drawLine(i * spacing, 0, i * spacing, w); } g.drawLine(0, h - 1, w, h - 1);
g.setColor(new Color(0xAAAAAA)); g.drawLine(0, w / 2, w, w / 2); g.drawLine(w / 2, 0, w / 2, w); }
void drawLegend(Graphics2D g) { g.setColor(Color.black); g.setFont(getFont()); g.drawString("n = " + String.valueOf(exp), getWidth() - 150, 45); g.drawString("a = b = 200", getWidth() - 150, 75); }
void drawEllipse(Graphics2D g) {
final int a = 200; // a = b double[] points = new double[a + 1];
Path2D p = new Path2D.Double(); p.moveTo(a, 0);
// calculate first quadrant for (int x = a; x >= 0; x--) { points[x] = pow(pow(a, exp) - pow(x, exp), 1 / exp); // solve for y p.lineTo(x, -points[x]); }
// mirror to others for (int x = 0; x <= a; x++) p.lineTo(x, points[x]);
for (int x = a; x >= 0; x--) p.lineTo(-x, points[x]);
for (int x = 0; x <= a; x++) p.lineTo(-x, -points[x]);
g.translate(getWidth() / 2, getHeight() / 2); g.setStroke(new BasicStroke(2));
g.setColor(new Color(0x25B0C4DE, true)); g.fill(p);
g.setColor(new Color(0xB0C4DE)); // LightSteelBlue g.draw(p); }
@Override public void paintComponent(Graphics gg) { super.paintComponent(gg); Graphics2D g = (Graphics2D) gg; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
drawGrid(g); drawLegend(g); drawEllipse(g); }
@Override public void stateChanged(ChangeEvent e) { JSlider source = (JSlider) e.getSource(); exp = source.getValue() / 2.0; repaint(); }
public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setTitle("Super Ellipse"); f.setResizable(false); SuperEllipse panel = new SuperEllipse(); f.add(panel, BorderLayout.CENTER);
JSlider exponent = new JSlider(JSlider.HORIZONTAL, 1, 9, 5); exponent.addChangeListener(panel); exponent.setMajorTickSpacing(1); exponent.setPaintLabels(true); exponent.setBackground(Color.white); exponent.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
Hashtable<Integer, JLabel> labelTable = new Hashtable<>(); for (int i = 1; i < 10; i++) labelTable.put(i, new JLabel(String.valueOf(i * 0.5))); exponent.setLabelTable(labelTable);
f.add(exponent, BorderLayout.SOUTH);
f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); }); }
}</lang>
JavaScript
<lang javascript> var n = 2.5, a = 200, b = 200, ctx;
function point( x, y ) {
ctx.fillRect( x, y, 1, 1);
}
function start() {
var can = document.createElement('canvas'); can.width = can.height = 600; ctx = can.getContext( "2d" ); ctx.rect( 0, 0, can.width, can.height ); ctx.fillStyle = "#000000"; ctx.fill(); document.body.appendChild( can );
ctx.fillStyle = "#ffffff"; for( var t = 0; t < 1000; t += .1 ) { x = Math.pow( Math.abs( Math.cos( t ) ), 2 / n ) * a * Math.sign( Math.cos( t ) ); y = Math.pow( Math.abs( Math.sin( t ) ), 2 / n ) * b * Math.sign( Math.sin( t ) );
point( x + ( can.width >> 1 ), y + ( can.height >> 1 ) ); }
} </lang>
Julia
<lang julia>function superellipse(n, a, b, step::Int=100)
@assert n > 0 && a > 0 && b > 0 na = 2 / n pc = 2π / step t = 0 xp = Vector{Float64}(undef, step + 1) yp = Vector{Float64}(undef, step + 1) for i in 0:step # because sin^n(x) is mathematically the same as (sin(x))^n... xp[i+1] = abs((cos(t))) ^ na * a * sign(cos(t)) yp[i+1] = abs((sin(t))) ^ na * b * sign(sin(t)) t += pc end return xp, yp
end
using UnicodePlots
x, y = superellipse(2.5, 200, 200)
println(lineplot(x, y))</lang>
- Output:
┌────────────────────────────────────────┐ 200 │⠀⠀⠀⠀⠀⠀⠀⢀⣠⠤⠔⠒⠊⠉⠉⠉⠉⠉⠉⠉⡏⠉⠉⠉⠉⠉⠉⠒⠒⠢⠤⣀⡀⠀⠀⠀⠀⠀⠀⠀│ │⠀⠀⠀⠀⣀⠤⠊⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠓⠤⣀⠀⠀⠀⠀│ │⠀⠀⢀⠜⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡄⠀⠀│ │⠀⡠⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢆⠀│ │⢰⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⡆│ │⡎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢱│ │⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│ │⡧⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⡧⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⠤⢼│ │⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸│ │⢇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡸│ │⠸⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠇│ │⠀⠱⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠊⠀│ │⠀⠀⠘⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡔⠁⠀⠀│ │⠀⠀⠀⠀⠉⠒⢤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠒⠉⠀⠀⠀⠀│ -200 │⠀⠀⠀⠀⠀⠀⠀⠈⠉⠒⠢⠤⠤⣀⣀⣀⣀⣀⣀⣀⣇⣀⣀⣀⣀⣀⣀⡠⠤⠔⠒⠋⠁⠀⠀⠀⠀⠀⠀⠀│ └────────────────────────────────────────┘ -200 200
Kotlin
The following is based on the Java entry but dispenses with the grid and slider as these aren't really part of the task. <lang scala>// version 1.1.2
import java.awt.* import java.awt.geom.Path2D import javax.swing.* import java.lang.Math.pow
/* assumes a == b */ class SuperEllipse(val n: Double, val a: Int) : JPanel() {
init { require(n > 0.0 && a > 0) preferredSize = Dimension(650, 650) background = Color.black }
private fun drawEllipse(g: Graphics2D) { val points = DoubleArray(a + 1) val p = Path2D.Double() p.moveTo(a.toDouble(), 0.0)
// calculate first quadrant for (x in a downTo 0) { points[x] = pow(pow(a.toDouble(), n) - pow(x.toDouble(), n), 1.0 / n) p.lineTo(x.toDouble(), -points[x]) } // mirror to others for (x in 0..a) p.lineTo(x.toDouble(), points[x]) for (x in a downTo 0) p.lineTo(-x.toDouble(), points[x]) for (x in 0..a) p.lineTo(-x.toDouble(), -points[x])
with(g) { translate(width / 2, height / 2) color = Color.yellow fill(p) } }
override fun paintComponent(gg: Graphics) { super.paintComponent(gg) val g = gg as Graphics2D g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON) drawEllipse(g) }
}
fun main(args: Array<String>) {
SwingUtilities.invokeLater { val f = JFrame() with (f) { defaultCloseOperation = JFrame.EXIT_ON_CLOSE title = "Super Ellipse" isResizable = false add(SuperEllipse(2.5, 200), BorderLayout.CENTER) pack() setLocationRelativeTo(null) isVisible = true } }
}</lang>
Liberty BASIC
Reworked the Julia version to work and added a loop with a spread on n values. <lang lb> [start]
nomainwin UpperLeftX=1:UpperLeftY=1 WindowWidth=800:WindowHeight=600 open "Super Ellipse" for graphics_nf_nsb as #1 #1 "trapclose [q];down;fill black;flush;color green;size 1"
n=1.5 a=200 b=200
for n = 0.1 to 5 step .1 na=2/n t=.01 for i = 0 to 314 xp=a*sign(cos(t))*abs((cos(t)))^na+350 yp=b*sign(sin(t))*abs((sin(t)))^na+275 t=t+.02 #1 "set ";xp;" ";yp next i next n
'plot only the super ellipse for the task n=2.5 na=2/n t=.01 #1 "color white;size 4" for i = 0 to 314 xp=a*sign(cos(t))*abs((cos(t)))^na+350 yp=b*sign(sin(t))*abs((sin(t)))^na+275 t=t+.02 #1 "set ";xp;" ";yp next i
wait
[q] close #1 end
function sign(x)
if x<0 then sign=1 if x>0 then sign=-1 if x=0 then sign=0
end function </lang>
Lua
Scale of a and b were reduced to facilitate an ASCII solution: <lang lua>local abs,cos,floor,pi,pow,sin = math.abs,math.cos,math.floor,math.pi,math.pow,math.sin local bitmap = {
init = function(self, w, h, value) self.w, self.h, self.pixels = w, h, {} for y=1,h do self.pixels[y]={} end self:clear(value) end, clear = function(self, value) for y=1,self.h do for x=1,self.w do self.pixels[y][x] = value or " " end end end, set = function(self, x, y, value) x,y = floor(x+0.5),floor(y+0.5) if x>0 and y>0 and x<=self.w and y<=self.h then self.pixels[y][x] = value or "#" end end, superellipse = function(self, ox, oy, n, a, b, c) local function sgn(n) return n>=0 and 1 or -1 end for t = 0, 1, 0.002 do local theta = t * 2 * pi local x = ox + a * pow(abs(cos(theta)), 2/n) * sgn(cos(theta)) local y = oy + b * pow(abs(sin(theta)), 2/n) * sgn(sin(theta)) self:set(x, y, c) end end, render = function(self) for y=1,self.h do print(table.concat(self.pixels[y])) end end,
}
bitmap:init(80, 60, "..") bitmap:superellipse(40, 30, 2.5, 38, 28, "[]") bitmap:render()</lang>
- Output:
................................................................................................................................................................ ..........................................................[][][][][][][][][][][][][][][][][][][][][]............................................................ ............................................[][][][][][][]..........................................[][][][][][][].............................................. ......................................[][][][]..................................................................[][][][]........................................ ................................[][][][]..............................................................................[][][][].................................. ............................[][][]..........................................................................................[][][].............................. ........................[][][]..................................................................................................[][][].......................... ......................[][]..........................................................................................................[][]........................ ..................[][]..................................................................................................................[][].................... ................[][]......................................................................................................................[][].................. ..............[][]..........................................................................................................................[][]................ ............[][]..............................................................................................................................[][].............. ............[]..................................................................................................................................[].............. ..........[]......................................................................................................................................[]............ ........[][]......................................................................................................................................[][].......... ........[]..........................................................................................................................................[].......... ......[]..............................................................................................................................................[]........ ......[]..............................................................................................................................................[]........ ....[][]..............................................................................................................................................[][]...... ....[]..................................................................................................................................................[]...... ....[]..................................................................................................................................................[]...... ....[]..................................................................................................................................................[]...... ..[][]..................................................................................................................................................[][].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[]......................................................................................................................................................[].... ..[][]..................................................................................................................................................[][].... ....[]..................................................................................................................................................[]...... ....[]..................................................................................................................................................[]...... ....[]..................................................................................................................................................[]...... ....[][]..............................................................................................................................................[][]...... ......[]..............................................................................................................................................[]........ ......[]..............................................................................................................................................[]........ ........[]..........................................................................................................................................[].......... ........[][]......................................................................................................................................[][].......... ..........[]......................................................................................................................................[]............ ............[]..................................................................................................................................[].............. ............[][]..............................................................................................................................[][].............. ..............[][]..........................................................................................................................[][]................ ................[][]......................................................................................................................[][].................. ..................[][]..................................................................................................................[][].................... ......................[][]..........................................................................................................[][]........................ ........................[][][]..................................................................................................[][][].......................... ............................[][][]..........................................................................................[][][].............................. ................................[][][][]..............................................................................[][][][].................................. ......................................[][][][]..................................................................[][][][]........................................ ............................................[][][][][][][]..........................................[][][][][][][].............................................. ..........................................................[][][][][][][][][][][][][][][][][][][][][]............................................................ ................................................................................................................................................................ ................................................................................................................................................................
Maple
The built-in command ImplicitPlot accepts an equation in 2 variables: <lang maple>plots:-implicitplot(abs((1/200)*x^2.5)+abs((1/200)*y^2.5) = 1, x = -10 .. 10, y = -10 .. 10);</lang>
Mathematica/Wolfram Language
The built-in function ContourPlot accepts and equation in 2 variables and creates the desired plot <lang Mathematica>ContourPlot[Abs[x/200]^2.5 + Abs[y/200]^2.5 == 1, {x, -200, 200}, {y, -200, 200}]</lang>
Nim
<lang Nim>import math import imageman
const
Size = 600 X0 = Size div 2 Y0 = Size div 2 Background = ColorRGBU [byte 0, 0, 0] Foreground = ColorRGBU [byte 255, 255, 255]
proc drawSuperEllipse(img: var Image; n: float; a, b: int) =
var yList = newSeq[int](a + 1) for x in 0..a: let an = pow(a.toFloat, n) let bn = pow(b.toFloat, n) let xn = pow(x.toFloat, n) let t = max(bn - xn * bn / an, 0.0) # Avoid negative values due to rounding errors. yList[x] = pow(t, 1/n).toInt
var pos: seq[Point] for x in countdown(a, 0): pos.add (X0 + x, Y0 - yList[x]) for x in 0..a: pos.add (X0 - x, Y0 - yList[x]) for x in countdown(a, 0): pos.add (X0 - x, Y0 + yList[x]) for x in 0..a: pos.add (X0 + x, Y0 + yList[x]) img.drawPolyline(true, Foreground, pos)
var image = initImage[ColorRGBU](Size, Size)
image.fill(Background)
image.drawSuperEllipse(2.5, 200, 200)
image.savePNG("super_ellipse.png", compression = 9)</lang>
ooRexx
This program draws 5 super ellipses: black 120,120,1.5 blue 160,160,2 red 200,200,2.5 green 240,240,3 black 280,280,4
<lang oorexx>/* REXX ***************************************************************
- Create a BMP file showing a few super ellipses
- /
Parse Version v If pos('Regina',v)>0 Then
superegg='superegga.bmp'
Else
superegg='supereggx.bmp'
'erase' superegg s='424d4600000000000000360000002800000038000000280000000100180000000000'X||,
'1000000000000000000000000000000000000000'x
z.0=0 black='000000'x white='ffffff'x red ='00ff00'x green='ff0000'x blue ='0000ff'x m=80 n=80 hor=m*8 /* 56 */ ver=n*8 /* 40 */ s=overlay(lend(hor),s,19,4) s=overlay(lend(ver),s,23,4) z.=copies('f747ff'x,3192%3) z.=copies('ffffff'x,8*m) z.0=648 u=320 v=320 Call supegg black,120,120,1.5,u,v Call supegg blue,160,160,2,u,v Call supegg red,200,200,2.5,u,v Call supegg green,240,240,3,u,v Call supegg black,280,280,4,u,v
Do i=1 To z.0
s=s||z.i End
Call lineout superegg,s Call lineout superegg Exit
supegg: Parse Arg color,a,b,n,u,v Do y=0 To b
t=(1-rxCalcpower(y/b,n)) x=a*rxCalcpower(t,1/n) Call point color,format(u+x,4,0),format(v+y,4,0) Call point color,format(u-x,4,0),format(v+y,4,0) Call point color,format(u+x,4,0),format(v-y,4,0) Call point color,format(u-x,4,0),format(v-y,4,0) End
Do x=0 To a
t=(1-rxCalcpower(x/b,n)) y=a*rxCalcpower(t,1/n) Call point color,format(u+x,4,0),format(v+y,4,0) Call point color,format(u-x,4,0),format(v+y,4,0) Call point color,format(u+x,4,0),format(v-y,4,0) Call point color,format(u-x,4,0),format(v-y,4,0) End
Return
lend: Return reverse(d2c(arg(1),4))
point: Procedure Expose z.
Call trace 'O' Parse Arg color,x0,y0 --Say x0 y0 Do x=x0-2 To x0+2 Do y=y0-2 To y0+2 z.y=overlay(copies(color,3),z.y,3*x) End End Return
- requires rxMath library</lang>
Perl
<lang perl>my $a = 200; my $b = 200; my $n = 2.5;
- y in terms of x
sub y_from_x {
my($x) = @_; int $b * abs(1 - ($x / $a) ** $n ) ** (1/$n)
}
- find point pairs for one quadrant
push @q, $_, y_from_x($_) for 0..200;
- Generate an SVG image
open $fh, '>', 'superellipse.svg'; print $fh
qq|<svg height="@{[2*$b]}" width="@{[2*$a]}" xmlns="http://www.w3.org/2000/svg">\n|, pline( 1, 1, @q ), pline( 1,-1, @q ), # flip and mirror pline(-1,-1, @q ), # for the other pline(-1, 1, @q ), # three quadrants '</svg>';
sub pline {
my($sx,$sy,@q) = @_;
for (0..$#q/2) { $q[ 2*$_] *= $sx; $q[1+2*$_] *= $sy; }
qq|<polyline points="@{[join ' ',@q]}" style="fill:none;stroke:black;stroke-width:3" transform="translate($a, $b)" />\n|
}</lang> Superellipse (offsite image)
Phix
You can run this online here.
-- -- demo\rosetta\Superellipse.exw -- ============================= -- with javascript_semantics atom n = 2.5 -- '+' and '-' increase/decrease in steps of 0.1 include pGUI.e Ihandle dlg, canvas cdCanvas cddbuffer, cdcanvas function redraw_cb(Ihandle /*ih*/) integer {w, h} = IupGetIntInt(canvas, "DRAWSIZE"), hw = floor(w/2), hh = floor(h/2), a = max(10,hw-100), -- (initially 200, from 602x ) b = max(10,hh-50) -- (initially 200, from x502) sequence y = b&repeat(0,a) for x=1 to a-1 do y[x+1] = floor(exp(log(1-power(x/a,n))/n)*b) end for cdCanvasActivate(cddbuffer) cdCanvasClear(cddbuffer) cdCanvasBegin(cddbuffer, CD_OPEN_LINES) cdCanvasVertex(cddbuffer, hw, hh-b) -- starting point for x=1 to a-1 do cdCanvasVertex(cddbuffer, hw+x, hh-y[x+1]) end for for x=a to 0 by -1 do cdCanvasVertex(cddbuffer, hw+x, hh+y[x+1]) end for for x=0 to a do cdCanvasVertex(cddbuffer, hw-x, hh+y[x+1]) end for for x=a to 0 by -1 do cdCanvasVertex(cddbuffer, hw-x, hh-y[x+1]) end for cdCanvasEnd(cddbuffer) cdCanvasFlush(cddbuffer) return IUP_DEFAULT end function function map_cb(Ihandle ih) cdcanvas = cdCreateCanvas(CD_IUP, ih) cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas) cdCanvasSetBackground(cddbuffer, CD_WHITE) cdCanvasSetForeground(cddbuffer, CD_BLACK) return IUP_DEFAULT end function function key_cb(Ihandle /*ih*/, atom c) if c=K_ESC then return IUP_CLOSE end if if c='+' then n = min(130,n+0.1) -- (otherwise [>130] power overflow) IupUpdate(canvas) elsif c='-' then n = max(0.1,n-0.1) -- (otherwise [=0.0] divide by zero) IupUpdate(canvas) end if return IUP_CONTINUE end function procedure main() IupOpen() canvas = IupCanvas("RASTERSIZE=602x502") IupSetCallbacks(canvas, {"MAP_CB", Icallback("map_cb"), "ACTION", Icallback("redraw_cb")}) dlg = IupDialog(canvas,"TITLE=Superellipse") IupSetCallback(dlg, "KEY_CB", Icallback("key_cb")) IupShow(dlg) IupSetAttribute(canvas, "RASTERSIZE", NULL) -- release the minimum limitation if platform()!=JS then IupMainLoop() IupClose() end if end procedure main()
Processing
<lang java> //Aamrun, 29th June 2022
float a = 200, b = 200, n = 2.5; float i, incr = 0.001; int xMul,yMul;
size(500,500);
stroke(#ff0000);
for(i=0;i<2*PI;i+=incr){
if(PI/2<i && i<3*PI/2) xMul = -1; else xMul = 1; if(PI<i && i<2*PI) yMul = -1; else yMul = 1; ellipse(width/2 + xMul * a*pow(abs(cos(i)),2/n),height/2 + yMul * b*pow(abs(sin(i)),2/n),1,1);
}
</lang>
Python
<lang python>
- Superellipse drawing in Python 2.7.9
- pic can see at http://www.imgup.cz/image/712
import matplotlib.pyplot as plt from math import sin, cos, pi
def sgn(x): return ((x>0)-(x<0))*1
a,b,n=200,200,2.5 # param n making shape na=2/n step=100 # accuracy piece=(pi*2)/step xp=[];yp=[]
t=0 for t1 in range(step+1): # because sin^n(x) is mathematically the same as (sin(x))^n... x=(abs((cos(t)))**na)*a*sgn(cos(t)) y=(abs((sin(t)))**na)*b*sgn(sin(t)) xp.append(x);yp.append(y) t+=piece
plt.plot(xp,yp) # plotting all point from array xp, yp plt.title("Superellipse with parameter "+str(n)) plt.show() </lang>
QB64
<lang qb64>_Title "Super Ellipse"
Dim As Integer sw, sh Dim As Single i sw = 480: sh = 480
Screen _NewImage(sw, sh, 8) Cls , 15
'Show different possible Super Ellipse shapes Color 10 For i = 0.2 To 5.0 Step .1
Call SuperEllipse(sw \ 2, sh \ 2, 200, 200, i, 80)
Next
'Show task specified Super Ellipse Color 0 Call SuperEllipse(sw \ 2, sh \ 2, 200, 200, 2.5, 200) Sleep System
Sub SuperEllipse (cX As Integer, cY As Integer, wide As Integer, high As Integer, pow As Double, segs As Integer)
Dim As Double power, inc, theta, cosTheta, sinTheta Dim As Integer x1, y1 'Limit 'pow' to acceptable values If pow < .1 Then pow = .1 If pow > 150 Then pow = 150 power = 2 / pow - 1 inc = 360.0 / segs * 0.0174532925199432957692369 PSet (wide + cX, cY) For theta = inc To 6.28318530717958647692528 + inc Step inc cosTheta = Cos(theta): sinTheta = Sin(theta) x1 = wide * cosTheta * Abs(cosTheta) ^ power + cX y1 = high * sinTheta * Abs(sinTheta) ^ power + cY Line -(x1, y1) Next
End Sub</lang>
QBasic
<lang QBasic>SCREEN 12 CLS a = 200 b = 200 n = 2.5 na = 2 / n t = .01
LINE -(520, 245), 0, BF FOR i = 0 TO 314
xp = a * SGN(COS(t)) * ABS((COS(t))) ^ na + 320 yp = b * SGN(SIN(t)) * ABS((SIN(t))) ^ na + 240 t = t + .02 LINE -(xp, yp), 1, BF
NEXT i</lang>
Racket
<lang Racket>#lang racket (require plot)
- (plot-new-window? #t)
(define ((superellipse a b n) x y)
(+ (expt (abs (/ x a)) n) (expt (abs (/ y b)) n)))
(plot (isoline (superellipse 200 200 2.5) 1
-220 220 -220 220))</lang>
Raku
(formerly Perl 6) <lang perl6>my (\a, \b, \n) = 200, 200, 2.5;
- y in terms of x
sub y ($x) { floor b × (1 - ($x/a).abs ** n ) ** (1/n) }
- find point pairs for one quadrant
my @q = flat map -> \x { x, y(x) }, ^(a+1);
my $out = open('superellipse.svg', :w); $out.print: [~] qq|<svg height="{b×2}" width="{a×2}" xmlns="http://www.w3.org/2000/svg">\n|,
pline( @q ), pline( @q «×» < 1 -1> ), # flip and mirror pline( @q «×» <-1 -1> ), # for the other pline( @q «×» <-1 1> ), # three quadrants '</svg>';
sub pline (@q) {
qq|<polyline points="{@q}" style="fill:none;stroke:black;stroke-width:3" transform="translate({a}, {b})" />\n|
}</lang> Superellipse (offsite image)
REXX
Here you can see a picture: http://austria-forum.org/af/User/Pachl%20Walter
<lang rexx>/* REXX ***************************************************************
- Create a BMP file showing a few super ellipses
- /
Parse Version v If pos('Regina',v)>0 Then
superegg='superegga.bmp'
Else
superegg='supereggo.bmp'
'erase' superegg s='424d4600000000000000360000002800000038000000280000000100180000000000'X||,
'1000000000000000000000000000000000000000'x
z.0=0 black='000000'x white='ffffff'x red ='00ff00'x green='ff0000'x blue ='0000ff'x m=80 n=80 hor=m*8 /* 56 */ ver=n*8 /* 40 */ s=overlay(lend(hor),s,19,4) s=overlay(lend(ver),s,23,4) z.=copies('f747ff'x,3192%3) z.=copies('ffffff'x,8*m) z.0=648 u=320 v=320 Call supegg black,080,080,0.5,u,v Call supegg black,110,110,1 ,u,v Call supegg black,140,140,1.5,u,v Call supegg blue ,170,170,2 ,u,v Call supegg red ,200,200,2.5,u,v Call supegg green,230,230,3 ,u,v Call supegg black,260,260,4 ,u,v Call supegg black,290,290,7 ,u,v Do i=1 To z.0
s=s||z.i End
Call lineout superegg,s Call lineout superegg Exit
supegg: Parse Arg color,a,b,n,u,v Do y=0 To b
t=(1-power(y/b,n)) x=a*power(t,1/n) Call point color,format(u+x,4,0),format(v+y,4,0) Call point color,format(u-x,4,0),format(v+y,4,0) Call point color,format(u+x,4,0),format(v-y,4,0) Call point color,format(u-x,4,0),format(v-y,4,0) End
Do x=0 To a
t=(1-power(x/b,n)) y=a*power(t,1/n) Call point color,format(u+x,4,0),format(v+y,4,0) Call point color,format(u-x,4,0),format(v+y,4,0) Call point color,format(u+x,4,0),format(v-y,4,0) Call point color,format(u-x,4,0),format(v-y,4,0) End
Return
lend: Return reverse(d2c(arg(1),4))
point: Procedure Expose z.
Call trace 'O' Parse Arg color,x0,y0 --Say x0 y0 Do x=x0-2 To x0+2 Do y=y0-2 To y0+2 z.y=overlay(copies(color,3),z.y,3*x) End End Return
power: Procedure /***********************************************************************
- Return b**x for any x -- with reasonable or specified precision
- 920903 Walter Pachl
- /
Parse Arg b,x,prec If prec<9 Then prec=9 Numeric Digits (2*prec) Numeric Fuzz 3 If b=0 Then Return 0 If b<> Then x=x*ln(b,prec+2) o=1 u=1 r=1 Do i=1 By 1 ra=r o=o*x u=u*i r=r+(o/u) If r=ra Then Leave End Numeric Digits (prec) Return r+0
ln: Procedure /***********************************************************************
- Return ln(x) -- with specified precision
- Three different series are used for the ranges 0 to 0.5
- 0.5 to 1.5
- 1.5 to infinity
- 920903 Walter Pachl
- /
Parse Arg x,prec,b If prec= Then prec=9 Numeric Digits (2*prec) Numeric Fuzz 3 Select When x<=0 Then r='*** invalid argument ***' When x<0.5 Then Do z=(x-1)/(x+1) o=z r=z k=1 Do i=3 By 2 ra=r k=k+1 o=o*z*z r=r+o/i If r=ra Then Leave End r=2*r End When x<1.5 Then Do z=(x-1) o=z r=z k=1 Do i=2 By 1 ra=r k=k+1 o=-o*z r=r+o/i If r=ra Then Leave End End Otherwise /* 1.5<=x */ Do z=(x+1)/(x-1) o=1/z r=o k=1 Do i=3 By 2 ra=r k=k+1 o=o/(z*z) r=r+o/i If r=ra Then Leave End r=2*r End End If b<> Then r=r/ln(b) Numeric Digits (prec) Return r+0</lang>
Scala
Java Swing Interoperability
<lang Scala>import java.awt._ import java.awt.geom.Path2D import java.util
import javax.swing._ import javax.swing.event.{ChangeEvent, ChangeListener}
object SuperEllipse extends App {
SwingUtilities.invokeLater(() => { new JFrame("Super Ellipse") {
class SuperEllipse extends JPanel with ChangeListener { setPreferredSize(new Dimension(650, 650)) setBackground(Color.white) setFont(new Font("Serif", Font.PLAIN, 18)) private var exp = 2.5
override def paintComponent(gg: Graphics): Unit = { val g = gg.asInstanceOf[Graphics2D]
def drawGrid(g: Graphics2D): Unit = { g.setStroke(new BasicStroke(2)) g.setColor(new Color(0xEEEEEE)) val w = getWidth val h = getHeight val spacing = 25
for (i <- 0 until (w / spacing)) { g.drawLine(0, i * spacing, w, i * spacing) g.drawLine(i * spacing, 0, i * spacing, w) } g.drawLine(0, h - 1, w, h - 1) g.setColor(new Color(0xAAAAAA)) g.drawLine(0, w / 2, w, w / 2) g.drawLine(w / 2, 0, w / 2, w) }
def drawLegend(g: Graphics2D): Unit = { g.setColor(Color.black) g.setFont(getFont) g.drawString("n = " + String.valueOf(exp), getWidth - 150, 45) g.drawString("a = b = 200", getWidth - 150, 75) }
def drawEllipse(g: Graphics2D): Unit = { val a = 200 // calculate first quadrant val points = Array.tabulate(a + 1)(n => math.pow(math.pow(a, exp) - math.pow(n, exp), 1 / exp)) val p = new Path2D.Double
p.moveTo(a, 0) for (n <- a to 0 by -1) p.lineTo(n, -points(n)) // mirror to others for (x <- points.indices) p.lineTo(x, points(x)) for (y <- a to 0 by -1) p.lineTo(-y, points(y)) for (z <- points.indices) p.lineTo(-z, -points(z)) g.translate(getWidth / 2, getHeight / 2) g.setStroke(new BasicStroke(2)) g.setColor(new Color(0x25B0C4DE, true)) g.fill(p) g.setColor(new Color(0xB0C4DE)) // LightSteelBlue g.draw(p) }
super.paintComponent(gg) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON) drawGrid(g) drawLegend(g) drawEllipse(g) }
override def stateChanged(e: ChangeEvent): Unit = { val source = e.getSource.asInstanceOf[JSlider] exp = source.getValue / 2.0 repaint() } }
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) setResizable(false) val panel = new SuperEllipse add(panel, BorderLayout.CENTER) val exponent = new JSlider(SwingConstants.HORIZONTAL, 1, 9, 5) exponent.addChangeListener(panel) exponent.setBackground(Color.white) exponent.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)) exponent.setMajorTickSpacing(1) exponent.setPaintLabels(true) val labelTable = new util.Hashtable[Integer, JLabel] for (i <- 1 until 10) labelTable.put(i, new JLabel(String.valueOf(i * 0.5)))
exponent.setLabelTable(labelTable) add(exponent, BorderLayout.SOUTH) pack() setLocationRelativeTo(null) setVisible(true) }
})
}</lang>
Sidef
<lang ruby>const (
a = 200, b = 200, n = 2.5,
)
- y in terms of x
func y(x) { b * (1 - abs(x/a)**n -> root(n)) -> int }
func pline(q) {
<<-"EOT"; <polyline points="#{q.join(' ')}" style="fill:none; stroke:black; stroke-width:3" transform="translate(#{a}, #{b})" /> EOT
}
- Generate an SVG image
say <<-"EOT"
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg height="#{b*2}" width="#{a*2}" version="1.1" xmlns="http://www.w3.org/2000/svg"> EOT
- find point pairs for one quadrant
var q = { |x| (x, y(x)) }.map(0..200 `by` 2)
[
pline(q), pline(q »*« [ 1,-1]), # flip and mirror pline(q »*« [-1,-1]), # for the other pline(q »*« [-1, 1]), # three quadrants
].each { .print } say '</svg>'</lang>
Stata
<lang stata>sca a=200 sca b=200 sca n=2.5 twoway function y=b*(1-(abs(x/a))^n)^(1/n), range(-200 200) || function y=-b*(1-(abs(x/a))^n)^(1/n), range(-200 200)</lang>
Wren
Uses Go's drawing code but produces a more complex image. <lang ecmascript>import "graphics" for Canvas, Color, Point
class Game {
static init() { Canvas.resize(500, 500) // draw 200 concentric superellipses with gradually decreasing 'n'. for (a in 200..1) { superEllipse(a/80, a) } }
static update() {}
static draw(alpha) {}
static superEllipse(n, a) { var hw = Canvas.width / 2 var hh = Canvas.height / 2
// calculate y for each x var y = List.filled(a + 1, 0) for (x in 0..a) { var aa = a.pow(n) var xx = x.pow(n) y[x] = (aa-xx).pow(1/n) }
// draw quadrants var prev = Point.new(hw + a, hh - y[a]) for (x in a-1..0) { var curr = Point.new(hw + x, hh - y[x]) Canvas.line(prev.x, prev.y, curr.x, curr.y, Color.white) prev = Point.new(curr.x, curr.y) }
prev = Point.new(hw, hh + y[0]) for (x in 1..a) { var curr = Point.new(hw + x, hh + y[x]) Canvas.line(prev.x, prev.y, curr.x, curr.y, Color.white) prev = Point.new(curr.x, curr.y) }
prev = Point.new(hw - a, hh + y[a]) for (x in a-1..0) { var curr = Point.new(hw - x, hh + y[x]) Canvas.line(prev.x, prev.y, curr.x, curr.y, Color.white) prev = Point.new(curr.x, curr.y) }
prev = Point.new(hw, hh - y[0]) for (x in 1..a) { var curr = Point.new(hw - x, hh - y[x]) Canvas.line(prev.x, prev.y, curr.x, curr.y, Color.white) prev = Point.new(curr.x, curr.y) } }
}</lang>
XPL0
<lang XPL0>def X0=640/2, Y0=480/2, Scale=25.0, N=2.5; real X, Y; int IX, IY;
proc OctPoint; [ Point(X0+IX, Y0-IY, $F); Point(X0-IX, Y0-IY, $F); Point(X0+IX, Y0+IY, $F); Point(X0-IX, Y0+IY, $F); Point(X0+IY, Y0-IX, $F); Point(X0-IY, Y0-IX, $F); Point(X0+IY, Y0+IX, $F); Point(X0-IY, Y0+IX, $F); ];
[SetVid($101); \VESA graphics 640x480x8 IX:= 0; repeat X:= float(IX)/Scale;
Y:= Pow(200.0 - Pow(X,N), 1.0/N); IY:= fix(Y*Scale); OctPoint; IX:= IX+1;
until IX >= IY; ]</lang>
- Output:
http://www.xpl0.org/rcell.gif
Yabasic
<lang Yabasic>open window 700, 600 backcolor 0,0,0 clear window
a=200 b=200 n=2.5 na=2/n t=.01 color 0,0,255 for i = 0 to 314
xp=a*sig(cos(t))*abs((cos(t)))^na+350 yp=b*sig(sin(t))*abs((sin(t)))^na+275 t=t+.02 line to xp, yp
next i</lang>
zkl
Uses the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl
<lang zkl>fcn superEllipse(plot,n,color=0xff0000){ // we'll assume width <= height
a,p:=(plot.w/2).toFloat(), 1.0/n; // just calculate upper right quadrant foreach x in ([0.0 .. a]){ y:=(a.pow(n) - x.pow(n)).pow(p); // a==b>0 --> y=(a^n - x^n)^(1/n) //println( (x/a).abs().pow(n) + (y/b).abs().pow(n) ); // sanity check plot[x,y]=plot[-x,-y]=plot[-x,y]=plot[x,-y]=color; // all 4 quadrants } plot
}</lang> <lang zkl>w:=h:=600; plot:=PPM(w+1,h+1,0x909090); plot.cross(w/2,h/2); foreach n in ([0.01..1, 0.14]){ superEllipse(plot,n, 0x0000bb) }// 0-1: blue foreach n in ([1.0.. 2, 0.14]){ superEllipse(plot,n, 0x00ff00) }// 1-2: green foreach n in ([2.0..10, 1.4]) { superEllipse(plot,n, 0xff0000) }// 2+: red
plot.writeJPGFile("superEllipse.jpg");</lang>
- Programming Tasks
- Solutions by Programming Task
- Action!
- Action! Tool Kit
- Ada
- SDLAda
- AutoHotkey
- C
- EchoLisp
- FreeBASIC
- Go
- Go Graphics
- Haskell
- J
- Java
- JavaScript
- Julia
- Kotlin
- Liberty BASIC
- Lua
- Maple
- Mathematica
- Wolfram Language
- Nim
- Imageman
- OoRexx
- Perl
- Phix
- Phix/pGUI
- Phix/online
- Processing
- Python
- QB64
- QBasic
- Racket
- Raku
- REXX
- Scala
- Sidef
- Stata
- Wren
- DOME
- XPL0
- Yabasic
- Zkl