Klein bottle
Draw a Klein bottle image in your language and show it on this page.
Klein bottle is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
- Task
sysconf topleft
steps_u = 50
steps_v = 40
len pts_x[][] steps_u + 1
len pts_y[][] steps_u + 1
for u = 0 to steps_u
len pts_x[u][] steps_v + 1
len pts_y[u][] steps_v + 1
.
gbackground 000
gcolor 099
glinewidth 0.2
ang = 30
on animate
cos_a = cos ang
sin_a = sin ang
ang += 0.5
for u = 0 to steps_u
u_deg = u / steps_u * 360
for v = 0 to steps_v
v_deg = v / steps_v * 360
if u_deg < 180
x = 6 * cos u_deg * (1 + sin u_deg) + (4 * (1 - cos u_deg / 2)) * cos u_deg * cos v_deg
z = 16 * sin u_deg + (4 * (1 - cos u_deg / 2)) * sin u_deg * cos v_deg
else
x = 6 * cos u_deg * (1 + sin u_deg) + (4 * (1 - cos u_deg / 2)) * cos (v_deg + 180)
z = 16 * sin u_deg
.
y = 4 * (1 - cos u_deg / 2) * sin v_deg
x_rot = x * cos_a - y * sin_a
y_rot = x * sin_a + y * cos_a
scale = 2.4
pts_x[u][v] = 50 + (x_rot - y_rot * 0.3) * scale
pts_y[u][v] = 55 - (z - y_rot * 0.2) * scale
.
.
gclear
for u = 0 to steps_u - 1
for v = 0 to steps_v - 1
gline pts_x[u][v] pts_y[u][v] pts_x[u][v + 1] pts_y[u][v + 1]
gline pts_x[u][v] pts_y[u][v] pts_x[u + 1][v] pts_y[u + 1][v]
.
.
.Const As Single PI = 4 * Atn(1.0)
Const ScrW = 900
Const ScrH = 700
Screenres ScrW, ScrH, 32
Windowtitle "True Classic Klein Bottle GUI - FreeBASIC"
' Resolution parameters for the true shape
Dim As Integer steps_u = 50
Dim As Integer steps_v = 40
' 2D arrays to store screen coordinates for drawing grid lines
Dim As Single points_x(0 To steps_u, 0 To steps_v)
Dim As Single points_y(0 To steps_u, 0 To steps_v)
' Fill background with dark navy/black
Line (0, 0)-(ScrW, ScrH), Rgb(10,10,15), BF
' Set pen for the 3D mesh (Neon cyan)
Dim As Uinteger meshColor = Rgb(0, 229, 255)
' --- STEP 1: Calculate mathematical points and project them ---
Dim As Integer u, v
For u = 0 To steps_u
Dim As Double u_val = (u / steps_u) * 2.0 * PI ' 0..2p
For v = 0 To steps_v
Dim As Double v_val = (v / steps_v) * 2.0 * PI
Dim As Double x, y, z
' Classical "bottle" Klein bottle equations (Stewart Dickson / Mathworld formula)
If u_val < PI Then
x = 6 * Cos(u_val) * (1 + Sin(u_val)) + _
(4 * (1 - Cos(u_val) / 2)) * Cos(u_val) * Cos(v_val)
z = 16 * Sin(u_val) + _
(4 * (1 - Cos(u_val) / 2)) * Sin(u_val) * Cos(v_val)
Else
x = 6 * Cos(u_val) * (1 + Sin(u_val)) + _
(4 * (1 - Cos(u_val) / 2)) * Cos(v_val + PI)
z = 16 * Sin(u_val)
End If
y = (4 * (1 - Cos(u_val) / 2)) * Sin(v_val)
' 3D -> 2D Projection (with 30-degree rotation around Y and Z axes for better depth)
Dim As Double cos_a = 0.866 ' cos(30°)
Dim As Double sin_a = 0.500 ' sin(30°)
' Rotated coordinates
Dim As Double x_rot = x * cos_a - y * sin_a
Dim As Double y_rot = x * sin_a + y * cos_a
Dim As Double z_rot = z
' Scale and translate to the center of the 900x700 window
Dim As Double scale = 17
Dim As Integer screen_x = 450 + (x_rot - y_rot * 0.3) * scale
Dim As Integer screen_y = 400 - (z_rot - y_rot * 0.2) * scale
' Save for wireframe drawing
points_x(u, v) = screen_x
points_y(u, v) = screen_y
Next
Next
' --- STEP 2: Connect the 3D wireframe mesh ---
For u = 0 To steps_u - 1
For v = 0 To steps_v - 1
' Line to adjacent V point (U lines)
Line (points_x(u, v), points_y(u, v)) - _
(points_x(u, v + 1), points_y(u, v + 1)), meshColor
' Line to adjacent U point (V lines)
Line (points_x(u, v), points_y(u, v)) - _
(points_x(u + 1, v), points_y(u + 1, v)), meshColor
Next
Next
Sleep
- Output:
using CairoMakie
"""
The parametric equations for the Klein bottle (u, v) -> (x, y, z)
See also https://en.wikipedia.org/wiki/Klein_bottle#Parametrization
"""
function klein_bottle_xyz(u, v)
if u < π
x = 6*cos(u)*(1 + sin(u)) + 4*(1 - cos(u)/2)*cos(u)*cos(v)
y = 16*sin(u) + 4*(1 - cos(u)/2)*sin(u)*cos(v)
else
x = 6*cos(u)*(1 + sin(u)) + 4*(1 - cos(u)/2)*cos(v + π)
y = 16*sin(u)
end
z = 4*(1 - cos(u)/2)*sin(v)
return x, z, y # rotate the Klein bottle so that the bow is in the x-y plane
end
""" Plot the Klein bottle, a 4D surface, as 3D on a 2D pane :) using parametric equations. """
function plotkleinbottle()
# Resolution of u, v parameters.
# Higher values give smoother surface but take longer.
nu = 200
nv = 72
u = range(0, 2π, length = nu)
v = range(0, 2π, length = nv)
X = Matrix{Float32}(undef, nu, nv)
Y = similar(X)
Z = similar(X)
for i in eachindex(u), j in eachindex(v)
x, y, z = klein_bottle_xyz(u[i], v[j])
X[i, j] = x
Y[i, j] = y
Z[i, j] = z
end
fig = Figure(size = (900, 700))
ax = Axis3(
fig[1, 1],
title = "Klein Bottle",
aspect = :data,
perspectiveness = 0.4,
azimuth = 0.5π, # side-on view, showing the bow in profile
elevation = 0.08π,
)
# Add the surface of the Klein bottle with shading
surface!(
ax,
X, Y, Z;
colormap = :plasma,
shading = true,
)
# outline the shape with a wireframe
wireframe!(
ax,
X, Y, Z;
color = (:white, 0.12),
)
fig
#display(fig)
end
display(plotkleinbottle())
if !isinteractive()
CairoMakie.save("klein_bottle.png", plotkleinbottle())
end
- Output:
Const PI = 4 * Atn(1)
Const ScrW = 900
Const ScrH = 700
Screen _NewImage(ScrW, ScrH, 32)
_Title "True Classic Klein Bottle - QB64"
Cls
' Resolution parameters for the true shape
Dim steps_u As Integer: steps_u = 50
Dim steps_v As Integer: steps_v = 40
' 2D arrays to store screen coordinates for drawing grid lines
Dim points_x(0 To steps_u, 0 To steps_v) As Single
Dim points_y(0 To steps_u, 0 To steps_v) As Single
' Fill background with dark navy/black
Line (0, 0)-(ScrW, ScrH), _RGB32(10, 10, 15), BF
' Set pen for the 3D mesh (Neon cyan)
meshColor& = _RGB32(0, 229, 255)
' --- STEP 1: Calculate mathematical points and project them ---
For u = 0 To steps_u
u_val = (u / steps_u) * 2 * PI
For v = 0 To steps_v
v_val = (v / steps_v) * 2 * PI
' Classical "bottle" Klein bottle equations (Stewart Dickson / Mathworld formula)
If u_val < PI Then
x = 6 * Cos(u_val) * (1 + Sin(u_val)) + (4 * (1 - Cos(u_val) / 2)) * Cos(u_val) * Cos(v_val)
z = 16 * Sin(u_val) + (4 * (1 - Cos(u_val) / 2)) * Sin(u_val) * Cos(v_val)
Else
x = 6 * Cos(u_val) * (1 + Sin(u_val)) + (4 * (1 - Cos(u_val) / 2)) * Cos(v_val + PI)
z = 16 * Sin(u_val)
End If
y = (4 * (1 - Cos(u_val) / 2)) * Sin(v_val)
' 3D -> 2D Projection (with 30-degree rotation around Y and Z axes for better depth)
cos_a = .866
sin_a = .5
' Rotated coordinates
x_rot = x * cos_a - y * sin_a
y_rot = x * sin_a + y * cos_a
z_rot = z
' Scale and translate to the center of the 900x700 window
scale = 17
sx = 450 + (x_rot - y_rot * .3) * scale
sy = 400 - (z_rot - y_rot * .2) * scale
' Save for wireframe drawing
points_x(u, v) = sx
points_y(u, v) = sy
Next
Next
' --- STEP 2: Connect the 3D wireframe mesh ---
For u = 0 To steps_u - 1
For v = 0 To steps_v - 1
' Line to adjacent V point (U lines)
Line (points_x(u, v), points_y(u, v))-(points_x(u, v + 1), points_y(u, v + 1)), meshColor&
' Line to adjacent U point (V lines)
Line (points_x(u, v), points_y(u, v))-(points_x(u + 1, v), points_y(u + 1, v)), meshColor&
Next
Next
Sleep
- Output:
Similar to FreeBASIC entry.
Red [
title: "Klein Bottle"
author: "hinjolicious"
needs: 'view
note: "Adapted from Julia's example. Insights from Gemini AI."
]
#include %../../lib/terse.red
cosh: f.[x] [(exp x + exp n. x) / 2]
sinh: f.[x] [(exp x - exp n. x) / 2]
matrix: f.[a b] [ collect [l* a [ keep/only make vector! collect [l* b [keep 0.0]] ]] ]
similar: f.[m] [copy/deep m]
range2: f.[blk /local st en num stp i] [
set [st en num] r. blk
if num = 1 [return reduce [st]]
; The step size is (stop - start) / (length - 1)
stp: (en - st) / (num - 1)
make vector! collect [r* i num [keep st + ((i - 1) * stp)]]
]
; == MAKIE mockup ==
red-makie: context [
angle-x: 100.0
angle-y: 0.0
object-radius: 1.5
camera-distance: object-radius * 3.0
perspective: 250.0
scale: 1.5
drawing: []
project: f.[x y z canvas-center
/local rad-x rad-y x1 z1 y2 z2 z-offset proj-factor x-fnal y-final s] [
; rotation
rad-x: angle-x * 0.0174532925199433
rad-y: angle-y * 0.0174532925199433
x1: (x * cos rad-y) - (z * sin rad-y)
z1: (x * sin rad-y) + (z * cos rad-y)
y2: (y * cos rad-x) - (z1 * sin rad-x)
z2: (y * sin rad-x) + (z1 * cos rad-x)
; perspective
e? perspective > 0.0 [
z-offset: z2 + camera-distance
proj-factor: perspective / (perspective + z-offset)
s: 500 / perspective * scale
x-final: x1 * proj-factor * s
y-final: y2 * proj-factor * s
][
s: 7.0 * scale
x-final: x1 * s
y-final: y2 * s
]
as-pair i' (x-final + canvas-center/x)
i' (y-final + canvas-center/y)
]
figure: f.[siz] [ object [size: siz axis: none] ]
axis3: f.[fig ttl asp persp azim elev] [
fig/axis: object [ title: ttl aspect: asp perspective: persp azimuth: azim elevation: elev
jobs: copy [] wire: none dots: none surf: none ] ]
wireframe: f.[ax x y z clr lw] [
ax/wire: object [ xx: x yy: y zz: z color: clr linewidth: lw ]
a. ax/jobs 'wire
]
dots: f.[ax x y z clr lw] [
ax/dots: object [ xx: x yy: y zz: z color: clr linewidth: lw ]
a. ax/jobs 'dots
]
surface: f.[ax x y z clr lw] [
ax/surf: object [ xx: x yy: y zz: z color: clr linewidth: lw ]
a. ax/jobs 'surf
]
; bounding-box display
bbox: f.[pp center /local a b c d e f g h][
set [a b c d e f g h] collect [fe* e pp [keep/only project e/1 e/2 e/3 center]]
c.[ pen brown polygon (a) (b) (c) (d) ; bottom
pen sky polygon (e) (f) (g) (h) ; top
pen navy line (a) (e) line (b) (f) ; back
pen maroon line (c) (g) line (d) (h) ] ; front
]
; tiny axis display
tiny-axis: f.[pos s] [
o: project 0 0 0 pos
x: project s 0 0 pos
y: project 0 s 0 pos
z: project 0 0 s pos
c.[pen red line (o) (x) pen green line (o) (y) pen blue line (o) (z)]
]
draw-it: f.[fig center][
clear drawing
; axis
a. drawing tiny-axis fig/size * 0.9 fig/size/1 * 0.005
a. drawing bbox [ [-15 -18 -10][10 -18 -10][10 -18 5][-15 -18 5]
[-15 20 -10][10 20 -10][10 20 5][-15 20 5] ] center
fe* jb jobs [c? [
; == DOTS ==
'dots = jb [
wire: fig/axis/dots
xx: wire/xx nv: l. xx
yy: wire/yy nu: l. yy
zz: wire/zz
a. drawing [pen off fill-pen white]
a. drawing c. collect [
r* j nu [
r* i nv [
p1: project xx/:i/:j yy/:i/:j zz/:i/:j center
rr: max 0 min 255 i' p1/1 * 0.1
gg: max 0 min 255 i' j * 3;p1/2 * 0.4
bb: max 0 min 255 i' p1/2 * 0.2
clr: as-color rr gg bb
keep c. [circle (p1) 1]
]
]
]
]
; == WIREFRAME ==
'wire = jb [
wire: fig/axis/wire
xx: wire/xx nv: l. xx
yy: wire/yy nu: l. yy
zz: wire/zz
a. drawing [fill-pen off]
a. drawing c. collect [
r* j (nu - 1) [
r* i nv [
nj: j + 1
ni: i + 1 i? i = nv [ni: 1]
p1: project xx/:i/:j yy/:i/:j zz/:i/:j center
p2: project xx/:ni/:j yy/:ni/:j zz/:ni/:j center
p3: project xx/:ni/:nj yy/:ni/:nj zz/:ni/:nj center
p4: project xx/:i/:nj yy/:i/:nj zz/:i/:nj center
rr: max 0 min 255 i' p1/1 * 0.3
gg: max 0 min 255 i' i * 2 ; i * 2;p1/2 * 0.4
bb: max 0 min 255 i' p1/2 * 0.3
clr: as-color rr gg bb
keep c. [pen (clr) polygon (p1) (p2) (p3) (p4)]
]
]
]
]
; == SURFACE ==
'surf = jb [
wire: fig/axis/surf
xx: wire/xx nv: l. xx
yy: wire/yy nu: l. yy
zz: wire/zz
a. drawing [pen 10.10.10.100]
a. drawing c. collect [
r* j (nu - 1) [
r* i nv [
nj: j + 1
ni: i + 1 i? i = nv [ni: 1]
p1: project xx/:i/:j yy/:i/:j zz/:i/:j center
p2: project xx/:ni/:j yy/:ni/:j zz/:ni/:j center
p3: project xx/:ni/:nj yy/:ni/:nj zz/:ni/:nj center
p4: project xx/:i/:nj yy/:i/:nj zz/:i/:nj center
rr: max 0 min 255 i' p1/1 * 0.4
gg: max 0 min 255 i' 0 ;p1/2 * 0.4
bb: max 0 min 255 i' p1/2 * 0.6
clr: as-rgba rr gg bb 150
keep c. [fill-pen (clr) polygon (p1) (p2) (p3) (p4)]
]
]
]
]
]] ; /jobs
a. drawing c.[
; info
pen coal
text 10x10 (rejoin ["angle-x: " s' angle-x])
text 10x20 (rejoin ["angle-y: " s' angle-y])
text 10x30 (rejoin ["perspective: " s' perspective])
]
] ; /draw-it
display: f.[fig
/local axis center wire xx yy zz
;angle-x angle-y perspective
;is-dragging last-mouse
i j p ] [
axis: fig/axis
center: fig/size / 2
jobs: axis/jobs
angle-x: axis/azimuth
angle-y: axis/elevation
perspective: axis/perspective
is-dragging?: no
last-mouse: none
draw-it fig center
view/tight compose [
title (axis/title)
canvas: base (fig/size) black all-over
draw drawing
rate 60 on-time [draw-it fig center]
on-down [is-dragging?: yes last-mouse: event/offset]
on-up [is-dragging?: no]
on-over [
i? is-dragging? [
delta: event/offset - last-mouse
last-mouse: event/offset
angle-y: angle-y + (delta/x * 0.4)
angle-x: angle-x - (delta/y * 0.4)
]
]
return below
text "perpesctive:" below persp: slider 500 [
val: face/data
e? val > 0.95 [ perspective: 0.0 ]
[ perspective: f' (val * 500.0) + 50.0 ]
]
]
]
] ; /red-makie
; API:
figure: :red-makie/figure
axis3: :red-makie/axis3
wireframe: :red-makie/wireframe
dots: :red-makie/dots
surface: :red-makie/surface
display: :red-makie/display
; == KLEIN BOTTLE ==
klein-bottle: f.[u v] [
t: 4 * (1 - ((cos u) / 2))
x: 6 * (cos u) * (1 + sin u) + (t * e? u < pi [(cos u) * cos v ][cos (v + pi)])
y: 16 * (sin u) + e? u < pi [(t * (sin u) * cos v)][0]
z: t * sin v
r.[x y z] ; place bow on xy plane
]
plot-klein-bottle: f.[/local nu nv u v a xx yy zz fig ax wr] [
nu: 50
nv: 50
u: range2 r.[0 (2 * pi) nu]
v: range2 r.[0 (2 * pi) nv]
xx: matrix nu nv
yy: similar xx
zz: similar xx
r* i l. u [r* j l. v [
set [x y z] klein-bottle u/:i v/:j
xx/:i/:j: x
yy/:i/:j: y
zz/:i/:j: z
]]
fig: figure 600x600
ax: axis3
fig
"Klein Bottle"
0 ;
250.0 ; perspective
180.0 ; angle-x, turned-up
0.0 ; angle-y
wr: surface
ax
xx yy zz
sky ; not used
1 ; line-width
fig
]
display plot-klein-bottle ; start drawing
- Output:
load "guilib.ring"
new qApp {
# 1. Initialize main window
win1 = new qWidget() {
setwindowtitle("True Classic Klein Bottle GUI - Ring")
setgeometry(100, 100, 900, 700)
# 2. Virtual canvas (Picture)
canvas = new qPicture()
painter = new qPainter() {
begin(canvas)
# Fill background with dark navy/black
bgColor = new qColor() { setrgb(10, 10, 15, 255) }
bgBrush = new qBrush() {
setstyle(1)
setcolor(bgColor)
}
setbrush(bgBrush)
drawrect(0, 0, 900, 700)
# Set pen for the 3D mesh (Neon cyan)
pen1 = new qPen()
pen1.setcolor(new qColor() { setrgb(0, 229, 255, 120) }) # Slight transparency for depth effect
pen1.setwidth(1)
setpen(pen1)
# Resolution parameters for the true shape
steps_u = 50
steps_v = 40
pi = 3.14159265
# 2D arrays to store screen coordinates for drawing grid lines
# In Ring, lists are dynamic; we pre-initialize the rows
points_x = list(steps_u + 1)
points_y = list(steps_u + 1)
for i = 1 to steps_u + 1
points_x[i] = list(steps_v + 1)
points_y[i] = list(steps_v + 1)
next
# --- STEP 1: Calculate mathematical points and project them ---
for u = 0 to steps_u
u_val = (u / steps_u) * 2 * pi # True range: from 0 to 2pi
for v = 0 to steps_v
v_val = (v / steps_v) * 2 * pi
# Classical "bottle" Klein bottle equations (Stewart Dickson / Mathworld formula)
if u_val < pi
x = 6 * cos(u_val) * (1 + sin(u_val)) + (4 * (1 - cos(u_val) / 2)) * cos(u_val) * cos(v_val)
z = 16 * sin(u_val) + (4 * (1 - cos(u_val) / 2)) * sin(u_val) * cos(v_val)
else
x = 6 * cos(u_val) * (1 + sin(u_val)) + (4 * (1 - cos(u_val) / 2)) * cos(v_val + pi)
z = 16 * sin(u_val)
ok
y = (4 * (1 - cos(u_val) / 2)) * sin(v_val)
# 3D -> 2D Projection (with 30-degree rotation around Y and Z axes for better depth)
cos_a = 0.866 # cos(30)
sin_a = 0.500 # sin(30)
# Rotated coordinates
x_rot = x * cos_a - y * sin_a
y_rot = x * sin_a + y * cos_a
z_rot = z
# Scale and translate to the center of the 900x700 window
scale = 17
screen_x = 450 + (x_rot - y_rot * 0.3) * scale
screen_y = 400 - (z_rot - y_rot * 0.2) * scale
# Save for wireframe drawing (1-based indexing in Ring)
points_x[u+1][v+1] = screen_x
points_y[u+1][v+1] = screen_y
next
next
# --- STEP 2: Connect the 3D wireframe mesh ---
for u = 1 to steps_u
for v = 1 to steps_v
# Line to adjacent V point (U lines)
drawline(points_x[u][v], points_y[u][v], points_x[u][v+1], points_y[u][v+1])
# Line to adjacent U point (V lines)
drawline(points_x[u][v], points_y[u][v], points_x[u+1][v], points_y[u+1][v])
next
next
endpaint()
}
# 3. Display using a Label component
label1 = new qLabel(win1) {
setgeometry(0, 0, 900, 700)
setpicture(canvas)
}
show()
}
exec()
}import "dome" for Window
import "graphics" for Canvas, Color
import "math" for Math
class KleinBottle {
construct new() {
Window.title = "Klein Bottle"
Window.resize(900, 700)
Canvas.resize(900, 700)
var clr = Color.rgb(10, 10, 15, 255) // dark navy/black
Canvas.cls(clr)
}
init() {
drawBottle()
}
drawBottle() {
// Resolution parameters for the true shape.
var stepsU = 50
var stepsV = 40
// 2D arrays to store screen coordinates for drawing grid lines.
var pointsX = List.filled(stepsU + 1, null)
var pointsY = List.filled(stepsU + 1, null)
for (i in 0..stepsU) {
pointsX[i] = List.filled(stepsV + 1, 0)
pointsY[i] = List.filled(stepsV + 1, 0)
}
// STEP 1: Calculate mathematical points and project them.
for (u in 0..stepsU) {
var uVal = (u / stepsU) * 2 * Num.pi // true range: 0 to 2pi
for (v in 0..stepsV) {
var vVal = (v / stepsV) * 2 * Num.pi
var x
var z
// Klein bottle equations (Stewart Dickson / Mathworld formula)
if (uVal < Num.pi) {
x = 6 * Math.cos(uVal) * (1 + Math.sin(uVal)) + 4 * (1 - Math.cos(uVal)/2) * Math.cos(uVal) * Math.cos(vVal)
z = 16 * Math.sin(uVal) + 4 * (1 - Math.cos(uVal)/2) * Math.sin(uVal) * Math.cos(vVal)
} else {
x = 6 * Math.cos(uVal) * (1 + Math.sin(uVal)) + 4 * (1 - Math.cos(uVal)/2) * Math.cos(vVal + Num.pi)
z = 16 * Math.sin(uVal)
}
var y = 4 * (1 - Math.cos(uVal)/2) * Math.sin(vVal)
// 3D -> 2D Projection (with 30-degree rotation around Y and Z axes for better depth)
var cosA = Math.cos(Num.pi / 6) // cos 30°
var sinA = Math.sin(Num.pi / 6) // sin 30°
// Rotated coordinates.
var xRot = x * cosA - y * sinA
var yRot = x * sinA + y * cosA
var zRot = z
// Scale and translate to the center of the window (900 x 700).
var scale = 17
var screenX = 450 + (xRot - yRot * 0.3) * scale
var screenY = 400 - (zRot - yRot * 0.2) * scale
// Save points for wireframe drawing.
pointsX[u][v] = screenX
pointsY[u][v] = screenY
}
}
// STEP 2: Connect the 3D wireframe mesh.
// Color: neon/cyan with slight transparency for depth effect.
var clr = Color.rgb(0, 229, 255, 120)
for (u in 0...stepsU) {
for (v in 0...stepsV) {
// Line to adjacent V point (U lines).
Canvas.line(pointsX[u][v], pointsY[u][v], pointsX[u][v+1], pointsY[u][v+1], clr)
// Line to adjacent V point (U lines).
Canvas.line(pointsX[u][v], pointsY[u][v], pointsX[u+1][v], pointsY[u+1][v+1], clr)
}
}
}
update() {}
draw(dt) {}
}
var Game = KleinBottle.new()
ScrW = 900
ScrH = 700
steps_u = 50
steps_v = 40
total = (steps_u+1) * (steps_v+1)
dim points_x(total)
dim points_y(total)
open window ScrW, ScrH
color 10,10,15
fill rectangle 0,0 to ScrW,ScrH
REM STEP 1: Calculate points
for u = 0 to steps_u
u_val = (u / steps_u) * 2 * PI
for v = 0 to steps_v
v_val = (v / steps_v) * 2 * PI
if u_val < PI then
x = 6*cos(u_val) * (1+sin(u_val)) + (4*(1-cos(u_val)/2)) * cos(u_val)*cos(v_val)
z = 16*sin(u_val) + (4*(1-cos(u_val)/2)) * sin(u_val)*cos(v_val)
else
x = 6*cos(u_val) * (1+sin(u_val)) + (4*(1-cos(u_val)/2)) * cos(v_val+PI)
z = 16*sin(u_val)
fi
y = (4*(1-cos(u_val)/2))*sin(v_val)
cos_a = 0.866
sin_a = 0.5
x_rot = x*cos_a - y*sin_a
y_rot = x*sin_a + y*cos_a
z_rot = z
scale = 17
sx = 450 + (x_rot - y_rot*0.3)*scale
sy = 400 - (z_rot - y_rot*0.2)*scale
idx = u * steps_v + v
points_x(idx) = sx
points_y(idx) = sy
next
next
REM STEP 2: Draw mesh
color 0,229,255
for u = 0 to steps_u-1
for v = 0 to steps_v-1
idx1 = u * steps_v + v
idx2 = u * steps_v + (v+1)
idx3 = (u+1) * steps_v + v
line points_x(idx1), points_y(idx1) to points_x(idx2), points_y(idx2)
line points_x(idx1), points_y(idx1) to points_x(idx3), points_y(idx3)
next
next
- Output:
Similar to FreeBASIC entry.