Skip to content

Commit

Permalink
Add Centroid theorem
Browse files Browse the repository at this point in the history
  • Loading branch information
newptcai committed May 12, 2020
1 parent 2ad2fb4 commit 912fdb4
Show file tree
Hide file tree
Showing 15 changed files with 385 additions and 28 deletions.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# PlaneGeomety
# PlaneGeomety.jl

This is collection used in my [blog post](https://newptcai.github.io/category/math.html) on using
Julia to prove some basic plane geometry theorems.
![Napoleon's Theorem](docs/src/assets/PlaneGeometry.svg)

This package originated from a [blog post](https://newptcai.github.io/category/math.html) I wrote on
proving Napoleon's theorem with Julia. I have since cleaned up the code and add a [new
theorem](https://newptcai.github.io/PlaneGeometry.jl/theorem/Centroid/). Please see [the document](https://newptcai.github.io/PlaneGeometry.jl/) for
details.
1 change: 1 addition & 0 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ makedocs(sitename="Plane Geometry in Julia",
[
"Summary" => "theorem/index.md",
"Napoleon" => "theorem/Napoleon.md",
"Centroid" => "theorem/Centroid.md",
],
"Utitlies" => "util.md",
"Ackowledgement" => "thanks.md",
Expand Down
57 changes: 54 additions & 3 deletions docs/src/definition/distance.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

## Euclidean distance

```@setup 1
using PlaneGeometry, Plots
using PlaneGeometry: A, B, C
```

```@docs
distance
```

### Source Code

```@example code
using PlaneGeometry # hide
```@example 1
@code_md distance(Point(), Point()) # hide
```

Expand All @@ -21,6 +25,53 @@ squaredist

### Source Code

```@example code
```@example 1
@code_md squaredist(Point(), Point()) # hide
```

## Midpoint of an edge

```@docs
midpoint
```

### Source Code

```@example 1
@code_md midpoint(Point(), Point()) # hide
```
### Picture

```@example 1
plot(Edge(A, B), leg=false, color=:orange)
mid = midpoint(A, B)
scatter!(shape([A, B, mid]), leg=false, aspect_ratio=:equal,
color=[:red, :red, :green], series_annotations = text.(["A", "B", "mid"], :bottom))
```

## Concurrent Point

```@docs
concurrent
```

### Source Code

```@example 1
@code_md concurrent(Edge[]) # hide
```
### Picture

```@example 1
elist = map(i->median(circshift([A, B, C], i)...), 0:2)
cpt = concurrent(elist)
plot(Triangle(A, B, C), fill=(0, :green), aspect_ratio=:equal, fillalpha= 0.2)
for e in elist
plot!(e, leg=false, color=:orange)
end
scatter!(shape([A, B, C, cpt]),
leg=false,
aspect_ratio=:equal,
color=[:red, :red, :red, :green],
series_annotations = text.(["A", "B", "C", "cpt"], :bottom))
```
23 changes: 23 additions & 0 deletions docs/src/definition/triangle.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,26 @@ for t in tri_out
end
plot!(tri, fill=(0, :green), aspect_ratio=:equal, fillalpha= 0.2)
```

## Median

```@docs
median
```

### Source Code

```@example 1
@code_md median(Point(), Point(), Point()) # hide
```

### Picture

```@example 1
me = median(A, B, C)
mid = midpoint(A, B)
scatter(shape([A, B, C, mid]), leg=false, color=:red,
series_annotations = text.(["A", "B", "C", "mid"], :bottom))
plot!(me, color=:orange)
plot!(tri, fill=(0, :green), aspect_ratio=:equal, fillalpha= 0.2)
```
73 changes: 73 additions & 0 deletions docs/src/theorem/Centroid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Centroid Exists Theorem

See [Napoleon's Theorem](Napoleon.md) for an example with more explanations.

```@setup 1
using
PlaneGeometry,
PlaneGeometry.Theorems,
PlaneGeometry.Theorems.Napoleon,
Plots
```

```@contents
Pages = ["Centroid.md"]
```

## The Theorem

```@docs
PlaneGeometry.Theorems.Centroid
```

## Finding the centroid and medians

```@docs
centroid
```
```@example 1
@code_md centroid(Triangle()) # hide
```

## Examples

```@docs
centroid_draw(::Triangle)
```

```@example 1
A = Point(0,0); B = Point(1, 3); C = Point(4,2)
plt, hold = centroid_draw(A, B, C)
does_thmhold(hold)
savefig("centroid-plot-1.svg"); nothing # hide
```

![centroid-plot-1.svg](centroid-plot-1.svg)

```@docs
centroid_rand()
```

```@example 1
plt, hold = centroid_rand()
does_thmhold(hold)
savefig("centroid-plot-2.svg"); nothing # hide
```
![centroid-plot-2.svg](centroid-plot-2.svg)

```@example 1
plt, hold = centroid_rand()
does_thmhold(hold)
savefig("centroid-plot-3.svg"); nothing # hide
```
![centroid-plot-3.svg](centroid-plot-3.svg)

## Proof

```@example 1
@code_md centroid_proof() # hide
```

```@example 1
does_thmhold(centroid_proof())
```
4 changes: 2 additions & 2 deletions docs/src/theorem/Napoleon.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Given a triangle, to find its Napoleon triangle, we use the following function.
napoleon_tri
```
```@example 1
@code_md napoleon_tri(Triangle()) #
@code_md napoleon_tri(Triangle()) # hide
```

## Examples
Expand Down Expand Up @@ -93,7 +93,7 @@ symbols provided by `SymPy`. Then we can just use `napoleon_tri` to find its Nap
check if it is equilateral. We put the code in the following function.

```@example 1
@code_md napoleon_proof()
@code_md napoleon_proof() # hide
```

And the final proof is a simple as one line of code ✌️.
Expand Down
17 changes: 14 additions & 3 deletions src/PlaneGeometry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ export
GeoObject, Point, Edge, Triangle, Circle,
vertices, edges,

# metrics
distance, squaredist,
# distances
distance, squaredist, midpoint, concurrent,

# triangles
equipoints, outer_equitri, outer_equitriangles, isequilateral,
equipoints, outer_equitri, outer_equitriangles, isequilateral, median,

# circles
circumcircle,
Expand All @@ -31,9 +31,20 @@ using .Theorems.Napoleon
export
napoleon_proof, napoleon_draw, napoleon_rand, napoleon_tri

using .Theorems.Centroid
export
centroid_proof, centroid_draw, centroid_rand, centroid

using .GeoPlots
export
plot, plot!, shape

function __init__()
global A, B, C

A = Point(0, 0);
B = Point(1, 3);
C = Point(4, 2);
end

end # module
55 changes: 50 additions & 5 deletions src/distance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,8 @@ end
"""
distance(A, B)
Compute the euclidean distance between `A` and `B`.
# Mathematical definition
> Euclidean distance or Euclidean metric is the "ordinary" straight-line distance between two points.
Compute the euclidean distance between `A` and `B`, which is the "ordinary" straight-line distance
between two points.
# Examples
```jldoctest
Expand All @@ -36,3 +33,51 @@ julia> distance(Point(0, 0), Point(3,4))
function distance(A, B)
SymPy.sqrt(squaredist(A, B))
end


"""
midpoint(A, B)
Find the midpoint between `A` and `B`.
# Examples
```jldoctest
julia> midpoint(Point(0, 0), Point(2,4))
Point(1, 2)
```
"""
function midpoint(A, B)
x1 = (A.x + B.x)/2
y1 = (A.y + B.y)/2
Point(x1, y1)
end


"""
concurrent(edgelist::Vector{Edge})
Find the point where all `edges` (lines) intersect if such point exists. Return nothing otherwise.
"""
function concurrent(edgelist::Vector{Edge})
enum = length(edgelist)
if enum == 1
throw(ArgumentError("At least two edges are needed. $enum is given."))
end

@vars x y

eqs = Sym[]
for e in edgelist
# This should be 0
eq = (x-e.src.x)*(y-e.dst.y) - (x-e.dst.x)*(y-e.src.y)
push!(eqs, eq)
end

sol = solve(eqs, [x,y])

if length(sol) == 0
return nothing
else
return Point(simplify(sol[x]), simplify(sol[y]))
end
end
14 changes: 8 additions & 6 deletions src/elementary.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Base: isequal, ==, show
using SymPy

"A plane geometric object."
abstract type GeoObject end
Expand All @@ -18,9 +19,11 @@ A = Point(0,0); B = Point(1, 3); C = Point(4,2)
"""
struct Point <: GeoObject
"x cooridnate"
x::Number
x::Sym
"y cooridnate"
y::Number
y::Sym

Point(x, y) = new(Sym(x), Sym(y))
end

"""
Expand All @@ -37,10 +40,6 @@ Point() = Point(0, 0)

show(io::IO, pt::Point) = print(io, "Point($(pt.x), $(pt.y))")

const A = Point(0,0);
const B = Point(1, 3);
const C = Point(4,2)

"""
Triangle(A, B, C)
Expand Down Expand Up @@ -109,6 +108,9 @@ struct Edge <: GeoShape
dst::Point
end

"Check if two edges are at the same."
(==)(e1::Edge, e2::Edge) = e1.src==e2.src && e1.dst==e2.dst

"Get the list of edges of the triangle `tri`."
function edges(tri::Triangle)
elist = Edge[]
Expand Down
23 changes: 21 additions & 2 deletions src/plots.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,34 @@ end;
"""
plot(obj::GeoObject, args...; kwargs...)
Plot a geometric object `obj`.
Plot `obj` on current plot.
"""
plot(obj::GeoObject, args...; kwargs...) = plot(shape(obj), args...; kwargs...)

"""
plot!(obj::GeoObject, args...; kwargs...)
Plot a geometric object `obj` on current plot.
Plot `obj` on current plot.
"""
plot!(obj::GeoObject, args...; kwargs...) = plot!(shape(obj), args...; kwargs...)

"""
plot!(edge::Edge, args...; kwargs...)
Plot `edge` on current plot.
"""
function plot!(edge::Edge, args...; kwargs...)
eshape = shape(edge)
plot!(eshape.x, eshape.y, args...; kwargs...)
end

"""
plot(edge::Edge, args...; kwargs...)
Plot `edge` on current plot.
"""
function plot(edge::Edge, args...; kwargs...)
eshape = shape(edge)
plot(eshape.x, eshape.y, args...; kwargs...)
end
end
Loading

0 comments on commit 912fdb4

Please sign in to comment.