summaryrefslogtreecommitdiff
path: root/appl/spree/other/tstboing.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/spree/other/tstboing.b')
-rw-r--r--appl/spree/other/tstboing.b158
1 files changed, 158 insertions, 0 deletions
diff --git a/appl/spree/other/tstboing.b b/appl/spree/other/tstboing.b
new file mode 100644
index 00000000..a599a0ab
--- /dev/null
+++ b/appl/spree/other/tstboing.b
@@ -0,0 +1,158 @@
+implement Tst;
+
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+ draw: Draw;
+ Point, Rect: import draw;
+include "sh.m";
+ sh: Sh;
+ Context: import Sh;
+include "math.m";
+ math: Math;
+ZERO: con 1e-6;
+
+stderr: ref Sys->FD;
+
+Tst: module {
+ init: fn(nil: ref Draw->Context, argv: list of string);
+};
+π: con Math->Pi;
+Maxδ: con π / 4.0;
+
+init(nil: ref Draw->Context, argv: list of string)
+{
+ sys = load Sys Sys->PATH;
+ stderr = sys->fildes(2);
+ math = load Math Math->PATH;
+ if (len argv != 9) {
+ sys->fprint(stderr, "args?\n");
+ exit;
+ }
+ ar := argv2r(tl argv);
+ br := argv2r(tl tl tl tl tl argv);
+
+ a := Line.new(ar.min, ar.max); # ball
+ b := Line.new(br.min, br.max); # bat
+ (hit, hitp, s, t) := b.intersection(a.p, a.v);
+ if (hit) {
+ nv := boing(a.v, b);
+ rl := ref Line(hitp, nv, 50.0);
+ ballθ := a.θ();
+ batθ := b.θ();
+ φ := ballθ - batθ;
+ δ: real;
+ if (math->sin(φ) > 0.0)
+ δ = (t / b.s) * Maxδ * 2.0 - Maxδ;
+ else
+ δ = (t / b.s) * -Maxδ * 2.0 + Maxδ;
+ nl := Line.newpolar(rl.p, rl.θ() + δ, rl.s);
+ sys->print("%s %s %s\n", p2s(rl.point(0.0)), p2s(rl.point(rl.s)), p2s(nl.point(nl.s)));
+ } else
+ sys->fprint(stderr, "no hit\n");
+}
+
+argv2r(v: list of string): Rect
+{
+ r: Rect;
+ (r.min.x, v) = (int hd v, tl v);
+ (r.min.y, v) = (int hd v, tl v);
+ (r.max.x, v) = (int hd v, tl v);
+ (r.max.y, v) = (int hd v, tl v);
+ return r;
+}
+Line: adt {
+ p, v: Realpoint;
+ s: real;
+ new: fn(p1, p2: Point): ref Line;
+ hittest: fn(l: self ref Line, p: Point): (Realpoint, real, real);
+ intersection: fn(b: self ref Line, p, v: Realpoint): (int, Realpoint, real, real);
+ point: fn(b: self ref Line, s: real): Point;
+ θ: fn(b: self ref Line): real;
+ newpolar: fn(p: Realpoint, θ: real, s: real): ref Line;
+};
+
+Realpoint: adt {
+ x, y: real;
+};
+
+Line.new(p1, p2: Point): ref Line
+{
+ ln := ref Line;
+ ln.p = (real p1.x, real p1.y);
+ v := Realpoint(real (p2.x - p1.x), real (p2.y - p1.y));
+ ln.s = math->sqrt(v.x * v.x + v.y * v.y);
+ if (ln.s > ZERO)
+ ln.v = (v.x / ln.s, v.y / ln.s);
+ else
+ ln.v = (1.0, 0.0);
+ return ln;
+}
+
+Line.newpolar(p: Realpoint, θ: real, s: real): ref Line
+{
+ l := ref Line;
+ l.p = p;
+ l.s = s;
+ l.v = (math->cos(θ), math->sin(θ));
+ return l;
+}
+
+Line.θ(l: self ref Line): real
+{
+ return math->atan2(l.v.y, l.v.x);
+}
+
+# return normal from line, perpendicular distance from line and distance down line
+Line.hittest(l: self ref Line, ip: Point): (Realpoint, real, real)
+{
+ p := Realpoint(real ip.x, real ip.y);
+ v := Realpoint(-l.v.y, l.v.x);
+ (nil, nil, perp, ldist) := l.intersection(p, v);
+ return (v, perp, ldist);
+}
+
+Line.point(l: self ref Line, s: real): Point
+{
+ return (int (l.p.x + s * l.v.x), int (l.p.y + s * l.v.y));
+}
+
+# compute the intersection of lines a and b.
+# b is assumed to be fixed, and a is indefinitely long
+# but doesn't extend backwards from its starting point.
+# a is defined by the starting point p and the unit vector v.
+# return whether it hit, the point at which it hit if so,
+# the distance of the intersection point from p,
+# and the distance of the intersection point from b.p.
+Line.intersection(b: self ref Line, p, v: Realpoint): (int, Realpoint, real, real)
+{
+ det := b.v.x * v.y - v.x * b.v.y;
+ if (det > -ZERO && det < ZERO)
+ return (0, (0.0, 0.0), 0.0, 0.0);
+
+ y21 := b.p.y - p.y;
+ x21 := b.p.x - p.x;
+ s := (b.v.x * y21 - b.v.y * x21) / det;
+ t := (v.x * y21 - v.y * x21) / det;
+ if (s < 0.0)
+ return (0, (0.0, 0.0), s, t);
+ hit := t >= 0.0 && t <= b.s;
+ hp: Realpoint;
+ if (hit)
+ hp = (p.x+v.x*s, p.y+v.y*s);
+ return (hit, hp, s, t);
+}
+
+# bounce ball travelling in direction av off line b.
+# return the new unit vector.
+boing(av: Realpoint, b: ref Line): Realpoint
+{
+ d := math->atan2(real b.v.y, real b.v.x) * 2.0 - math->atan2(av.y, av.x);
+ return (math->cos(d), math->sin(d));
+}
+
+p2s(p: Point): string
+{
+ return string p.x + " " + string p.y;
+}
+