Skip to content

Commit

Permalink
Merge pull request #797 from TaeJoongYoon/master
Browse files Browse the repository at this point in the history
Add CounterClockWise(CCW)
  • Loading branch information
kelvinlauKL authored Aug 29, 2020
2 parents cf518c0 + e48117c commit 73baaaa
Show file tree
Hide file tree
Showing 14 changed files with 264 additions and 0 deletions.
76 changes: 76 additions & 0 deletions CounterClockWise/CounterClockWise.playground/Contents.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
CounterClockWise(CCW) Algorithm
The user cross-multiplies corresponding coordinates to find the area encompassing the polygon,
and subtracts it from the surrounding polygon to find the area of the polygon within.
This code is based on the "Shoelace formula" by Carl Friedrich Gauss
https://en.wikipedia.org/wiki/Shoelace_formula
*/

import Foundation

// MARK : Point struct for defining 2-D coordinate(x,y)
public struct Point{
// Coordinate(x,y)
var x: Int
var y: Int

public init(x: Int ,y: Int){
self.x = x
self.y = y
}
}

// MARK : Function that determine the area of a simple polygon whose vertices are described
// by their Cartesian coordinates in the plane.
func ccw(points: [Point]) -> Int{
let polygon = points.count
var orientation = 0

// Take the first x-coordinate and multiply it by the second y-value,
// then take the second x-coordinate and multiply it by the third y-value,
// and repeat as many times until it is done for all wanted points.
for i in 0..<polygon{
orientation += (points[i%polygon].x*points[(i+1)%polygon].y
- points[(i+1)%polygon].x*points[i%polygon].y)
}

// If the points are labeled sequentially in the counterclockwise direction,
// then the sum of the above determinants is positive and the absolute value signs can be omitted
// if they are labeled in the clockwise direction, the sum of the determinants will be negative.
// This is because the formula can be viewed as a special case of Green's Theorem.
switch orientation {
case Int.min..<0:
return -1 // if operation < 0 : ClockWise
case 0:
return 0 // if operation == 0 : Parallel
default:
return 1 // if operation > 0 : CounterClockWise
}
}

// A few simple tests


// Triangle
var p1 = Point(x: 5, y: 8)
var p2 = Point(x: 9, y: 1)
var p3 = Point(x: 3, y: 6)

print(ccw(points: [p1,p2,p3])) // -1 means ClockWise

// Quadrilateral
var p4 = Point(x: 5, y: 8)
var p5 = Point(x: 2, y: 3)
var p6 = Point(x: 6, y: 1)
var p7 = Point(x: 9, y: 3)

print(ccw(points: [p4,p5,p6,p7])) // 1 means CounterClockWise

// Pentagon
var p8 = Point(x: 5, y: 11)
var p9 = Point(x: 3, y: 4)
var p10 = Point(x: 5, y: 6)
var p11 = Point(x: 9, y: 5)
var p12 = Point(x: 12, y: 8)

print(ccw(points: [p8,p9,p10,p11,p12])) // 1 means CounterClockWise
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='ios' executeOnSourceChanges='false'>
<timeline fileName='timeline.xctimeline'/>
</playground>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
50 changes: 50 additions & 0 deletions CounterClockWise/CounterClockWise.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
CounterClockWise(CCW) Algorithm
The user cross-multiplies corresponding coordinates to find the area encompassing the polygon,
and subtracts it from the surrounding polygon to find the area of the polygon within.
This code is based on the "Shoelace formula" by Carl Friedrich Gauss
https://en.wikipedia.org/wiki/Shoelace_formula
*/


import Foundation

// MARK : Point struct for defining 2-D coordinate(x,y)
public struct Point{
// Coordinate(x,y)
var x: Int
var y: Int

public init(x: Int ,y: Int){
self.x = x
self.y = y
}
}

// MARK : Function that determine the area of a simple polygon whose vertices are described
// by their Cartesian coordinates in the plane.
func ccw(points: [Point]) -> Int{
let polygon = points.count
var orientation = 0

// Take the first x-coordinate and multiply it by the second y-value,
// then take the second x-coordinate and multiply it by the third y-value,
// and repeat as many times until it is done for all wanted points.
for i in 0..<polygon{
orientation += (points[i%polygon].x*points[(i+1)%polygon].y
- points[(i+1)%polygon].x*points[i%polygon].y)
}

// If the points are labeled sequentially in the counterclockwise direction,
// then the sum of the above determinants is positive and the absolute value signs can be omitted
// if they are labeled in the clockwise direction, the sum of the determinants will be negative.
// This is because the formula can be viewed as a special case of Green's Theorem.
switch orientation {
case Int.min..<0:
return -1 // if operation < 0 : ClockWise
case 0:
return 0 // if operation == 0 : Parallel
default:
return 1 // if operation > 0 : CounterClockWise
}
}
Binary file added CounterClockWise/Images/Pentagon_img.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added CounterClockWise/Images/Quadrilateral_img.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added CounterClockWise/Images/Shoelace.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added CounterClockWise/Images/Triangle_img.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added CounterClockWise/Images/pentagon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added CounterClockWise/Images/quadrilateral.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added CounterClockWise/Images/triangle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 118 additions & 0 deletions CounterClockWise/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# CounterClockWise

Goal : Determine what direction to take when multiple points are given.

CounterClockWise(CCW) is based on [Shoelace formula](https://en.wikipedia.org/wiki/Shoelace_formula#Examples) by Carl Friedrich Gauss.



1. Take the first x-coordinate and multiply it by the second y-value, then take the second x-coordinate and multiply it by the third y-value, and repeat as many times until it is done for all wanted points.
2. If the points are labeled sequentially in the counterclockwise direction, then the sum of the above determinants is positive and the absolute value signs can be omitted if they are labeled in the clockwise direction, the sum of the determinants will be negative. This is because the formula can be viewed as a special case of [Green's theorem](https://en.wikipedia.org/wiki/Green%27s_theorem).

![Shoelace](./Images/Shoelace.png)



Here's an implementation in Swift that should be easy to understand:

```swift
func ccw(points: [Point]) -> Int{
let polygon = points.count
var orientation = 0

for i in 0..<polygon{
orientation += (points[i%polygon].x*points[(i+1)%polygon].y
- points[(i+1)%polygon].x*points[i%polygon].y)
}

switch orientation {
case Int.min..<0:
return -1 // if operation < 0 : ClockWise
case 0:
return 0 // if operation == 0 : Parallel
default:
return 1 // if operation > 0 : CounterClockWise
}
}
```

Put this code in a playground and test it like so:

```swift
var p1 = Point(x: 5, y: 8)
var p2 = Point(x: 9, y: 1)
var p3 = Point(x: 3, y: 6)

print(ccw(points: [p1,p2,p3])) // -1 means ClockWise
```

Here's how it works. When given an `[Photo]`, `ccw(points:)` calculates the direction of the given points according to the Shoelaces formula.



`orientation` is less than 0, the direction is clockwise.

`orientation` is equal to 0, the direction is parallel.

`orientation` is greater than 0, the direction is counterclockwise.



## An example

**In Triangle**

```swift
var p1 = Point(x: 5, y: 8)
var p2 = Point(x: 9, y: 1)
var p3 = Point(x: 3, y: 6)

print(ccw(points: [p1,p2,p3])) // -1 means ClockWise
```

![triangle](./Images/Triangle_img.jpg)

![triangleExpression](./Images/triangle.png)



**In Quadrilateral**

```swift
var p4 = Point(x: 5, y: 8)
var p5 = Point(x: 2, y: 3)
var p6 = Point(x: 6, y: 1)
var p7 = Point(x: 9, y: 3)

print(ccw(points: [p4,p5,p6,p7])) // 1 means CounterClockWise
```

![Quadrilateral](./Images/Quadrilateral_img.jpg)

![triangleExpression](./Images/quadrilateral.png)



**In Pentagon**

```swift
var p8 = Point(x: 5, y: 11)
var p9 = Point(x: 3, y: 4)
var p10 = Point(x: 5, y: 6)
var p11 = Point(x: 9, y: 5)
var p12 = Point(x: 12, y: 8)

print(ccw(points: [p8,p9,p10,p11,p12])) // 1 means CounterClockWise
```

![triangle](./Images/Pentagon_img.png)

![triangleExpression](./Images/pentagon.png)



You probably won't need to use the CCW in any real-world problems, but it's cool to play around with geometry algorithm. The formula was described by Meister (1724-1788) in 1769 and by Gauss in 1795. It can be verified by dividing the polygon into triangles, and can be considered to be a special case of Green's theorem.



*Written for Swift Algorithm Club by TaeJoong Yoon*
1 change: 1 addition & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ Bad sorting algorithms (don't use these!):
- [Karatsuba Multiplication](Karatsuba%20Multiplication/). Another take on elementary multiplication.
- [Haversine Distance](HaversineDistance/). Calculating the distance between 2 points from a sphere.
- [Strassen's Multiplication Matrix](Strassen%20Matrix%20Multiplication/). Efficient way to handle matrix multiplication.
- [CounterClockWise](/CounterClockWise/). Determining the area of a simple polygon.

### Machine learning

Expand Down

0 comments on commit 73baaaa

Please sign in to comment.