Skip to content

Commit

Permalink
ShapefileWriter class
Browse files Browse the repository at this point in the history
and a few fixes and improvements here and there
  • Loading branch information
Gaspare Sganga committed Aug 26, 2019
1 parent 7bbbcf3 commit 043926b
Show file tree
Hide file tree
Showing 8 changed files with 1,884 additions and 734 deletions.
39 changes: 24 additions & 15 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
- `Shapefile`, `Geometry` and `GeometryCollection` abstract classes
- Custom *DBF* charset support
- Support for emulated `null` values in *DBF* files
- Reading optional *DBT* files (support for `MEMO` fields)
- Reading optional *CPG* and *CST* files
- Reading and writing optional *DBT* files (support for `MEMO` fields)
- Reading and writing optional *CPG* files
- `ShapefileException::getDetails()` method
- Constructor options constants:
- `Shapefile::OPTION_INVERT_POLYGONS_ORIENTATION`
- `Shapefile::OPTION_SUPPRESS_Z`
- `Shapefile::OPTION_SUPPRESS_M`
- `Shapefile::OPTION_CPG_ENABLE_FOR_DEFAULT_CHARSET`
- `Shapefile::OPTION_DBF_CONVERT_TO_UTF8`
- `Shapefile::OPTION_DBF_FORCE_ALL_CAPS`
- `Shapefile::OPTION_NULL_PADDING_CHAR`
- `Shapefile::OPTION_FORCE_MULTIPART_GEOMETRIES`
- `Shapefile::OPTION_ENFORCE_POLYGON_CLOSED_RINGS`
- `Shapefile::OPTION_IGNORE_SHAPEFILE_BBOX`
- `Shapefile::OPTION_IGNORE_GEOMETRIES_BBOXES`
- `Shapefile::OPTION_DBF_IGNORED_FIELDS`
- `Shapefile::OPTION_DBF_NULL_PADDING_CHAR`
- `Shapefile::OPTION_DBF_NULLIFY_INVALID_DATES`
- `Shapefile::OPTION_DBF_CONVERT_TO_UTF8`
- `Shapefile::OPTION_DBF_RETURN_DATES_AS_OBJECTS`
- `Shapefile::OPTION_DELETE_EMPTY_FILES`
- `Shapefile::OPTION_ENFORCE_GEOMETRY_DATA_STRUCTURE`
- `Shapefile::OPTION_ENFORCE_POLYGON_CLOSED_RINGS`
- `Shapefile::OPTION_FORCE_MULTIPART_GEOMETRIES`
- `Shapefile::OPTION_IGNORE_GEOMETRIES_BBOXES`
- `Shapefile::OPTION_IGNORE_SHAPEFILE_BBOX`
- `Shapefile::OPTION_INVERT_POLYGONS_ORIENTATION`
- `Shapefile::OPTION_OVERWRITE_EXISTING_FILES`
- `Shapefile::OPTION_SUPPRESS_M`
- `Shapefile::OPTION_SUPPRESS_Z`
- File types constants:
- `Shapefile::FILE_SHP`
- `Shapefile::FILE_SHX`
- `Shapefile::FILE_DBF`
- `Shapefile::FILE_DBT`
- `Shapefile::FILE_PRJ`
- `Shapefile::FILE_CPG`
- `Shapefile::FILE_CST`
- Shape types constants:
- `Shapefile::SHAPE_TYPE_NULL`
- `Shapefile::SHAPE_TYPE_POINT`
Expand All @@ -63,7 +68,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
- `Shapefile::ERR_UNDEFINED`
- `Shapefile::ERR_FILE_MISSING`
- `Shapefile::ERR_FILE_EXISTS`
- `Shapefile::ERR_FILE_INVALID_RESOURCE`
- `Shapefile::ERR_FILE_OPEN`
- `Shapefile::ERR_FILE_READING`
- `Shapefile::ERR_FILE_WRITING`
- `Shapefile::ERR_SHP_TYPE_NOT_SUPPORTED`
- `Shapefile::ERR_SHP_TYPE_NOT_SET`
- `Shapefile::ERR_SHP_TYPE_ALREADY_SET`
Expand All @@ -81,12 +89,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
- `Shapefile::ERR_DBF_FIELD_SIZE_NOT_VALID`
- `Shapefile::ERR_DBF_FIELD_DECIMALS_NOT_VALID`
- `Shapefile::ERR_DBF_CHARSET_CONVERSION`
- `Shapefile::ERR_DBT_EOF_REACHED`
- `Shapefile::ERR_GEOM_NOT_EMPTY`
- `Shapefile::ERR_GEOM_COORD_VALUE_NOT_VALID`
- `Shapefile::ERR_GEOM_MISMATCHED_DIMENSIONS`
- `Shapefile::ERR_GEOM_MISMATCHED_BBOX`
- `Shapefile::ERR_GEOM_SHAPEFILE_NOT_SET`
- `Shapefile::ERR_GEOM_SHAPEFILE_ALREADY_SET`
- `Shapefile::ERR_GEOM_MISSING_FIELD`
- `Shapefile::ERR_GEOM_POINT_NOT_VALID`
- `Shapefile::ERR_GEOM_POLYGON_OPEN_RING`
- `Shapefile::ERR_GEOM_POLYGON_AREA_TOO_SMALL`
Expand All @@ -98,6 +106,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
- `Shapefile::ERR_INPUT_ARRAY_NOT_VALID`
- `Shapefile::ERR_INPUT_WKT_NOT_VALID`
- `Shapefile::ERR_INPUT_GEOJSON_NOT_VALID`
- `Shapefile::ERR_INPUT_NUMERIC_VALUE_OVERFLOW`

### Changed
- Folder structure under `src/` reflects namespaces hierarchy
Expand All @@ -111,7 +120,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

### Fixed
- Stricter invalid date format detection
- Logical (`bool`) not initialized values (`null`) detection
- Logical (`bool`) not initialized values (`null`) detection in *DBF* files

### Removed
- `ShapefileReader` public methods:
Expand Down
93 changes: 21 additions & 72 deletions src/Shapefile/Geometry/Geometry.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,11 @@ abstract class Geometry
*/
private $custom_bounding_box = null;


/**
* @var array DBF data of the Geometry.
* @var array Data of the Geometry.
*/
private $data = [];

/**
* @var Shapefile|null Shapefile the Geometry belongs to.
* It is used only for geometries that belong to a Shapefile and
* NOT for the ones contained in a collection.
* The structure of the Shapefile will dictate the structure of Geometry data.
*/
private $Shapefile = null;


/**
* @var bool Flag representing whether the Geometry is empty.
*/
Expand Down Expand Up @@ -198,17 +188,18 @@ public function setFlagDeleted($value)

/**
* Sets a custom bounding box for the Geometry.
* No formal check is carried out except the compliance of dimensions.
* No check is carried out except a formal compliance of dimensions.
*
* @param array $bounding_box Associative array with the xmin, xmax, ymin, ymax and optional zmin, zmax, mmin, mmax values.
*/
public function setCustomBoundingBox($bounding_box)
{
$bounding_box = array_intersect_key($bounding_box, array_flip(['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax', 'mmin', 'mmax']));
if (
$this->isEmpty() ||
!isset($bounding_box['xmin'], $bounding_box['xmax'], $bounding_box['ymin'], $bounding_box['ymax']) ||
($this->isZ() && !isset($bounding_box['zmin'], $bounding_box['zmax'])) ||
($this->isM() && !isset($bounding_box['mmin'], $bounding_box['mmax']))
$this->isEmpty()
|| !isset($bounding_box['xmin'], $bounding_box['xmax'], $bounding_box['ymin'], $bounding_box['ymax'])
|| (($this->isZ() && !isset($bounding_box['zmin'], $bounding_box['zmax'])) || (!$this->isZ() && (isset($bounding_box['zmin']) || isset($bounding_box['zmax']))))
|| (($this->isM() && !isset($bounding_box['mmin'], $bounding_box['mmax'])) || (!$this->isM() && (isset($bounding_box['mmin']) || isset($bounding_box['mmax']))))
) {
throw new ShapefileException(Shapefile::ERR_GEOM_MISMATCHED_BBOX);
}
Expand All @@ -227,78 +218,51 @@ public function resetCustomBoundingBox()

/**
* Gets data value for speficied field name.
* It requires the Geometry to belong to a Shapefile.
*
* @param string $field Name of the field.
* @param string $fieldname Name of the field.
*
* @return mixed
*/
public function getData($field)
public function getData($fieldname)
{
$this->checkShapefile();
$this->Shapefile->checkField($field);
return $this->data[$field];
if (!isset($this->data[$fieldname])) {
throw new ShapefileException(Shapefile::ERR_INPUT_FIELD_NOT_FOUND, $fieldname);
}
return $this->data[$fieldname];
}

/**
* Sets data value for speficied field name.
* It requires the Geometry to belong to a Shapefile.
*
* @param string $field Name of the field.
* @param string $fieldname Name of the field.
* @param mixed $value Value to assign to the field.
*/
public function setData($field, $value)
public function setData($fieldname, $value)
{
$this->checkShapefile();
$this->Shapefile->checkField($field);
$this->data[$field] = $value;
$this->data[$fieldname] = $value;
}

/**
* Gets an array of data of all the defined fields.
* It requires the Geometry to belong to a Shapefile.
* Gets an array of defined data.
*
* @return array
*/
public function getDataArray()
{
$this->checkShapefile();
return $this->data;
}

/**
* Sets an array of data.
* It requires the Geometry to belong to a Shapefile.
*
* @param array $data Associative array of values.
* @param array $data Associative array of values.
*/
public function setDataArray($data)
{
$this->checkShapefile();
foreach ($data as $field => $value) {
$this->Shapefile->checkField($field);
$this->data[$field] = $value;
foreach ($data as $fieldname => $value) {
$this->data[$fieldname] = $value;
}
}


/**
* Sets the Shapefile the Geometry belongs to.
* It can be called just once for an instance of the class.
* This is not intended for users, but Shapefile requires it for internal mechanisms.
*
* @internal
*
* @param Shapefile $Shapefile
*/
public function setShapefile(\Shapefile\Shapefile $Shapefile)
{
if ($this->Shapefile !== null) {
throw new ShapefileException(Shapefile::ERR_GEOM_SHAPEFILE_ALREADY_SET);
}
$this->Shapefile = $Shapefile;
$this->data = array_fill_keys(array_keys($Shapefile->getFields()), null);
}



Expand Down Expand Up @@ -335,17 +299,13 @@ protected function setFlagM($value)


/**
* Checks if the Geometry has been initialized (it is not empty or has been added to a Shapefile)
* and if YES throws and exception.
* Checks if the Geometry has been initialized (it is not empty) and if YES throws and exception.
*/
protected function checkInit()
{
if (!$this->isEmpty()) {
throw new ShapefileException(Shapefile::ERR_GEOM_NOT_EMPTY);
}
if ($this->Shapefile !== null) {
throw new ShapefileException(Shapefile::ERR_GEOM_SHAPEFILE_ALREADY_SET);
}
}


Expand Down Expand Up @@ -629,15 +589,4 @@ private function parseCoordinatesArray($coordinates, $force_z, $force_m, $err_co
return $ret;
}


/**
* Checks if the Geometry belongs to a Shapefile and if NOT throws and exception.
*/
private function checkShapefile()
{
if ($this->Shapefile === null) {
throw new ShapefileException(Shapefile::ERR_GEOM_SHAPEFILE_NOT_SET);
}
}

}
7 changes: 1 addition & 6 deletions src/Shapefile/Geometry/GeometryCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,9 @@ abstract protected function getCollectionClass();
*/
public function __construct(array $geometries = null)
{
$classname = $this->getCollectionClass();
if ($geometries !== null) {
foreach ($geometries as $Geometry) {
if (is_a($Geometry, $classname)) {
$this->addGeometry($Geometry);
} else {
throw new ShapefileException(Shapefile::ERR_INPUT_GEOMETRY_TYPE_NOT_VALID, $classname);
}
$this->addGeometry($Geometry);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Shapefile/Geometry/MultiPolygon.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public function getArray()
}
return [
'numparts' => $this->getNumGeometries(),
'rings' => $parts,
'parts' => $parts,
];
}

Expand Down
Loading

0 comments on commit 043926b

Please sign in to comment.