Skip to content

Commit d39caa8

Browse files
authored
Merge pull request #11 from MatanYadaev/more-spatial-functions
More spatial functions
2 parents 4a6851c + c788cf7 commit d39caa8

File tree

3 files changed

+145
-42
lines changed

3 files changed

+145
-42
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
}
4444
},
4545
"scripts": {
46-
"style-fix": "./vendor/bin/php-cs-fixer fix --allow-risky=yes",
46+
"php-cs-fixer": "./vendor/bin/php-cs-fixer fix --allow-risky=yes",
4747
"phpstan": "vendor/bin/phpstan analyse --memory-limit=2G",
4848
"test": "vendor/bin/phpunit --colors=always",
4949
"test-coverage": "vendor/bin/phpunit --coverage-html coverage"

src/Builders/SpatialBuilder.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,41 @@ public function whereTouches(string $column, Geometry | string $geometryOrColumn
8585
return $this->whereRaw("ST_TOUCHES(`{$column}`, {$geometryOrColumn})");
8686
}
8787

88+
public function whereIntersects(string $column, Geometry | string $geometryOrColumn): self
89+
{
90+
$geometryOrColumn = $this->toExpression($geometryOrColumn);
91+
92+
return $this->whereRaw("ST_INTERSECTS(`{$column}`, {$geometryOrColumn})");
93+
}
94+
95+
public function whereCrosses(string $column, Geometry | string $geometryOrColumn): self
96+
{
97+
$geometryOrColumn = $this->toExpression($geometryOrColumn);
98+
99+
return $this->whereRaw("ST_CROSSES(`{$column}`, {$geometryOrColumn})");
100+
}
101+
102+
public function whereDisjoint(string $column, Geometry | string $geometryOrColumn): self
103+
{
104+
$geometryOrColumn = $this->toExpression($geometryOrColumn);
105+
106+
return $this->whereRaw("ST_DISJOINT(`{$column}`, {$geometryOrColumn})");
107+
}
108+
109+
public function whereOverlaps(string $column, Geometry | string $geometryOrColumn): self
110+
{
111+
$geometryOrColumn = $this->toExpression($geometryOrColumn);
112+
113+
return $this->whereRaw("ST_OVERLAPS(`{$column}`, {$geometryOrColumn})");
114+
}
115+
116+
public function whereEquals(string $column, Geometry | string $geometryOrColumn): self
117+
{
118+
$geometryOrColumn = $this->toExpression($geometryOrColumn);
119+
120+
return $this->whereRaw("ST_EQUALS(`{$column}`, {$geometryOrColumn})");
121+
}
122+
88123
protected function toExpression(Geometry | string $geometryOrColumn): Expression
89124
{
90125
return $geometryOrColumn instanceof Geometry

tests/Builders/SpatialBuilderTest.php

Lines changed: 109 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
namespace MatanYadaev\EloquentSpatial\Tests\Builders;
44

55
use Illuminate\Foundation\Testing\DatabaseMigrations;
6-
use MatanYadaev\EloquentSpatial\Objects\MultiPolygon;
6+
use MatanYadaev\EloquentSpatial\Objects\LineString;
77
use MatanYadaev\EloquentSpatial\Objects\Point;
8+
use MatanYadaev\EloquentSpatial\Objects\Polygon;
89
use MatanYadaev\EloquentSpatial\Tests\TestCase;
910
use MatanYadaev\EloquentSpatial\Tests\TestModels\TestPlace;
1011

@@ -16,7 +17,7 @@ class SpatialBuilderTest extends TestCase
1617
public function it_calculates_distance_between_column_and_column(): void
1718
{
1819
TestPlace::factory()->create([
19-
'point' => new Point(23.1, 55.5),
20+
'point' => new Point(0, 0),
2021
]);
2122

2223
/** @var TestPlace $testPlaceWithDistance */
@@ -31,56 +32,55 @@ public function it_calculates_distance_between_column_and_column(): void
3132
public function it_calculates_distance_between_column_and_geometry(): void
3233
{
3334
TestPlace::factory()->create([
34-
'point' => new Point(23.1, 55.5),
35+
'point' => new Point(0, 0),
3536
]);
3637

3738
/** @var TestPlace $testPlaceWithDistance */
3839
$testPlaceWithDistance = TestPlace::query()
39-
->withDistance('point', new Point(23.1, 55.6))
40+
->withDistance('point', new Point(1, 1))
4041
->firstOrFail();
4142

42-
$this->assertEquals(0.1, $testPlaceWithDistance->distance);
43+
$this->assertEquals(1.4142135623731, $testPlaceWithDistance->distance);
4344
}
4445

4546
/** @test */
4647
public function it_calculates_distance_with_defined_name(): void
4748
{
4849
TestPlace::factory()->create([
49-
'point' => new Point(23.1, 55.5),
50+
'point' => new Point(0, 0),
5051
]);
5152

5253
/** @var TestPlace $testPlaceWithDistance */
5354
$testPlaceWithDistance = TestPlace::query()
54-
->withDistance('point', new Point(23.1, 55.6), 'distance_in_meters')
55+
->withDistance('point', new Point(1, 1), 'distance_in_meters')
5556
->firstOrFail();
5657

57-
$this->assertEquals(0.1, $testPlaceWithDistance->distance_in_meters);
58+
$this->assertEquals(1.4142135623731, $testPlaceWithDistance->distance_in_meters);
5859
}
5960

6061
/** @test */
6162
public function it_filters_by_distance(): void
6263
{
6364
TestPlace::factory()->create([
64-
'point' => new Point(23.1, 55.5),
65+
'point' => new Point(0, 0),
6566
]);
6667

67-
/** @var TestPlace $testPlaceWithinDistance */
6868
$testPlaceWithinDistance = TestPlace::query()
69-
->whereDistance('point', new Point(23.1, 55.6), '<', 1)
70-
->firstOrFail();
69+
->whereDistance('point', new Point(1, 1), '<', 10)
70+
->first();
7171

7272
$this->assertNotNull($testPlaceWithinDistance);
7373
}
7474

7575
/** @test */
7676
public function it_orders_by_distance(): void
7777
{
78-
$point = new Point(23.1, 55.51);
78+
$point = new Point(0, 0);
7979
$testPlace1 = TestPlace::factory()->create([
80-
'point' => new Point(23.1, 55.5),
80+
'point' => new Point(1, 1),
8181
]);
8282
$testPlace2 = TestPlace::factory()->create([
83-
'point' => new Point(0, 0),
83+
'point' => new Point(2, 2),
8484
]);
8585

8686
/** @var TestPlace $closestTestPlace */
@@ -100,7 +100,9 @@ public function it_orders_by_distance(): void
100100
/** @test */
101101
public function it_calculates_distance_sphere_column_and_column(): void
102102
{
103-
TestPlace::factory()->create();
103+
TestPlace::factory()->create([
104+
'point' => new Point(0, 0),
105+
]);
104106

105107
/** @var TestPlace $testPlaceWithDistance */
106108
$testPlaceWithDistance = TestPlace::query()
@@ -114,56 +116,55 @@ public function it_calculates_distance_sphere_column_and_column(): void
114116
public function it_calculates_distance_sphere_column_and_geometry(): void
115117
{
116118
TestPlace::factory()->create([
117-
'point' => new Point(23.1, 55.5),
119+
'point' => new Point(0, 0),
118120
]);
119121

120122
/** @var TestPlace $testPlaceWithDistance */
121123
$testPlaceWithDistance = TestPlace::query()
122-
->withDistanceSphere('point', new Point(23.1, 55.51))
124+
->withDistanceSphere('point', new Point(1, 1))
123125
->firstOrFail();
124126

125-
$this->assertEquals(1022.7925914593363, $testPlaceWithDistance->distance);
127+
$this->assertEquals(157249.0357231545, $testPlaceWithDistance->distance);
126128
}
127129

128130
/** @test */
129131
public function it_calculates_distance_sphere_with_defined_name(): void
130132
{
131133
TestPlace::factory()->create([
132-
'point' => new Point(23.1, 55.5),
134+
'point' => new Point(0, 0),
133135
]);
134136

135137
/** @var TestPlace $testPlaceWithDistance */
136138
$testPlaceWithDistance = TestPlace::query()
137-
->withDistanceSphere('point', new Point(23.1, 55.51), 'distance_in_meters')
139+
->withDistanceSphere('point', new Point(1, 1), 'distance_in_meters')
138140
->firstOrFail();
139141

140-
$this->assertEquals(1022.7925914593363, $testPlaceWithDistance->distance_in_meters);
142+
$this->assertEquals(157249.0357231545, $testPlaceWithDistance->distance_in_meters);
141143
}
142144

143145
/** @test */
144146
public function it_filters_distance_sphere(): void
145147
{
146148
TestPlace::factory()->create([
147-
'point' => new Point(23.1, 55.5),
149+
'point' => new Point(0, 0),
148150
]);
149151

150-
/** @var TestPlace $testPlaceWithinDistanceSphere */
151152
$testPlaceWithinDistanceSphere = TestPlace::query()
152-
->whereDistanceSphere('point', new Point(23.1, 55.51), '<', 2000)
153-
->firstOrFail();
153+
->whereDistanceSphere('point', new Point(1, 1), '<', 200000)
154+
->first();
154155

155156
$this->assertNotNull($testPlaceWithinDistanceSphere);
156157
}
157158

158159
/** @test */
159160
public function it_orders_by_distance_sphere(): void
160161
{
161-
$point = new Point(23.1, 55.51);
162+
$point = new Point(0, 0);
162163
$testPlace1 = TestPlace::factory()->create([
163-
'point' => new Point(23.1, 55.5),
164+
'point' => new Point(1, 1),
164165
]);
165166
$testPlace2 = TestPlace::factory()->create([
166-
'point' => new Point(0, 0),
167+
'point' => new Point(2, 2),
167168
]);
168169

169170
/** @var TestPlace $closestTestPlace */
@@ -184,13 +185,12 @@ public function it_orders_by_distance_sphere(): void
184185
public function it_filters_by_within(): void
185186
{
186187
TestPlace::factory()->create([
187-
'point' => new Point(23.1, 55.5),
188+
'point' => new Point(0, 0),
188189
]);
189190

190-
/** @var TestPlace $testPlace */
191191
$testPlace = TestPlace::query()
192-
->whereWithin('point', MultiPolygon::fromJson('{"type":"MultiPolygon","coordinates":[[[[55.5,23.0],[55.4,23.2],[55.8,23.3],[55.5,23.0]]]]}'))
193-
->firstOrFail();
192+
->whereWithin('point', Polygon::fromJson('{"type":"Polygon","coordinates":[[[-1,-1],[1,-1],[1,1],[-1,1],[-1,-1]]]}'))
193+
->first();
194194

195195
$this->assertNotNull($testPlace);
196196
}
@@ -199,13 +199,12 @@ public function it_filters_by_within(): void
199199
public function it_filters_by_contains(): void
200200
{
201201
TestPlace::factory()->create([
202-
'multi_polygon' => MultiPolygon::fromJson('{"type":"MultiPolygon","coordinates":[[[[55.5,23.0],[55.4,23.2],[55.8,23.3],[55.5,23.0]]]]}'),
202+
'polygon' => Polygon::fromJson('{"type":"Polygon","coordinates":[[[-1,-1],[1,-1],[1,1],[-1,1],[-1,-1]]]}'),
203203
]);
204204

205-
/** @var TestPlace $testPlace */
206205
$testPlace = TestPlace::query()
207-
->whereContains('multi_polygon', new Point(23.1, 55.5))
208-
->firstOrFail();
206+
->whereContains('polygon', new Point(0, 0))
207+
->first();
209208

210209
$this->assertNotNull($testPlace);
211210
}
@@ -214,13 +213,82 @@ public function it_filters_by_contains(): void
214213
public function it_filters_by_touches(): void
215214
{
216215
TestPlace::factory()->create([
217-
'point' => new Point(23.1, 55.5),
216+
'point' => new Point(0, 0),
217+
]);
218+
219+
$testPlace = TestPlace::query()
220+
->whereTouches('point', Polygon::fromJson('{"type":"Polygon","coordinates":[[[-1,-1],[0,-1],[0,0],[-1,0],[-1,-1]]]}'))
221+
->first();
222+
223+
$this->assertNotNull($testPlace);
224+
}
225+
226+
/** @test */
227+
public function it_filters_by_intersects(): void
228+
{
229+
TestPlace::factory()->create([
230+
'point' => new Point(0, 0),
218231
]);
219232

220-
/** @var TestPlace $testPlace */
221233
$testPlace = TestPlace::query()
222-
->whereTouches('point', MultiPolygon::fromJson('{"type":"MultiPolygon","coordinates":[[[[55.5,23.1],[55.6,23.2],[55.7,23.3],[55.5,23.1]]]]}'))
223-
->firstOrFail();
234+
->whereIntersects('point', Polygon::fromJson('{"type":"Polygon","coordinates":[[[-1,-1],[1,-1],[1,1],[-1,1],[-1,-1]]]}'))
235+
->first();
236+
237+
$this->assertNotNull($testPlace);
238+
}
239+
240+
/** @test */
241+
public function it_filters_by_crosses(): void
242+
{
243+
TestPlace::factory()->create([
244+
'line_string' => LineString::fromJson('{"type":"LineString","coordinates":[[0,0],[2,0]]}'),
245+
]);
246+
247+
$testPlace = TestPlace::query()
248+
->whereCrosses('line_string', Polygon::fromJson('{"type":"Polygon","coordinates":[[[-1,-1],[1,-1],[1,1],[-1,1],[-1,-1]]]}'))
249+
->first();
250+
251+
$this->assertNotNull($testPlace);
252+
}
253+
254+
/** @test */
255+
public function it_filters_by_disjoint(): void
256+
{
257+
TestPlace::factory()->create([
258+
'point' => new Point(0, 0),
259+
]);
260+
261+
$testPlace = TestPlace::query()
262+
->whereDisjoint('point', Polygon::fromJson('{"type":"Polygon","coordinates":[[[-1,-1],[-0.5,-1],[-0.5,-0.5],[-1,-0.5],[-1,-1]]]}'))
263+
->first();
264+
265+
$this->assertNotNull($testPlace);
266+
}
267+
268+
/** @test */
269+
public function it_filters_by_overlaps(): void
270+
{
271+
TestPlace::factory()->create([
272+
'polygon' => Polygon::fromJson('{"type":"Polygon","coordinates":[[[-1,-1],[-0.5,-1],[-0.5,-0.5],[-1,-0.5],[-1,-1]]]}'),
273+
]);
274+
275+
$testPlace = TestPlace::query()
276+
->whereOverlaps('polygon', Polygon::fromJson('{"type":"Polygon","coordinates":[[[-0.75,-0.75],[1,-1],[1,1],[-1,1],[-0.75,-0.75]]]}'))
277+
->first();
278+
279+
$this->assertNotNull($testPlace);
280+
}
281+
282+
/** @test */
283+
public function it_filters_by_equals(): void
284+
{
285+
TestPlace::factory()->create([
286+
'point' => new Point(0, 0),
287+
]);
288+
289+
$testPlace = TestPlace::query()
290+
->whereEquals('point', new Point(0, 0))
291+
->first();
224292

225293
$this->assertNotNull($testPlace);
226294
}

0 commit comments

Comments
 (0)