Skip to content

Commit

Permalink
Change point repr to record
Browse files Browse the repository at this point in the history
  • Loading branch information
pdnm committed Jan 13, 2019
1 parent 78187a5 commit df0594f
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 82 deletions.
42 changes: 22 additions & 20 deletions ch7/circles.ml
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@
open Printf

type 'a point = Point of 'a * 'a
type 'a point = { x: 'a; y: 'a }
let point (x, y) = { x; y }

type 'a circle = { c: 'a point; r: 'a }
type 'a circle = { center: 'a point; radius: 'a }

let pi = Float.pi
let sqr x = x *. x
let deg_to_rad d = d *. pi /. 180.

let inside_circle (Point(x, y)) { c=Point(cx, cy); r } =
let dx, dy = x - cx, y - cy in
compare (dx * dx + dy * dy) (r * r) + 1 (* 0 inside / 1 border / 2 outside *)
(* Returns: 0 inside / 1 border / 2 outside *)
let inside_circle {x; y} { center; radius } =
let dx, dy = x - center.x, y - center.y in
compare (dx * dx + dy * dy) (radius * radius) + 1

(** Returns the center of a circle with radius r and goes through 2 points.
To get the other center, reverse p1 and p2 *)
let circle_2pts_rad (Point(x1, y1)) (Point(x2, y2)) r =
let d2 = sqr (x1 -. x2) +. sqr (y1 -. y2) in
let circle_2pts_rad p1 p2 r =
let d2 = sqr (p1.x -. p2.x) +. sqr (p1.y -. p2.y) in
let det = sqr r /. d2 -. 0.25 in
if det < 0. then None else
let h = sqrt det in
let cx = (x1 +. x2) *. 0.5 +. (y1 -. y2) *. h in
let cy = (y1 +. y2) *. 0.5 +. (x1 -. x2) *. h in
Some (Point(cx, cy))
let cx = (p1.x +. p2.x) *. 0.5 +. (p1.y -. p2.y) *. h in
let cy = (p1.y +. p2.y) *. 0.5 +. (p1.x -. p2.x) *. h in
Some (point(cx, cy))

let () =
let circle = { c = Point(2, 2); r = 7 } in
let inside = Point(8, 2) in printf "%d\n" (inside_circle inside circle);
let border = Point(9, 2) in printf "%d\n" (inside_circle border circle);
let outside = Point(10, 2) in printf "%d\n" (inside_circle outside circle);
let circle = { center = point(2, 2); radius = 7 } in
let inside = point(8, 2) in printf "%d\n" (inside_circle inside circle);
let border = point(9, 2) in printf "%d\n" (inside_circle border circle);
let outside = point(10, 2) in printf "%d\n" (inside_circle outside circle);

let r = float_of_int circle.r in
let r = float_of_int circle.radius in
let d = r *. 2. in
let c = d *. pi in
let area = pi *. sqr r in
Expand All @@ -44,10 +46,10 @@ let () =
printf "Area of sector (central angle = 60 degrees) = %.2f\n"
(60.0 /. 360.0 *. area);

let p1 = Point(0., 0.) in
let p2 = Point(0., -1.) in
let p1 = point(0., 0.) in
let p2 = point(0., -1.) in
match circle_2pts_rad p1 p2 2., circle_2pts_rad p2 p1 2. with
| Some (Point(x1, y1)), Some (Point(x2, y2)) ->
printf "One of the center is (%.2f, %.2f)\n" x1 y1;
printf "The other center is (%.2f, %.2f)\n" x2 y2;
| Some p1, Some p2 ->
printf "One of the center is (%.2f, %.2f)\n" p1.x p1.y;
printf "The other center is (%.2f, %.2f)\n" p2.x p2.y;
| _ -> assert false
79 changes: 40 additions & 39 deletions ch7/points_lines.ml
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ let pi = Float.pi
let deg_to_rad d = d *. pi /. 180.
let rad_to_deg r = r *. 180. /. pi

type point = Point of float * float
type point = { x: float; y: float }
let point (x, y) = { x; y }

let dist (Point(x1, y1)) (Point(x2, y2)) = hypot (x1 -. x2) (y1 -. y2)
let dist a b = hypot (a.x -. b.x) (a.y -. b.y)

let rotate (Point (x, y)) degree =
let rotate {x; y} degree =
let rad = deg_to_rad degree in
let sin = sin rad in
let cos = cos rad in
Point(x *. cos -. y *. sin, x *. sin +. y *. cos)
point(x *. cos -. y *. sin, x *. sin +. y *. cos)

type vector = Vector of float * float

let to_vec (Point(x1, y1)) (Point(x2, y2)) = Vector(x2 -. x1, y2 -. y1)
let to_vec a b = Vector(b.x -. a.x, b.y -. a.y)
let scale (Vector(a, b)) s = Vector(a *. s, b *. s)
let translate (Point(x, y)) (Vector(a, b)) = Point(x +. a, y +. b)
let translate {x; y} (Vector(a, b)) = point(x +. a, y +. b)
let dot (Vector(a1, b1)) (Vector(a2, b2)) = a1 *. a2 +. b1 *. b2
let norm v = sqrt (dot v v)
let cross (Vector(a1, b1)) (Vector(a2, b2)) = a1 *. b2 -. a2 *. b1
Expand All @@ -48,23 +49,23 @@ end = struct
(** ax + by + c = 0 *)
type line = { a: float; b: float; c: float }

let through_points (Point(x1, y1)) (Point(x2, y2)) =
if near x1 x2 then { a = 1.; b = 0.; c = -. x1 }
let through_points p1 p2 =
if near p1.x p2.x then { a = 1.; b = 0.; c = -. p1.x }
else
let a = -. (y1 -. y2) /. (x1 -. x2) in
{ a; b = 1.; c = -. a *. x1 -. y1 }
let a = -. (p1.y -. p2.y) /. (p1.x -. p2.x) in
{ a; b = 1.; c = -. a *. p1.x -. p1.y }

let from_point_slope (Point (x, y)) m =
let from_point_slope {x; y} m =
let a, b = -. m, 1. in
{ a; b; c = -. ((a *. x) +. (b *. y)) }

type line2 = { m: float; c: float }

let through_points2 (Point(x1, y1)) (Point(x2, y2)) =
if near x1 x2 then None
let through_points2 p1 p2 =
if near p1.x p2.x then None
else
let m = (y1 -. y2) /. (x1 -. x2) in
let c = y1 -. m *. x1 in
let m = (p1.y -. p2.y) /. (p1.x -. p2.x) in
let c = p1.y -. m *. p1.x in
Some { m; c }

let are_parallel l1 l2 = near l1.a l2.a && near l1.b l2.b
Expand All @@ -78,11 +79,11 @@ end = struct
let y =
if not (near l1.b 0.) then -. (l1.a *. x +. l1.c)
else -. (l2.a *. x +. l2.c) in
Some (Point (x, y))
Some (point (x, y))

let closest_point l (Point(x, y) as p) =
if near l.b 0. then Point(-. l.c, y) else
if near l.a 0. then Point(x, -. l.c) else
let closest_point l ({x; y} as p) =
if near l.b 0. then point(-. l.c, y) else
if near l.a 0. then point(x, -. l.c) else
let perpendicular = from_point_slope p (1. /. l.a) in
match intersect l perpendicular with
| Some q -> q
Expand Down Expand Up @@ -115,16 +116,16 @@ let dist_to_segment p a b : float * point =
let () =
(* sorting points demo *)
let p =
[ Point(2., 2.)
; Point(4., 3.)
; Point(2., 4.)
; Point(6., 6.)
; Point(2., 6.)
; Point(6., 5.)] in
[ point(2., 2.)
; point(4., 3.)
; point(2., 4.)
; point(6., 6.)
; point(2., 6.)
; point(6., 5.)] in
p
|> List.sort (fun (Point(x1, y1)) (Point(x2, y2)) ->
if near x1 x2 then compare y1 y2 else compare x1 x2)
|> List.iter (fun (Point(x, y)) -> printf "(%.2f, %.2f)\n" x y);
|> List.sort (fun p1 p2 ->
if near p1.x p2.x then compare p1.y p2.y else compare p1.x p2.x)
|> List.iter (fun {x; y} -> printf "(%.2f, %.2f)\n" x y);

(* the positions of these 7 points (0-based indexing)
6 P4 P3 P6
Expand All @@ -134,7 +135,7 @@ let () =
2 P0
1
0 1 2 3 4 5 6 7 8 *)
let p = p @ [Point(8., 6.)] |> Array.of_list in
let p = p @ [point(8., 6.)] |> Array.of_list in
printf "Euclidean distance between P[0] and P[5] = %.2f\n" (dist p.(0) p.(5));

let l1 = Line.through_points p.(0) p.(1) in
Expand All @@ -150,22 +151,22 @@ let () =
printf "l2 & l4 are the same? %d\n" (Line.are_same l2 l4 |> bool_to_int);

(match Line.intersect l1 l2 with
| Some (Point(x, y)) ->
| Some {x; y} ->
printf "l1 & l2 are intersect? 1, at (%.2f, %.2f)\n" x y
| None -> ());

let fmt = format_of_string ": (%.2f, %.2f), dist = %.2f\n" in
let d, (Point(x, y)) = altitude p.(0) p.(2) p.(3) in
let d, {x; y} = altitude p.(0) p.(2) p.(3) in
printf ("Closest point from P[0] to line (P[2]-P[3])" ^^ fmt) x y d;
let (Point(x, y) as q) = Line.closest_point l3 p.(0) in
let ({x; y} as q) = Line.closest_point l3 p.(0) in
printf ("Closest point from P[0] to line V2 (P[2]-P[3])" ^^ fmt) x y (dist p.(0) q);

[(0, 2, 3); (1, 2, 3); (6, 2, 3)] |> List.iter (fun (i, j, k) ->
let d, (Point(x, y)) = dist_to_segment p.(i) p.(j) p.(k) in
let d, {x; y} = dist_to_segment p.(i) p.(j) p.(k) in
printf ("Closest point from P[%d] to line SEGMENT (P[%d]-P[%d])" ^^ fmt) i j k x y d
);

let (Point(x, y)) = Line.reflection_point l4 p.(1) in
let {x; y} = Line.reflection_point l4 p.(1) in
printf "Reflection point from P[1] to line (P[2]-P[4]): (%.2f, %.2f)\n" x y;

[(0, 4, 3); (0, 2, 1); (4, 3, 6)] |> List.iter (fun (i, j, k) ->
Expand All @@ -180,7 +181,7 @@ let () =
printf "P[%d], P[%d], P[%d] are collinear? %d\n" i j k (collinear p.(i) p.(j) p.(k) |> bool_to_int)
);

let p, q, r = Point(3., 7.), Point(11., 13.), Point(35., 30.) in
let p, q, r = point(3., 7.), point(11., 13.), point(35., 30.) in
printf "r is on the %s of line p-r\n" (if ccw p q r then "left" else "right");

(* the positions of these 6 points
Expand All @@ -192,14 +193,14 @@ let () =
-1
-2
F<-- -3 *)
let a = Point(2., 2.) in
let b = Point(4., 3.) in
let c = Point(3., 2.) in
let a = point(2., 2.) in
let b = point(4., 3.) in
let c = point(3., 2.) in
let v = to_vec a b in

(* translation *)
let d = translate c v in
let point_to_string (Point(x, y)) = sprintf "(%.2f, %.2f)" x y in
let point_to_string {x; y} = sprintf "(%.2f, %.2f)" x y in
printf "D = %s\n" (point_to_string d);
let e = translate c (scale v 0.5) in
printf "E = %s\n" (point_to_string e);
Expand Down
46 changes: 23 additions & 23 deletions ch7/triangles.ml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ let pi = Float.pi
let deg_to_rad d = d *. pi /. 180.
let rad_to_deg r = r *. 180. /. pi

type point = Point of float * float
type point = { x: float; y: float }
let point (x, y) = { x; y }

let dist (Point(x1, y1)) (Point(x2, y2)) = hypot (x1 -. x2) (y1 -. y2)
let dist a b = hypot (a.x -. b.x) (a.y -. b.y)

type vector = Vector of float * float

let to_vec (Point(x1, y1)) (Point(x2, y2)) = Vector(x2 -. x1, y2 -. y1)
let to_vec a b = Vector(b.x -. a.x, b.y -. a.y)
let scale (Vector(a, b)) s = Vector(a *. s, b *. s)
let translate (Point(x, y)) (Vector(a, b)) = Point(x +. a, y +. b)
let translate {x; y} (Vector(a, b)) = point(x +. a, y +. b)
let dot (Vector(a1, b1)) (Vector(a2, b2)) = a1 *. a2 +. b1 *. b2
let norm v = sqrt (dot v v)
let cross (Vector(a1, b1)) (Vector(a2, b2)) = a1 *. b2 -. a2 *. b1
Expand All @@ -45,11 +46,11 @@ end = struct
(** ax + by + c = 0 *)
type line = { a: float; b: float; c: float }

let through_points (Point(x1, y1)) (Point(x2, y2)) =
if near x1 x2 then { a = 1.; b = 0.; c = -. x1 }
let through_points p1 p2 =
if near p1.x p2.x then { a = 1.; b = 0.; c = -. p1.x }
else
let a = -. (y1 -. y2) /. (x1 -. x2) in
{ a; b = 1.; c = -. a *. x1 -. y1 }
let a = -. (p1.y -. p2.y) /. (p1.x -. p2.x) in
{ a; b = 1.; c = -. a *. p1.x -. p1.y }

let are_parallel l1 l2 = near l1.a l2.a && near l1.b l2.b

Expand All @@ -62,7 +63,7 @@ end = struct
let y =
if not (near l1.b 0.) then -. (l1.a *. x +. l1.c)
else -. (l2.a *. x +. l2.c) in
Some (Point (x, y))
Some (point (x, y))

let to_string line =
sprintf "%.2f * x + %.2f * y + %.2f = 0.00" line.a line.b line.c
Expand All @@ -77,9 +78,10 @@ let sqr x = x *. x

let can_form_triangle x y z = x +. y > z && y +. z > x && x +. z > y

let inside_circle (Point(x, y)) { center=Point(cx, cy); radius=r } =
let dx, dy = x -. cx, y -. cy in
compare (sqr dx +. sqr dy) (sqr r) + 1 (* 0 inside / 1 border / 2 outside *)
(* Returns: 0 inside / 1 border / 2 outside *)
let inside_circle {x; y} { center; radius } =
let dx, dy = x -. center.x, y -. center.y in
compare (dx *. dx +. dy *. dy) (radius *. radius) + 1

let perimeter (Triangle(a, b, c)) = dist a b +. dist b c +. dist c a

Expand All @@ -105,26 +107,24 @@ let r_circumcircle (Triangle(a, b, c) as t) =
dist a b *. dist b c *. dist c a /. (4. *. area t)

let circumcircle (Triangle(p1, p2, p3)) =
let x (Point(x', _)) = x' in
let y (Point(_, y')) = y' in
let a, b = x p2 -. x p1, y p2 -. y p1 in
let c, d = x p3 -. x p1, y p3 -. y p1 in
let e = a *. (x p1 +. x p2) +. b *. (y p1 +. y p2) in
let f = c *. (x p1 +. x p3) +. d *. (y p1 +. y p3) in
let g = 2. *. (a *. (y p3 -. y p2) -. b *. (x p3 -. x p2)) in
let a, b = p2.x -. p1.x, p2.y -. p1.y in
let c, d = p3.x -. p1.x, p3.y -. p1.y in
let e = a *. (p1.x +. p2.x) +. b *. (p1.y +. p2.y) in
let f = c *. (p1.x +. p3.x) +. d *. (p1.y +. p3.y) in
let g = 2. *. (a *. (p3.y -. p2.y) -. b *. (p3.x -. p2.x)) in
if near g 0. then None else
let center = Point((d *. e -. b *. f) /. g, (a *. f -. c *. e) /. g) in
let center = point((d *. e -. b *. f) /. g, (a *. f -. c *. e) /. g) in
Some { center; radius = dist p1 center }

let in_circumcircle triangle p =
circumcircle triangle |> Option.fold false (fun circle ->
inside_circle p circle = 0)

let () =
let t = Triangle(Point(0., 0.), Point(4., 0.), Point(4., 3.)) in
let t = Triangle(point(0., 0.), point(4., 0.), point(4., 3.)) in
printf "Area = %.2f\n" (area t);

let to_string (Point(x, y)) = sprintf "(%.2f, %.2f)" x y in
let to_string {x; y} = sprintf "(%.2f, %.2f)" x y in

incircle t |> Option.foreach (fun circle ->
printf "R1 (radius of incircle) = %.2f\n" circle.radius;
Expand All @@ -134,7 +134,7 @@ let () =
printf "R1 (radius of circumcircle) = %.2f\n" circle.radius;
printf "Center = %s\n" (to_string circle.center));

[Point(2.0, 1.0); Point(2.0, 3.9); Point(2.0, -1.1)]
[point(2.0, 1.0); point(2.0, 3.9); point(2.0, -1.1)]
|> List.iter (fun point ->
printf "%s inside circumCircle? %b\n"
(to_string point)
Expand Down

0 comments on commit df0594f

Please sign in to comment.