abstract class Collection in geoPHP 8
Same name and namespace in other branches
- 7 geoPHP/lib/geometry/Collection.class.php \Collection
Collection: Abstract class for compound geometries
A geometry is a collection if it is made up of other component geometries. Therefore everything but a Point is a Collection. For example a LingString is a collection of Points. A Polygon is a collection of LineStrings etc.
Hierarchy
- class \Geometry
- class \Collection
Expanded class hierarchy of Collection
File
- geoPHP/
lib/ geometry/ Collection.class.php, line 11
View source
abstract class Collection extends Geometry {
public $components = array();
/**
* Constructor: Checks and sets component geometries
*
* @param array $components array of geometries
*/
public function __construct($components = array()) {
if (!is_array($components)) {
throw new Exception("Component geometries must be passed as an array");
}
foreach ($components as $component) {
if ($component instanceof Geometry) {
$this->components[] = $component;
}
else {
throw new Exception("Cannot create a collection with non-geometries");
}
}
}
/**
* Returns Collection component geometries
*
* @return array
*/
public function getComponents() {
return $this->components;
}
public function centroid() {
if ($this
->isEmpty()) {
return NULL;
}
if ($this
->geos()) {
$geos_centroid = $this
->geos()
->centroid();
if ($geos_centroid
->typeName() == 'Point') {
return geoPHP::geosToGeometry($this
->geos()
->centroid());
}
}
// As a rough estimate, we say that the centroid of a colletion is the centroid of it's envelope
// @@TODO: Make this the centroid of the convexHull
// Note: Outside of polygons, geometryCollections and the trivial case of points, there is no standard on what a "centroid" is
$centroid = $this
->envelope()
->centroid();
return $centroid;
}
public function getBBox() {
if ($this
->isEmpty()) {
return NULL;
}
if ($this
->geos()) {
$envelope = $this
->geos()
->envelope();
if ($envelope
->typeName() == 'Point') {
return geoPHP::geosToGeometry($envelope)
->getBBOX();
}
$geos_ring = $envelope
->exteriorRing();
return array(
'maxy' => $geos_ring
->pointN(3)
->getY(),
'miny' => $geos_ring
->pointN(1)
->getY(),
'maxx' => $geos_ring
->pointN(1)
->getX(),
'minx' => $geos_ring
->pointN(3)
->getX(),
);
}
// Go through each component and get the max and min x and y
$i = 0;
foreach ($this->components as $component) {
$component_bbox = $component
->getBBox();
// On the first run through, set the bbox to the component bbox
if ($i == 0) {
$maxx = $component_bbox['maxx'];
$maxy = $component_bbox['maxy'];
$minx = $component_bbox['minx'];
$miny = $component_bbox['miny'];
}
// Do a check and replace on each boundary, slowly growing the bbox
$maxx = $component_bbox['maxx'] > $maxx ? $component_bbox['maxx'] : $maxx;
$maxy = $component_bbox['maxy'] > $maxy ? $component_bbox['maxy'] : $maxy;
$minx = $component_bbox['minx'] < $minx ? $component_bbox['minx'] : $minx;
$miny = $component_bbox['miny'] < $miny ? $component_bbox['miny'] : $miny;
$i++;
}
return array(
'maxy' => $maxy,
'miny' => $miny,
'maxx' => $maxx,
'minx' => $minx,
);
}
public function asArray() {
$array = array();
foreach ($this->components as $component) {
$array[] = $component
->asArray();
}
return $array;
}
public function area() {
if ($this
->geos()) {
return $this
->geos()
->area();
}
$area = 0;
foreach ($this->components as $component) {
$area += $component
->area();
}
return $area;
}
// By default, the boundary of a collection is the boundary of it's components
public function boundary() {
if ($this
->isEmpty()) {
return new LineString();
}
if ($this
->geos()) {
return $this
->geos()
->boundary();
}
$components_boundaries = array();
foreach ($this->components as $component) {
$components_boundaries[] = $component
->boundary();
}
return geoPHP::geometryReduce($components_boundaries);
}
public function numGeometries() {
return count($this->components);
}
// Note that the standard is 1 based indexing
public function geometryN($n) {
$n = intval($n);
if (array_key_exists($n - 1, $this->components)) {
return $this->components[$n - 1];
}
else {
return NULL;
}
}
public function length() {
$length = 0;
foreach ($this->components as $delta => $component) {
$length += $component
->length();
}
return $length;
}
public function greatCircleLength($radius = 6378137) {
$length = 0;
foreach ($this->components as $component) {
$length += $component
->greatCircleLength($radius);
}
return $length;
}
public function haversineLength() {
$length = 0;
foreach ($this->components as $component) {
$length += $component
->haversineLength();
}
return $length;
}
public function dimension() {
$dimension = 0;
foreach ($this->components as $component) {
if ($component
->dimension() > $dimension) {
$dimension = $component
->dimension();
}
}
return $dimension;
}
// A collection is empty if it has no components OR all it's components are empty
public function isEmpty() {
if (!count($this->components)) {
return TRUE;
}
else {
foreach ($this->components as $component) {
if (!$component
->isEmpty()) {
return FALSE;
}
}
return TRUE;
}
}
public function numPoints() {
$num = 0;
foreach ($this->components as $component) {
$num += $component
->numPoints();
}
return $num;
}
public function getPoints() {
$points = array();
foreach ($this->components as $component) {
$points = array_merge($points, $component
->getPoints());
}
return $points;
}
public function equals($geometry) {
if ($this
->geos()) {
return $this
->geos()
->equals($geometry
->geos());
}
// To test for equality we check to make sure that there is a matching point
// in the other geometry for every point in this geometry.
// This is slightly more strict than the standard, which
// uses Within(A,B) = true and Within(B,A) = true
// @@TODO: Eventually we could fix this by using some sort of simplification
// method that strips redundant vertices (that are all in a row)
$this_points = $this
->getPoints();
$other_points = $geometry
->getPoints();
// First do a check to make sure they have the same number of vertices
if (count($this_points) != count($other_points)) {
return FALSE;
}
foreach ($this_points as $point) {
$found_match = FALSE;
foreach ($other_points as $key => $test_point) {
if ($point
->equals($test_point)) {
$found_match = TRUE;
unset($other_points[$key]);
break;
}
}
if (!$found_match) {
return FALSE;
}
}
// All points match, return TRUE
return TRUE;
}
public function isSimple() {
if ($this
->geos()) {
return $this
->geos()
->isSimple();
}
// A collection is simple if all it's components are simple
foreach ($this->components as $component) {
if (!$component
->isSimple()) {
return FALSE;
}
}
return TRUE;
}
public function explode() {
$parts = array();
foreach ($this->components as $component) {
$parts = array_merge($parts, $component
->explode());
}
return $parts;
}
// Not valid for this geometry type
// --------------------------------
public function x() {
return NULL;
}
public function y() {
return NULL;
}
public function startPoint() {
return NULL;
}
public function endPoint() {
return NULL;
}
public function isRing() {
return NULL;
}
public function isClosed() {
return NULL;
}
public function pointN($n) {
return NULL;
}
public function exteriorRing() {
return NULL;
}
public function numInteriorRings() {
return NULL;
}
public function interiorRingN($n) {
return NULL;
}
public function pointOnSurface() {
return NULL;
}
}