Skip to content

Commit 3cad42e

Browse files
authored
Merge pull request #4308 from brebenelmihnea/Lattice-Points
Geometry Primitives - Polygon Lattice Points
2 parents b11183f + 49b2af7 commit 3cad42e

File tree

2 files changed

+90
-4
lines changed

2 files changed

+90
-4
lines changed

content/5_Plat/Geo_Pri.mdx

+76-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ You should know operations such as the cross product and dot product.
1010

1111
## Standard Problems
1212

13+
### Location of a point
1314
<FocusProblem problem="pointlocationtest" />
1415

1516
To check the $P$ location towards the $P_1$ $P_2$ line we use following formula: $(P.y - P_1.y) * (P_2.x - P_1.x) - (P.x - P_1.x) * (P_2.y - P_1.y)$
@@ -30,7 +31,7 @@ This formula doesn't only tell us whether the points are collinear, but where th
3031

3132
</Spoiler>
3233

33-
### Implementation
34+
#### Implementation
3435

3536
<LanguageSection>
3637
<CPPSection>
@@ -78,12 +79,13 @@ int main() {
7879
</CPPSection>
7980
</LanguageSection>
8081
82+
### Segment intersection
8183
<FocusProblem problem="line" />
8284
8385
We can quickly dismiss the segment intersection by treating them as rectangles having the segments as diagonals which can be easily done.
8486
If it turns out the rectangles intersect then we just check if the segment's ends are on different sides of the other segment.
8587
86-
### Implementation
88+
#### Implementation
8789
8890
<LanguageSection>
8991
<CPPSection>
@@ -161,11 +163,12 @@ int main() {
161163
</CPPSection>
162164
</LanguageSection>
163165
166+
### Polygon area
164167
<FocusProblem problem="polygon" />
165168
166169
The following algorithm uses the [Shoelace formula](https://en.wikipedia.org/wiki/Shoelace_formula).
167170
168-
### Implementation
171+
#### Implementation
169172
170173
<LanguageSection>
171174
<CPPSection>
@@ -205,6 +208,8 @@ int main() {
205208
</CPPSection>
206209
</LanguageSection>
207210

211+
### Point's location relative to polygon
212+
208213
<FocusProblem problem="polygon2" />
209214

210215
We can cast a ray from the point $P$ going in any fixed direction (people usually go to the right).
@@ -213,7 +218,7 @@ If the point is on the inside of the polygon then it will intersect the edge an
213218

214219
This approach is called [ray casting](https://en.wikipedia.org/wiki/Point_in_polygon).
215220

216-
### Implementation
221+
#### Implementation
217222

218223
<LanguageSection>
219224
<CPPSection>
@@ -312,6 +317,73 @@ int main() {
312317
</CPPSection>
313318
</LanguageSection>
314319

320+
### Lattice points in polygon
321+
<FocusProblem problem="latticepoints" />
322+
323+
Let's first focus on the lattice points on the polygon's boundary. We'll process each edge individually. The number of intersections of a line with lattice points is the greatest
324+
common divisor of $P_1.x - P_2.x$ and $P_1.y - P_2.y$.
325+
326+
<Spoiler title="Demonstration">
327+
Using the linear function it can be proven. Denote the segment ends with ($x_1$,$y_1$) and ($x_2$, $y_2$). The function has the following
328+
form: &f(x) = ax + b&. The slope of $f(x)$, in our case $a$, is $\frac{y_1-y_2}{x_1-x_2}$, so $f(x)$ becomes $f(x) = \frac{y_1-y_2}{x_1-x_2} * x + b$.
329+
330+
This means that every points along the line has the following form: $(x, f(x))$ which has become $(x, \frac{y_1-y_2}{x_1-x_2} * x + b)$. Number $x$ can
331+
be any integer, but &f(x)& no. In order to be lattice point &f(x)& has to be an integer, by eliminating the fraction resulting in $x$ divisible by $x_1 - x_2$.
332+
333+
</Spoiler>
334+
335+
Now that we know the number of lattice points on the boundary we can find the number of lattice points inside the polygon using [Pick's theorem](https://en.wikipedia.org/wiki/Pick%27s_theorem).
336+
Let's denote $A$ polygon's area, $i$ the number of integer points inside and $b$ the number of integer points on its boundary. Then, according to Pick's theorem, we have the following
337+
equation: $A = i + b/2 - 1$. Changing the order a little bit to get $i = A - b/2 + 1$. We've found $b$ and, as you've probably already solved [Polygon Area](https://cses.fi/problemset/task/2191) from above,
338+
$A$ can be computed using cross-product.
339+
340+
#### Implementation
341+
342+
<LanguageSection>
343+
<CPPSection>
344+
```cpp
345+
#include <bits/stdc++.h>
346+
347+
using namespace std;
348+
349+
// BeginCodeSnip{Point Class}
350+
struct Point {
351+
int x, y;
352+
Point(int a = 0, int b = 0) : x(a), y(b) {}
353+
Point operator-(const Point &other) { return {x - other.x, y - other.y}; }
354+
friend istream &operator>>(istream &in, Point &p) {
355+
int x, y;
356+
in >> p.x >> p.y;
357+
return in;
358+
}
359+
};
360+
// EndCodeSnip
361+
362+
int main() {
363+
int n;
364+
cin >> n;
365+
vector<Point> points(n);
366+
for (Point &point : points) { cin >> point; }
367+
points.push_back(points[0]);
368+
long long area = 0;
369+
for (int i = 0; i < n; i++) {
370+
area += (1LL * points[i].x * points[i + 1].y -
371+
1LL * points[i].y * points[i + 1].x);
372+
}
373+
area = abs(area);
374+
long long boundary_points = 0;
375+
for (int i = 0; i < n; i++) {
376+
Point diff = points[i + 1] - points[i];
377+
int g = gcd(abs(diff.x), abs(diff.y));
378+
boundary_points += g;
379+
}
380+
long long interior_points = (area - boundary_points) / 2 + 1;
381+
cout << interior_points << ' ' << boundary_points;
382+
}
383+
```
384+
</CPPSection>
385+
</LanguageSection>
386+
315387
<Problems problems="standard" />
316388

317389
## Resources

content/5_Plat/Geo_Pri.problems.json

+14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
{
22
"MODULE_ID": "geo-pri",
3+
"latticepoints": [
4+
{
5+
"uniqueId": "lattice",
6+
"name": "Polygon Lattice Points",
7+
"url": "https://cses.fi/problemset/task/2193",
8+
"source": "CSES",
9+
"difficulty": "Medium",
10+
"isStarred": false,
11+
"tags": ["Geometry"],
12+
"solutionMetadata": {
13+
"kind": "none"
14+
}
15+
}
16+
],
317
"pointlocationtest": [
418
{
519
"uniqueId": "point",

0 commit comments

Comments
 (0)