Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trac #768 - Add GEOSSTRtree_nearest to CAPI #61

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 16 additions & 0 deletions capi/geos_c.cpp
Expand Up @@ -1146,6 +1146,22 @@ GEOSSTRtree_query (geos::index::strtree::STRtree *tree,
GEOSSTRtree_query_r( handle, tree, g, cb, userdata );
}

const GEOSGeometry *
GEOSSTRtree_nearest (geos::index::strtree::STRtree *tree,
const geos::geom::Geometry *g)
{
return (const GEOSGeometry*) GEOSSTRtree_nearest_generic( tree, g, g, NULL, NULL);
}

const void* GEOSSTRtree_nearest_generic(GEOSSTRtree *tree,
const void* item,
const GEOSGeometry* itemEnvelope,
GEOSDistanceCallback distancefn,
void* userdata)
{
return GEOSSTRtree_nearest_generic_r( handle, tree, item, itemEnvelope, distancefn, userdata);
}

void
GEOSSTRtree_iterate(geos::index::strtree::STRtree *tree,
GEOSQueryCallback callback,
Expand Down
91 changes: 91 additions & 0 deletions capi/geos_c.h.in
Expand Up @@ -153,6 +153,7 @@ enum GEOSByteOrders {
};

typedef void (*GEOSQueryCallback)(void *item, void *userdata);
typedef int (*GEOSDistanceCallback)(const void *item1, const void* item2, double* distance, void* userdata);

/************************************************************************
*
Expand Down Expand Up @@ -814,6 +815,19 @@ extern void GEOS_DLL GEOSSTRtree_query_r(GEOSContextHandle_t handle,
const GEOSGeometry *g,
GEOSQueryCallback callback,
void *userdata);

extern const void* GEOS_DLL GEOSSTRtree_nearest_r(GEOSContextHandle_t handle,
GEOSSTRtree *tree,
const GEOSGeometry* geom);


extern const void* GEOS_DLL GEOSSTRtree_nearest_generic_r(GEOSContextHandle_t handle,
GEOSSTRtree *tree,
const void* item,
const GEOSGeometry* itemEnvelope,
GEOSDistanceCallback distancefn,
void* userdata);

extern void GEOS_DLL GEOSSTRtree_iterate_r(GEOSContextHandle_t handle,
GEOSSTRtree *tree,
GEOSQueryCallback callback,
Expand Down Expand Up @@ -1651,17 +1665,94 @@ extern char GEOS_DLL GEOSPreparedWithin(const GEOSPreparedGeometry* pg1, const G
* GEOSGeometry ownership is retained by caller
*/

/*
* Create a new R-tree using the Sort-Tile-Recursive algorithm (STRtree) for two-dimensional
* spatial data.
*
* @param nodeCapacity the maximum number of child nodes that a node may have. The minimum
* recommended capacity value is 4. If unsure, use a default node capacity of 10.
* @return a pointer to the created tree
*/
extern GEOSSTRtree GEOS_DLL *GEOSSTRtree_create(size_t nodeCapacity);

/*
* Insert an item into an STRtree
*
* @param tree the STRtree in which the item should be inserted
* @param g a GEOSGeometry whose envelope corresponds to the extent of 'item'
* @param item the item to insert into the tree
*/
extern void GEOS_DLL GEOSSTRtree_insert(GEOSSTRtree *tree,
const GEOSGeometry *g,
void *item);

/*
* Query an STRtree for items intersecting a specified envelope
*
* @param tree the STRtree to search
* @param g a GEOSGeomety from which a query envelope will be extracted
* @param callback a function to be executed for each item in the tree whose envelope intersects
* the envelope of 'g'. The callback function should take two parameters: a void
* pointer representing the located item in the tree, and a void userdata pointer.
* @param userdata an optional pointer to pe passed to 'callback' as an argument
*/
extern void GEOS_DLL GEOSSTRtree_query(GEOSSTRtree *tree,
const GEOSGeometry *g,
GEOSQueryCallback callback,
void *userdata);
/*
* Returns the nearest item in the STRtree to the supplied GEOSGeometry.
* All items in the tree MUST be of type GEOSGeometry. If this is not the case, use
* GEOSSTRtree_nearest_generic instead.
*
* @param tree the STRtree to search
* @param geom the geometry with which the tree should be queried
* @return a const pointer to the nearest GEOSGeometry in the tree to 'geom', or NULL in
* case of exception
*/
extern const GEOSGeometry* GEOS_DLL GEOSSTRtree_nearest(GEOSSTRtree *tree, const GEOSGeometry* geom);

/*
* Returns the nearest item in the STRtree to the supplied item
*
* @param tree the STRtree to search
* @param item the item with which the tree should be queried
* @param itemEnvelope a GEOSGeometry having the bounding box of 'item'
* @param distancefn a function that can compute the distance between two items
* in the STRtree. The function should return zero in case of error,
* and should store the computed distance to the location pointed to by
* the 'distance' argument. The computed distance between two items
* must not exceed the Cartesian distance between their envelopes.
* @param userdata optional pointer to arbitrary data; will be passed to distancefn
* each time it is called.
* @return a const pointer to the nearest item in the tree to 'item', or NULL in
* case of exception
*/
extern const void* GEOS_DLL GEOSSTRtree_nearest_generic(GEOSSTRtree *tree,
const void* item,
const GEOSGeometry* itemEnvelope,
GEOSDistanceCallback distancefn,
void* userdata);
/*
* Iterates over all items in the STRtree
*
* @param tree the STRtree over which to iterate
* @param callback a function to be executed for each item in the tree.
*/
extern void GEOS_DLL GEOSSTRtree_iterate(GEOSSTRtree *tree,
GEOSQueryCallback callback,
void *userdata);

/*
* Removes an item from the STRtree
*
* @param tree the STRtree from which to remove an item
* @param g the envelope of the item to remove
* @param the item to remove
* @return 0 if the item was not removed;
* 1 if the item was removed;
* 2 if an exception occurred
*/
extern char GEOS_DLL GEOSSTRtree_remove(GEOSSTRtree *tree,
const GEOSGeometry *g,
void *item);
Expand Down
77 changes: 76 additions & 1 deletion capi/geos_ts_c.cpp
Expand Up @@ -34,7 +34,8 @@
#include <geos/geom/Coordinate.h>
#include <geos/geom/IntersectionMatrix.h>
#include <geos/geom/Envelope.h>
#include <geos/index/strtree/STRtree.h>
#include <geos/index/strtree/STRtree.h>
#include <geos/index/strtree/GeometryItemDistance.h>
#include <geos/index/ItemVisitor.h>
#include <geos/io/WKTReader.h>
#include <geos/io/WKBReader.h>
Expand Down Expand Up @@ -5945,6 +5946,80 @@ GEOSSTRtree_query_r(GEOSContextHandle_t extHandle,
}
}

const void *
GEOSSTRtree_nearest_generic_r(GEOSContextHandle_t extHandle,
geos::index::strtree::STRtree *tree,
const void* item,
const geos::geom::Geometry* itemEnvelope,
GEOSDistanceCallback distancefn,
void* userdata)
{

GEOSContextHandleInternal_t *handle = 0;
try
{
if (distancefn) {
struct CustomItemDistance : public ItemDistance {
CustomItemDistance(GEOSDistanceCallback p_distancefn, void* p_userdata)
: m_distancefn(p_distancefn), m_userdata(p_userdata) {}

GEOSDistanceCallback m_distancefn;
void* m_userdata;

double distance(const ItemBoundable* item1, const ItemBoundable* item2) {
const void* a = item1->getItem();
const void* b = item2->getItem();
double d;

if (!m_distancefn(a, b, &d, m_userdata)) {
throw std::runtime_error(std::string("Failed to compute distance."));
}

return d;
}
};

CustomItemDistance itemDistance(distancefn, userdata);
return tree->nearestNeighbour(itemEnvelope->getEnvelopeInternal(), item, &itemDistance);
} else {
GeometryItemDistance itemDistance = GeometryItemDistance();
return tree->nearestNeighbour(itemEnvelope->getEnvelopeInternal(), item, &itemDistance);
}
}
catch (const std::exception &e)
{
if ( 0 == extHandle )
{
return NULL;
}

handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
if ( 0 == handle->initialized )
{
return NULL;
}

handle->ERROR_MESSAGE("%s", e.what());
}
catch (...)
{
if ( 0 == extHandle )
{
return NULL;
}

handle = reinterpret_cast<GEOSContextHandleInternal_t*>(extHandle);
if ( 0 == handle->initialized )
{
return NULL;
}

handle->ERROR_MESSAGE("Unknown exception thrown");
}

return NULL;
}

void
GEOSSTRtree_iterate_r(GEOSContextHandle_t extHandle,
geos::index::strtree::STRtree *tree,
Expand Down
114 changes: 114 additions & 0 deletions include/geos/index/strtree/BoundablePair.h
@@ -0,0 +1,114 @@
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
*
* Copyright (C) 2016 Daniel Baston
*
* This is free software; you can redistribute and/or modify it under
* the terms of the GNU Lesser General Public Licence as published
* by the Free Software Foundation.
* See the COPYING file for more information.
*
**********************************************************************
*
* Last port: index/strtree/BoundablePair.java (JTS-1.14)
*
**********************************************************************/

#ifndef GEOS_INDEX_STRTREE_BOUNDABLEPAIR_H
#define GEOS_INDEX_STRTREE_BOUNDABLEPAIR_H

#include <geos/index/strtree/Boundable.h>
#include <geos/index/strtree/ItemDistance.h>
#include <queue>

/**
* A pair of {@link Boundable}s, whose leaf items
* support a distance metric between them.
* Used to compute the distance between the members,
* and to expand a member relative to the other
* in order to produce new branches of the
* Branch-and-Bound evaluation tree.
* Provides an ordering based on the distance between the members,
* which allows building a priority queue by minimum distance.
*
* @author Martin Davis
*
*/

using namespace geos::index::strtree;


namespace geos {
namespace index {
namespace strtree {
class BoundablePair {
private:
const Boundable* boundable1;
const Boundable* boundable2;
ItemDistance* itemDistance;
double mDistance;

public:
struct BoundablePairQueueCompare {
bool operator()(const BoundablePair* a, const BoundablePair* b) {
return a->getDistance() > b->getDistance();
}
};

typedef std::priority_queue<BoundablePair*, std::vector<BoundablePair*>, BoundablePairQueueCompare> BoundablePairQueue;
BoundablePair(const Boundable* boundable1, const Boundable* boundable2, ItemDistance* itemDistance);

/**
* Gets one of the member {@link Boundable}s in the pair
* (indexed by [0, 1]).
*
* @param i the index of the member to return (0 or 1)
* @return the chosen member
*/
const Boundable* getBoundable(int i) const;

/**
* Computes the distance between the {@link Boundable}s in this pair.
* The boundables are either composites or leaves.
* If either is composite, the distance is computed as the minimum distance
* between the bounds.
* If both are leaves, the distance is computed by {@link #itemDistance(ItemBoundable, ItemBoundable)}.
*
* @return
*/
double distance();

/**
* Gets the minimum possible distance between the Boundables in
* this pair.
* If the members are both items, this will be the
* exact distance between them.
* Otherwise, this distance will be a lower bound on
* the distances between the items in the members.
*
* @return the exact or lower bound distance for this pair
*/
double getDistance() const;

/**
* Tests if both elements of the pair are leaf nodes
*
* @return true if both pair elements are leaf nodes
*/
bool isLeaves() const;

static bool isComposite(const Boundable* item);

static double area(const Boundable* b);

void expandToQueue(BoundablePairQueue &, double minDistance);
void expand(const Boundable* bndComposite, const Boundable* bndOther, BoundablePairQueue & priQ, double minDistance);
};
}
}
}

#endif

45 changes: 45 additions & 0 deletions include/geos/index/strtree/GeometryItemDistance.h
@@ -0,0 +1,45 @@
/**********************************************************************
*
* GEOS - Geometry Engine Open Source
* http://geos.osgeo.org
*
* Copyright (C) 2016 Daniel Baston
*
* This is free software; you can redistribute and/or modify it under
* the terms of the GNU Lesser General Public Licence as published
* by the Free Software Foundation.
* See the COPYING file for more information.
*
**********************************************************************
*
* Last port: index/strtree/GeometryItemDistance.java (JTS-1.14)
*
**********************************************************************/

#ifndef GEOS_INDEX_STRTREE_GEOMETRYITEMDISTANCE_H
#define GEOS_INDEX_STRTREE_GEOMETRYITEMDISTANCE_H

#include <geos/geom/Geometry.h>
#include <geos/index/strtree/ItemDistance.h>

namespace geos {
namespace index {
namespace strtree {
class GeometryItemDistance : public ItemDistance {
public:
/**
* Computes the distance between two {@link Geometry} items,
* using the {@link Geometry#distance(Geometry)} method.
*
* @param item1 an item which is a Geometry
* @param item2 an item which is a Geometry
* @return the distance between the geometries
* @throws ClassCastException if either item is not a Geometry
*/
double distance(const ItemBoundable* item1, const ItemBoundable* item2);
};
}
}
}

#endif //GEOS_GEOMETRYITEMDISTANCE_H