smindel / silverstripe-gis Goto Github PK
View Code? Open in Web Editor NEWAdds support for geographic types.
License: BSD 3-Clause "New" or "Revised" License
Adds support for geographic types.
License: BSD 3-Clause "New" or "Revised" License
The co-ordinate "summary" text shown beneath the leaflet map in the backend, gets really long, really easily.
Suggest this is added as a separate FormField
subclass, so developers can target it for removal or modification. The default could be a ToggleCompositeField
to make it easier to see all the info in it, rather than having to focus in this area with a mouse cursor, and dragging to its full-length.
Hello @smindel ,
Many thanks for making this module available. It has been very useful.
Wonder if there is an error in the sample codes in the docs where it says:
`$city = City::get()->filter('Name', 'Wellington')->first();
$distance = 100000; // metres
$degrees = $distance / 111195;
$cities = Cities::get()->filter('Location:ST_Contains', [$city->Location, $degrees]);`
Shouldn't it be
$cities = Cities::get()->filter('Location:ST_Distance', [$city->Location, $degrees]);
Also, the value of $city->Location is a string in this format
POINT(lat lng),4332
Am I correct?
Regards,
Ben
The README documents several useful DataList
producing methods on the GIS
class, but each of which have no docs to help devs understand what they do (and why they're so named). For example, what does "ewkt" mean / stand for?
The rendering of tiles can be customised. Things like changing colors, adding text or background patterns can be achieved using GD and Imagick.
If I follow the same, minmal instructions from the README, but use Page
instead of DataObject
, I don't see a scaffolded leaflet map in the admin UI, when creating a new Page
. If I create a new DataObject
, I see a map, but it has no basemap - the latter problem could be donw to config. I'll play around a little more.
PHP 7.1 / Ubuntu 16.04 / Framework & CMS 4.3 / silverstripe/admin 1.3
EDIT:
class PlanPage extends Page
{
private static $db = [
'Location' => 'Geometry',
];
public function getCMSFields()
{
...
$fields->dataFieldByName('Location'); // null
...
}
...
}
EDIT: basemap appears after saving - see #4
Tenth of thousandth points can easily be served with 128MB RAM. But when we hit millions, the service errors out because of insufficient memory. By not buffering, memory issues can be avoided altogether.
A minor issue: Until you save a DataObject
record, the map appears to be "broken" in the admin backend - it won't show the MapField
with a base-map. Not sure right now how this would be fixed.
It would be great if the $geojsonservice
static accepted strings that mapped to methods, just like $summary_fields
works.
Then we can do stuff like this, where the map's JS has access to layer.feature.properties.foo
for each model:
private static $geojsonservice = [
'geometry_field' => 'Location',
'searchable_fields' => [
'Address',
'Location',
],
'property_map' => [
'ID' => 'id',
'Type' => 'type',
'Foo' => 'foo',
],
];
public function getFoo()
{
return 'Bar';
}
hi,
I've been trying to get continuous integration working on this project with GitHub actions, as I am learning it and this module looked like a good challenge.
I've come across an issue with extracting the SRID from an image, I've tracked it down to the command created here:
https://github.com/smindel/silverstripe-gis/blob/master/src/Model/Raster.php#L38
The output parsed by https://github.com/smindel/silverstripe-gis/blob/master/src/Model/Raster.php#L45 is a failure with newer versions of gdalsrsinfo
With added debug, I see the following:
T2: command=
gdalsrsinfo -o wkt /var/www/tests/php/RasterTest.tif
T3:GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433],AUTHORITY["EPSG","4326"]]
T4: MATCHES: Array
(
[0] => ,AUTHORITY["EPSG","4326"]]
[1] => 4326
)
I think this is the latest LTS, should double check. However the output changes to a multi line structure
T2: command=
gdalsrsinfo -o wkt /home/runner/work/silverstripe-gis/silverstripe-gis/tests/php/RasterTest.tif
T3:
GEOGCRS["WGS 84",
DATUM["World Geodetic System 1984",
ELLIPSOID["WGS 84",6378137,298.257223563,
LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433]],
CS[ellipsoidal,2],
AXIS["geodetic latitude (Lat)",north,
ORDER[1],
ANGLEUNIT["degree",0.0174532925199433]],
AXIS["geodetic longitude (Lon)",east,
ORDER[2],
ANGLEUNIT["degree",0.0174532925199433]],
ID["EPSG",4326]]
T5: No match!!
This fails the regular expression match.
I rebuilt my local docker php command line to bullseye, and then added --single-line
flag to the gdalsrsinfo command, this is incompatible with version 2 when I tested on Buster above. An error was returned instead.
One line is returned, but different info, and again the regular expression match fails:
T2: command=
gdalsrsinfo --single-line -o wkt /var/www/tests/php/RasterTest.tif
T3:GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]]
T5: No match!!
I am not sure what the best solution is here, but I guess running likes of gdalsrsinfo --version
and if it is > 2, add the --single-line flag. After that, the regular expression match would need changed to work in all cases
Kind regards
Gordon
When debugging the module, it's hard to read lengthy one-liners, let alone lengthy one-liners without braces.
Please consider joining the revolution and running phpcs-fixer or similar over the module codebase.
At the moment in PostgreSQLSchemaManager
:
if (!class_exists(PostgreSQLSchemaManager::class)) {
return;
}
Consider throwing an Exception
"Postgres package not installed"
If I add a default_location
in app.yml, that differs from the one declared in MapField
, when I publish a Page
object in the admin area, instead of replacing the MapField
default, the yml-declared default is appended to it.
app.yml
Smindel\GIS\Forms\MapField:
default_location:
# Lon
- '174.7'
# Lat
- '-41.2'
DBGeography
fieldTextField
so you can see at-a-glance what the value is interpreted as (The column in Postgres is a non Human readable, exponented int or something)This doesn't look right, and as a result (I think) the map in the MapField
no longer shows any information.
To reproduce (using v1.1.3)
Page
with a Location
field as Geometry
TestModel
as a DataObject
subclass, that also has a Location
field as Geometry
and set that location value, as any polygon located within the Page's geometry, e.g. around the shape of Te Papa's building footprintPage
records, that intersect or are within the geometry of the one TestModel
you just created, somethuing like this: $coords = (array) $request->postVar('coords');
$srid = Config::inst()->get(GIS::class, 'default_srid');
$records = PlanPage::get()->filter([
'Location:WithinGeo' => GIS::array_to_ewkt($coords, $srid, true),
]);
Note: As discussed, there should prob be a unit-test to cover the WithinGeo
filter :-)
[UPDATE]
I was partly being an idiot, in that I was relying too hard on expected behviour. In a standard SilverStripe FormField
subclass, changing the value, re-renders the "Publish" button, as SilverStripe detects that something has changed. It is this that isn't happening for the MapField
. SilverStripe simply wasn't recognising that a change had ocurred. Once I made a change to a different field, the "Publish" button highlighted itself, and publishing wrote the right Geometry string to the xx_Live table.
Inner rings of polygons are supposed to be interpreted as holes in the primary ring, aka donut polygons. These inner rings are currently drawn but filled.
hi,
SilverStripe 4.9 uses a version of symfony/yaml, 4.4.29 locally, and it is more strict, breaking YAML config files within this project:
PHP Fatal error: Uncaught Symfony\Component\Yaml\Exception\ParseException: Duplicate key "SilverStripe\Core\Injector\Injector" detected at line 3 (near " StCrossesFilter: '%$DataListFilter.ST_Crosses'"). in /var/www/vendor/symfony/yaml/Parser.php:345
The offending file appears to be https://github.com/smindel/silverstripe-gis/blob/master/_config/model.yml, which has the multiple keys problem
Regards
Gordon
GeoJsonService::index()
calls GeoJsonService::getConfig()
which always uses the module's default, baked-in value for the value of property_map
, even if API consumers specify one as follows in their model(s), as such, a leafletJS map was taking the wrong DataObject
field. With a patched module (incoming...) this will work as expected.
/**
* @var array
*/
private static $geojsonservice = [
'geometry_field' => 'Location',
'searchable_fields' => [
'Address',
'Location',
],
'property_map' => [
'ID' => 'id',
'Type' => 'type',
],
];
It appears that GeoJsonService::getConfig()
isn't really needed and that the default for property_map
can be added to the other defaults in AbstractGISWebServiceController::getConfig()
.
In MapField
on line 44:
if ($value instanceof DBGeometry) $value = $value->getValue();
Should this not be a check for instanceof DBGeography
? i.e. DBGeometry
's parent class?
It would be good if developers could manipulate the default height of the auto-scaffolded MapField
using a familliar API e.g. ->setHeight()
or even mimicing HTMLTextEditor
's ->setRows()
.
At the moment, the default height of the map is a little narrow. Of course I appreciate it auto-expands on hover, which would still be useful. In addition, maybe add a ->setDisableHoverBehaviour()
or similar.
In the CMS, and using the Polygon map-tool to select a multi-point area, I cannot seem to be able to save the record. Using the line-tool works though.
php 7.2 / SilverStripe 4.3 / Postgres 9.5 / Postgis 2.2
The error I get is:
[Emergency] Uncaught SilverStripe\ORM\Connect\DatabaseException: Couldn't run query: UPDATE "PlanRecord" SET "ClassName" = $1, "Location" = ST_GeomFromText($2, $3), "Type" = $4, "Label" = $5, "Address" = $6, "LastEdited" = $7, "Created" = $8, "Version" = $9 WHERE ("ID" = $10) ERROR: geometry contains non-closed rings HINT: "....75690175808978 -41.292060174344435))"
POST /admin/gis/Catalyst-CatPlan-Model-PlanRecord/EditForm/field/Catalyst-CatPlan-Model-PlanRecord/item/new/ItemEditForm/
Line 64 in /vagrant/vendor/silverstripe/framework/src/ORM/Connect/DBConnector.php
I gather this is a PostGIS error. Could the lat/lon be the wrong way around? Is each DB connection using the correct datum/projection?
EDIT:
When creating or editing a record with only 3 points, I get the error:
[Emergency] Uncaught SilverStripe\ORM\Connect\DatabaseException: Couldn't run query: UPDATE "PlanRecord" SET "ClassName" = $1, "Location" = ST_GeomFromText($2, $3), "Type" = $4, "Label" = $5, "Address" = $6, "LastEdited" = $7, "Created" = $8, "Version" = $9 WHERE ("ID" = $10) ERROR: geometry requires more points HINT: "...74.7733789170987 -41.30315140250484))"
POST /admin/gis/Catalyst-CatPlan-Model-PlanRecord/EditForm/field/Catalyst-CatPlan-Model-PlanRecord/item/new/ItemEditForm/
Line 64 in /vagrant/vendor/silverstripe/framework/src/ORM/Connect/DBConnector.php
Source
Which begs the question "What is the minimum no. points that PostGIS will allow"? If there is a minimum. there should probably be some client-side validation or SilverStripe validation to prevent creation of polygons with too few points. But really..If I want to create a triangle, why can't I?!
Here are the steps to reproduce:
DataObject
subclass and create a DataExtension
for it, whose $db
static contains Location => 'Geometry'
ModelAdmin
for itTo help with DI and service construction, all module classes available for use in userland code should consume the Injectable
trait so we can instantiate e.g. GridFieldMap::create($geometry)
.
To configure an app with the GeoJSON web service, the README says to configure your custom DO's with private static $geojsonwebservice
, when in fact the correct name should be private static $geojsonservice
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.