Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update LineContainer.mdx #4518

Closed
wants to merge 76 commits into from
Closed
Changes from 7 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
898abf4
Update LineContainer.mdx
Jun 12, 2024
4e6154b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 12, 2024
955b0b4
Update LineContainer.mdx
Jun 12, 2024
cbc350c
Update LineContainer.mdx
Jun 12, 2024
21b0fcc
Update LineContainer.mdx
Jun 12, 2024
698f185
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 12, 2024
e32dc0e
Update LineContainer.mdx
Jun 12, 2024
81c8566
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 12, 2024
6271221
Update LineContainer.mdx
Jun 12, 2024
f476c71
Update LineContainer.mdx
Jun 13, 2024
32c0b0f
Update LineContainer.mdx
Jun 13, 2024
f75dd40
Update LineContainer.mdx
Jun 14, 2024
10f604d
Update LineContainer.mdx
Jun 14, 2024
e494756
Update LineContainer.mdx
Jun 14, 2024
09d7586
Update LineContainer.mdx
SansPapyrus683 Jun 14, 2024
d0d079e
Update LineContainer.mdx
Jun 16, 2024
8a91afb
Update LineContainer.mdx
Jun 16, 2024
5002f38
Update LineContainer.mdx
SansPapyrus683 Jun 16, 2024
7b63718
Add files via upload
Jun 19, 2024
fdbceb7
Update LineContainer.mdx
Jun 19, 2024
34a4127
Merge branch 'cpinitiative:master' into master
Jun 20, 2024
61cad07
Merge branch 'cpinitiative:master' into master
Jun 24, 2024
7781a90
Add files via upload
Jun 24, 2024
c02317d
Merge pull request #1 from TheScarletPhoenix/TheScarletPhoenix-patch-2
Jun 24, 2024
e36fa9e
Merge branch 'cpinitiative:master' into patch-2
Jun 24, 2024
5b72bf5
Add files via upload
Jun 24, 2024
7397124
Add files via upload
Jun 24, 2024
ca620c3
Update LineContainer.mdx
Jun 24, 2024
613f86f
Update LineContainer.mdx
Jun 25, 2024
2372e14
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 25, 2024
f4a66f6
Update LineContainer.mdx
Jun 25, 2024
77da2bb
Update LineContainer.mdx
Jun 25, 2024
49e92a6
Update LineContainer.mdx
Jun 25, 2024
fad697d
Update LineContainer.mdx
Jun 25, 2024
75f1d5e
Update LineContainer.mdx
Jun 25, 2024
d7db6b9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 25, 2024
a5fe95c
Update LineContainer.mdx
SansPapyrus683 Jun 25, 2024
2d12a6a
Update LineContainer.mdx
Jul 1, 2024
d7d4382
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 1, 2024
1751c29
Update LineContainer.mdx
Jul 1, 2024
7fa0188
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 1, 2024
4a383e0
Update LineContainer.problems.json
Jul 3, 2024
7b1a9cb
Update LineContainer.mdx
SansPapyrus683 Jul 3, 2024
b2a2227
Update LineContainer.mdx
Jul 3, 2024
ce4cd79
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 3, 2024
94592e7
Merge branch 'cpinitiative:master' into master
Jul 3, 2024
7754556
Merge pull request #2 from TheScarletPhoenix/patch-4
Jul 3, 2024
4f578b2
Merge branch 'master' into patch-2
Jul 3, 2024
fdac120
Merge branch 'cpinitiative:master' into TheScarletPhoenix-patch-2
Jul 3, 2024
809f63c
Update LineContainer.problems.json
Jul 6, 2024
8854822
Merge pull request #4 from TheScarletPhoenix/TheScarletPhoenix-patch-2
Jul 6, 2024
e5e4a71
Update LineContainer.mdx
Jul 6, 2024
1dc5058
Update LineContainer.problems.json
Jul 6, 2024
f5b3ef2
Update LineContainer.mdx
Jul 7, 2024
e651a48
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 7, 2024
f8135cf
Merge branch 'cpinitiative:master' into master
Jul 10, 2024
f6150ca
Merge branch 'cpinitiative:master' into patch-2
Jul 10, 2024
6e656bb
Update LineContainer.mdx
Jul 10, 2024
4cd8cc0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 10, 2024
cf8fe33
minor rewording for clarity
ryanchou-dev Jul 12, 2024
80a287f
Update content/6_Advanced/LineContainer.mdx
Jul 12, 2024
e64e976
Add files via upload
Jul 12, 2024
20afdad
Merge pull request #5 from TheScarletPhoenix/master
Jul 12, 2024
602b2da
Update LineContainer.mdx
Jul 12, 2024
aebdea0
Delete halfplane1.png
Jul 12, 2024
466be1c
Delete halfplane2.png
Jul 12, 2024
eae227a
Delete halfplane3.png
Jul 12, 2024
9cf4675
Delete halfplane4.png
Jul 12, 2024
e9380d7
Delete content/6_Advanced/halfplane1.png
Jul 12, 2024
643d0cb
Delete content/6_Advanced/halfplane2.png
Jul 12, 2024
11ccf67
Delete content/6_Advanced/halfplane3.png
Jul 12, 2024
1a21466
Delete content/6_Advanced/halfplane4.png
Jul 12, 2024
88ccd61
Merge pull request #6 from TheScarletPhoenix/master
Jul 12, 2024
b9e52ee
Update LineContainer.mdx
Jul 12, 2024
3360a85
latex fix
ryanchou-dev Jul 15, 2024
c27a395
Merge branch 'cpinitiative:master' into patch-2
Jul 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 185 additions & 1 deletion content/6_Advanced/LineContainer.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,191 @@ frequency: 1
</Resource>
</Resources>

<IncompleteSection>Example problem + implementation?</IncompleteSection>
A half-plane can be defined as a planar region that consists of all points on one side of an infinite straight line, and none on the other side. We can apply computational geometry here, as an intersection can be represented as a convex polygon, where every point inside it is also inside all half-planes. If we can construct this polygon, we can retrieve the intersections.

### Example Problem

This conversation was marked as resolved.
Show resolved Hide resolved
We can state that $N$ is the number of half-planes in our set. We represent lines and half-planes by a point and a vector, or in other terms, any point that lies on said line and the direction vector of the line. Each half-plane allows the region to the left of its direction vector. We can define the angle of a given half-plane as the polar coordinates of its direction vector. We can also state that a resulting intersection is always either bounded or empty, in cases where this doesn't hold, we can add 4 more half-planes which increase the size of the bounding box. For now, we shall also assume that parallel half-planes will not be present. To get a more visual representation of this, see the image below:
This conversation was marked as resolved.
Show resolved Hide resolved

<iframe
src="https://iq.opengenus.org/content/images/2022/02/halfplane.PNG"
width="365px"
height="293px"
frameborder="0"
/>

This half-plane has an equation $y = 2x -2$ and can be represented as $P = (1,0)$ with the direction vector $PQ$ as $(1,2)$.
I will now describe various ways of solving this problem, explaining algorithms in increasing efficiency:
This conversation was marked as resolved.
Show resolved Hide resolved

#### Brute Force
This problem can be solved using brute force by computing the intersection point of the lines and all pairs of half-planes and then, for every point, checking if it is inside all of the other half-planes. There are $\mathcal{O}(N^2)$ intersection points that need to be checked against $\mathcal{O}(N)$ half-planes, resulting in the final complexity being $\mathcal{O}(N^3)$. We can then create a convex hull on the set of intersection points which were also included in the half-planes. The vertices of this convex hull are the intersection points of the half-plane lines, as they, of course, would mean they are points in every half-plane since it is points of intersection. This approach works to gain a solution; however, it's impractical to apply in a real-world scenario due to its extremely poor efficiency.

#### Incremental
A slightly faster approach to this problem would be to incrementally construct the intersection of the half-planes one by one. We cut the convex polygon by a line $N$ amount of times, removing the redundant planes each time.

If we represent the convex polygon as a set of line segments, we can cut it with a half-plane by finding the points of intersection of the segments with the half-plane line, replacing all the line segments in the middle with a new segment corresponding to a half-plane. This can be implemented in $\mathcal{O}(N)$ time, and decrease the bounding box with each half-plane, resulting in an $\mathcal{O}(N^2)$ complexity.

This is much better than our initial approach. However, it's still relatively inefficient as we still have to loop over $\mathcal{O}(N)$ half-planes with every iteration. We will make some alterations to this algorithm in the next approach for a more reasonable solution.

#### Sort and Increment Algorithm
We can use some properties of the output of the previous algorithm to optimize it. We know that the resulting region of the intersection of half-planes is convex, therefore it will consist of some segments of half-planes in order of their angles. In other words, if we incrementally intersect the half-planes in the order of their angles, storing them in a double-ended queue, we will only need to remove half-planes from the front and the back of the queue.

Let's say that the half-plane angles are sorted from $-π$ to $π$ and that we are about to start the $k$-th step of the algorithm. We can say that we have already constructed the intersection of the half-planes up to $k-1$. Because the half-planes are sorted by angle, we can be sure that $k$ will form a convex turn with the $k-1$ half-plane. From this, we can say:
* Some of the half-planes that are located at the back of the intersection may become redundant, in which case we shall pop from the queue from the back of the double-ended queue.
* Some of the half-planes that are located at the front of the intersection may become redundant, in which case we shall pop from the queue from the back of the double-ended queue.
* The intersection may become empty from this, in which case we shall simply terminate the algorithm and return the intersection as empty.

In this case, redundant means that it doesn't change the intersection, or the half-plane could be removed and the intersection wouldn't change.

To visualize this, we shall let $H = A,B,C,D,E$. This is the set of half-planes that are currently present in the intersection. For the points, we can define them as $P = p,q,r,s$ which are intersection points of adjacent half-planes from $H$. This could be represented as such below:

<iframe
src="https://iq.opengenus.org/content/images/2022/02/halfplane2.PNG"
width="651px"
height="491px"
frameborder="0"
/>

Say we want to intersect it with a new half-plane $F$; it may make some existing half-planes redundant.

<iframe
src="https://iq.opengenus.org/content/images/2022/02/halfplane3.PNG"
width="735px"
height="492px"
frameborder="0"
/>

We can see $F$ here represented in orange. It makes the half-planes $A$ and $E$ redundant. Therefore, we can remove them from the front and back of the queue and add $F$ at the end. Then, we obtain a new intersection between $H = B,C,D,F$ with $P = q,r,t,u$. This can be shown below:

<iframe
src="https://iq.opengenus.org/content/images/2022/02/halfplane4.PNG"
width="707px"
height="416px"
frameborder="0"
/>

This is the main principle of the algorithm. However, there are a few special cases we should cover. In the case of parallel half-planes, there are 2 possible scenarios, either two that are parallel with the same direction or different directions. We should approach parallel lines with different directions the same as if we have to increase the size of the bounding box, since there will have to be at least one of the half-planes within the bounding box in between the two since they are sorted by angle. This means that the only case we have to deal with is where there are two half-planes with the same angle. To do this is straightforward: simply keep the leftmost half-plane and erase the rest since the others will eventually become redundant anyway.

So, as an overview of the algorithm:
* Sort the set of half-planes by angle; it takes $\mathcal{O}(NlogN)$ time.
This conversation was marked as resolved.
Show resolved Hide resolved
* Iterate over the set. For each, perform incrementation and pop either from the front or back of the double-ended queue as necessary; it takes linear time since every half-plane can only be added or removed once.
* Once this has been completed, the convex polygon that results from the intersection can be obtained by computing the intersection points of adjacent half-planes in the double-ended queue. It will take linear time. This results in our final complexity as $\{O}(NlogN)$. In a special case where the half-planes are pre-sorted, this algorithm could be completed in $\{O}(N)$. However, for the majority of cases, we will be looking at $\{O}(NlogN)$, most of which is coming from the sorting by angle.

#### Implementation

```cpp
#include <climits>
#include <deque>
#include <vector>
#include <algorithm>

const long double eps = 1e-9;
const int inf = INT32_MAX;

This conversation was marked as resolved.
Show resolved Hide resolved
struct Point {
long double x, y;
explicit Point(long double x = 0, long double y = 0) : x(x), y(y) {}
This conversation was marked as resolved.
Show resolved Hide resolved

friend Point operator + (const Point& p, const Point& q) {
return Point(p.x + q.x, p.y + q.y);
}

friend Point operator - (const Point& p, const Point& q) {
return Point(p.x - q.x, p.y - q.y);
}

friend Point operator * (const Point& p, const long double& k) {
return Point(p.x * k, p.y * k);
}

friend long double cross(const Point& p, const Point& q) {
return p.x * q.y - p.y * q.x;
}
};

struct Halfplane {
Point p, pq;
long double angle;

Halfplane() {}
Halfplane(const Point& a, const Point& b) : p(a), pq(b - a) {
angle = atan2l(pq.y, pq.x);
}

bool out(const Point& r) {
return cross(pq, r - p) < -eps;
}

bool operator < (const Halfplane& e) const {
if (fabsl(angle - e.angle) < eps) return cross(pq, e.p - p) < 0;
return angle < e.angle;
}

bool operator == (const Halfplane& e) const {
return fabsl(angle - e.angle) < eps;
}

friend Point inter(const Halfplane& s, const Halfplane& t) {
long double alpha = cross((t.p - s.p), t.pq) / cross(s.pq, t.pq);
return s.p + (s.pq * alpha);
}
};

// Actual algorithm: Computes the intersection of a set of halfplanes
This conversation was marked as resolved.
Show resolved Hide resolved
std::vector<Point> halfplane_intersect(std::vector<Halfplane>& halfplanes) {
Point box[4] = {
Point(inf, inf),
Point(-inf, inf),
Point(-inf, -inf),
Point(inf, -inf)
};

// Add bounding box halfplanes
for(int i = 0; i < 4; i++) {
Halfplane aux(box[i], box[(i + 1) % 4]);
halfplanes.push_back(aux);
}

std::sort(halfplanes.begin(), halfplanes.end());
halfplanes.erase(std::unique(halfplanes.begin(), halfplanes.end()), halfplanes.end());

std::deque<Halfplane> active_halfplanes;
int len = 0;
for(int i = 0; i < int(halfplanes.size()); i++) {
while (len > 1 && halfplanes[i].out(inter(active_halfplanes[len - 1], active_halfplanes[len - 2]))) {
active_halfplanes.pop_back();
len--;
}

while (len > 1 && halfplanes[i].out(inter(active_halfplanes[0], active_halfplanes[1]))) {
active_halfplanes.pop_front();
len--;
}

active_halfplanes.push_back(halfplanes[i]);
len++;
}

while (len > 2 && halfplanes[0].out(inter(active_halfplanes[len - 1], active_halfplanes[len - 2]))) {
active_halfplanes.pop_back();
len--;
}

while (len > 2 && halfplanes[len - 1].out(inter(active_halfplanes[0], active_halfplanes[1]))) {
active_halfplanes.pop_front();
len--;
}

if (len < 3) return std::vector<Point>();

std::vector<Point> intersection_points(len);
for(int i = 0; i < len - 1; i++) {
intersection_points[i] = inter(active_halfplanes[i], active_halfplanes[i + 1]);
}
intersection_points.back() = inter(active_halfplanes[len - 1], active_halfplanes[0]);
return intersection_points;
}
```

<Problems problems="half" />

Expand Down
Loading