mirror of https://gitee.com/bigwinds/arangodb
added MultiPolygon GeoJSON constructor function (#7634)
This commit is contained in:
parent
4376f9efb6
commit
a94a402dde
|
@ -277,6 +277,32 @@ RETURN GEO_POLYGON([
|
||||||
@END_EXAMPLE_AQL
|
@END_EXAMPLE_AQL
|
||||||
@endDocuBlock aqlGeoPolygon_2
|
@endDocuBlock aqlGeoPolygon_2
|
||||||
|
|
||||||
|
### GEO_MULTIPOLYGON()
|
||||||
|
|
||||||
|
`GEO_MULTIPOLYGON(polygons) → geoJson`
|
||||||
|
|
||||||
|
Construct a GeoJSON MultiPolygon. Needs at least two Polygons in an array.
|
||||||
|
See [GEO_POLYGON()](#geopolygon) for the rules of Polygon construction.
|
||||||
|
|
||||||
|
- **polygons** (array): array of polygons
|
||||||
|
- returns **geoJson** (object|null): a valid GeoJSON MultiPolygon
|
||||||
|
|
||||||
|
MultiPolygon comprised of a simple Polygon and a Polygon with hole:
|
||||||
|
|
||||||
|
@startDocuBlockInline aqlGeoMultiPolygon_1
|
||||||
|
@EXAMPLE_AQL{aqlGeoMultiPolygon_1}
|
||||||
|
RETURN GEO_MULTIPOLYGON([
|
||||||
|
[
|
||||||
|
[[40, 40], [20, 45], [45, 30], [40, 40]]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[[20, 35], [10, 30], [10, 10], [30, 5], [45, 20], [20, 35]],
|
||||||
|
[[30, 20], [20, 15], [20, 25], [30, 20]]
|
||||||
|
]
|
||||||
|
])
|
||||||
|
@END_EXAMPLE_AQL
|
||||||
|
@endDocuBlock aqlGeoMultiPolygon_1
|
||||||
|
|
||||||
Geo Index Functions
|
Geo Index Functions
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
|
|
@ -358,6 +358,7 @@ void AqlFunctionFeature::addGeometryConstructors() {
|
||||||
add({"GEO_POINT", ".,.", flags, &Functions::GeoPoint});
|
add({"GEO_POINT", ".,.", flags, &Functions::GeoPoint});
|
||||||
add({"GEO_MULTIPOINT", ".", flags, &Functions::GeoMultiPoint});
|
add({"GEO_MULTIPOINT", ".", flags, &Functions::GeoMultiPoint});
|
||||||
add({"GEO_POLYGON", ".", flags, &Functions::GeoPolygon});
|
add({"GEO_POLYGON", ".", flags, &Functions::GeoPolygon});
|
||||||
|
add({"GEO_MULTIPOLYGON", ".", flags, &Functions::GeoMultiPolygon});
|
||||||
add({"GEO_LINESTRING", ".", flags, &Functions::GeoLinestring});
|
add({"GEO_LINESTRING", ".", flags, &Functions::GeoLinestring});
|
||||||
add({"GEO_MULTILINESTRING", ".", flags, &Functions::GeoMultiLinestring});
|
add({"GEO_MULTILINESTRING", ".", flags, &Functions::GeoMultiLinestring});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1461,6 +1461,109 @@ AqlValue callApplyBackend(arangodb::aql::Query* query,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Result parseGeoPolygon(VPackSlice polygon, VPackBuilder& b) {
|
||||||
|
// check if nested or not
|
||||||
|
bool unnested = false;
|
||||||
|
for (auto const& v : VPackArrayIterator(polygon)) {
|
||||||
|
if (v.isArray() && v.length() == 2) {
|
||||||
|
unnested = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unnested) {
|
||||||
|
b.openArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!polygon.isArray()) {
|
||||||
|
return Result(
|
||||||
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
|
"Polygon needs to be an array of positions.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& v : VPackArrayIterator(polygon)) {
|
||||||
|
if (v.isArray() && v.length() > 2) {
|
||||||
|
b.openArray();
|
||||||
|
for (auto const& coord : VPackArrayIterator(v)) {
|
||||||
|
if (coord.isNumber()) {
|
||||||
|
b.add(VPackValue(coord.getNumber<double>()));
|
||||||
|
} else if (coord.isArray()) {
|
||||||
|
if (coord.length() < 2) {
|
||||||
|
return Result(
|
||||||
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
|
"a Position needs at least two numeric values");
|
||||||
|
} else {
|
||||||
|
b.openArray();
|
||||||
|
for (auto const& innercord : VPackArrayIterator(coord)) {
|
||||||
|
if (innercord.isNumber()) {
|
||||||
|
b.add(VPackValue(innercord.getNumber<double>())); // TODO
|
||||||
|
} else if (innercord.isArray() && innercord.length() == 2) {
|
||||||
|
if (innercord.at(0).isNumber() && innercord.at(1).isNumber()) {
|
||||||
|
b.openArray();
|
||||||
|
b.add(VPackValue(innercord.at(0).getNumber<double>()));
|
||||||
|
b.add(VPackValue(innercord.at(1).getNumber<double>()));
|
||||||
|
b.close();
|
||||||
|
} else {
|
||||||
|
return Result(
|
||||||
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
|
"coordinate is not a number");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Result(
|
||||||
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
|
"not an array describing a position");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Result(
|
||||||
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
|
"not an array containing positions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.close();
|
||||||
|
} else if (v.isArray() && v.length() == 2) {
|
||||||
|
if (polygon.length() > 2) {
|
||||||
|
b.openArray();
|
||||||
|
for (auto const& innercord : VPackArrayIterator(v)) {
|
||||||
|
if (innercord.isNumber()) {
|
||||||
|
b.add(VPackValue(innercord.getNumber<double>()));
|
||||||
|
} else if (innercord.isArray() && innercord.length() == 2) {
|
||||||
|
if (innercord.at(0).isNumber() && innercord.at(1).isNumber()) {
|
||||||
|
b.openArray();
|
||||||
|
b.add(VPackValue(innercord.at(0).getNumber<double>()));
|
||||||
|
b.add(VPackValue(innercord.at(1).getNumber<double>()));
|
||||||
|
b.close();
|
||||||
|
} else {
|
||||||
|
return Result(
|
||||||
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
|
"coordinate is not a number");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Result(
|
||||||
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
|
"not a numeric value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.close();
|
||||||
|
} else {
|
||||||
|
return Result(
|
||||||
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
|
"a Polygon needs at least three positions");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Result(
|
||||||
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
|
"not an array containing positions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unnested) {
|
||||||
|
b.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {TRI_ERROR_NO_ERROR};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -5235,110 +5338,86 @@ AqlValue Functions::GeoPolygon(arangodb::aql::Query* query,
|
||||||
AqlValueMaterializer materializer(trx);
|
AqlValueMaterializer materializer(trx);
|
||||||
VPackSlice s = materializer.slice(geoArray, false);
|
VPackSlice s = materializer.slice(geoArray, false);
|
||||||
|
|
||||||
// check if nested or not
|
Result res = ::parseGeoPolygon(s, b);
|
||||||
bool unnested = false;
|
if (res.fail()) {
|
||||||
for (auto const& v : VPackArrayIterator(s)) {
|
::registerWarning(query, "GEO_POLYGON", res);
|
||||||
if (v.isArray() && v.length() == 2) {
|
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
||||||
unnested = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (unnested) {
|
|
||||||
b.openArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& v : VPackArrayIterator(s)) {
|
b.close(); // coordinates
|
||||||
if (v.isArray() && v.length() > 2) {
|
b.close(); // object
|
||||||
b.openArray();
|
|
||||||
for (auto const& coord : VPackArrayIterator(v)) {
|
return AqlValue(b);
|
||||||
if (coord.isNumber()) {
|
}
|
||||||
b.add(VPackValue(coord.getNumber<double>()));
|
|
||||||
} else if (coord.isArray()) {
|
/// @brief function GEO_MULTIPOLYGON
|
||||||
if (coord.length() < 2) {
|
AqlValue Functions::GeoMultiPolygon(arangodb::aql::Query* query,
|
||||||
::registerWarning(query, "GEO_POLYGON", Result(
|
transaction::Methods* trx,
|
||||||
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
VPackFunctionParameters const& parameters) {
|
||||||
"a Position needs at least two numeric values"));
|
size_t const n = parameters.size();
|
||||||
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
|
||||||
} else {
|
if (n < 1) {
|
||||||
b.openArray();
|
// no parameters
|
||||||
for (auto const& innercord : VPackArrayIterator(coord)) {
|
return AqlValue(AqlValueHintNull());
|
||||||
if (innercord.isNumber()) {
|
}
|
||||||
b.add(VPackValue(innercord.getNumber<double>()));
|
|
||||||
} else if (innercord.isArray()) {
|
AqlValue const& geoArray = extractFunctionParameterValue(parameters, 0);
|
||||||
if (innercord.at(0).isNumber() && innercord.at(1).isNumber()) {
|
|
||||||
b.openArray();
|
if (!geoArray.isArray()) {
|
||||||
b.add(VPackValue(innercord.at(0).getNumber<double>()));
|
::registerWarning(query, "GEO_MULTIPOLYGON",
|
||||||
b.add(VPackValue(innercord.at(1).getNumber<double>()));
|
TRI_ERROR_QUERY_ARRAY_EXPECTED);
|
||||||
b.close();
|
|
||||||
} else {
|
|
||||||
::registerWarning(query, "GEO_POLYGON", Result(
|
|
||||||
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
|
||||||
"not a number"));
|
|
||||||
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
::registerWarning(query, "GEO_POLYGON", Result(
|
AqlValueMaterializer materializer(trx);
|
||||||
|
VPackSlice s = materializer.slice(geoArray, false);
|
||||||
|
|
||||||
|
/*
|
||||||
|
return GEO_MULTIPOLYGON([
|
||||||
|
[
|
||||||
|
[[40, 40], [20, 45], [45, 30], [40, 40]]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[[20, 35], [10, 30], [10, 10], [30, 5], [45, 20], [20, 35]],
|
||||||
|
[[30, 20], [20, 15], [20, 25], [30, 20]]
|
||||||
|
]
|
||||||
|
])
|
||||||
|
*/
|
||||||
|
|
||||||
|
TRI_ASSERT(s.isArray());
|
||||||
|
if (s.length() < 2) {
|
||||||
|
::registerWarning(query, "GEO_MULTIPOLYGON", Result(
|
||||||
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
"not an array describing a position"));
|
"a MultiPolygon needs at least two Polygons inside."));
|
||||||
|
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
||||||
|
}
|
||||||
|
|
||||||
|
VPackBuilder b;
|
||||||
|
b.openObject();
|
||||||
|
b.add("type", VPackValue("MultiPolygon"));
|
||||||
|
b.add("coordinates", VPackValue(VPackValueType::Array));
|
||||||
|
|
||||||
|
for (auto const& arrayOfPolygons : VPackArrayIterator(s)) {
|
||||||
|
if (!arrayOfPolygons.isArray()) {
|
||||||
|
::registerWarning(query, "GEO_MULTIPOLYGON", Result(
|
||||||
|
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
||||||
|
"a MultiPolygon needs at least two Polygons inside."));
|
||||||
|
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
||||||
|
}
|
||||||
|
b.openArray(); //arrayOfPolygons
|
||||||
|
for (auto const& v : VPackArrayIterator(arrayOfPolygons)) {
|
||||||
|
Result res = ::parseGeoPolygon(v, b);
|
||||||
|
if (res.fail()) {
|
||||||
|
::registerWarning(query, "GEO_MULTIPOLYGON", res);
|
||||||
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.close();
|
b.close(); //arrayOfPolygons close
|
||||||
}
|
|
||||||
} else {
|
|
||||||
::registerWarning(query, "GEO_POLYGON", Result(
|
|
||||||
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
|
||||||
"not an array containing positions"));
|
|
||||||
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.close();
|
|
||||||
} else if (v.isArray() && v.length() == 2) {
|
|
||||||
if (s.length() > 2) {
|
|
||||||
b.openArray();
|
|
||||||
for (auto const& innercord : VPackArrayIterator(v)) {
|
|
||||||
if (innercord.isNumber()) {
|
|
||||||
b.add(VPackValue(innercord.getNumber<double>()));
|
|
||||||
} else if (innercord.isArray()) {
|
|
||||||
if (innercord.at(0).isNumber() && innercord.at(1).isNumber()) {
|
|
||||||
b.openArray();
|
|
||||||
b.add(VPackValue(innercord.at(0).getNumber<double>()));
|
|
||||||
b.add(VPackValue(innercord.at(1).getNumber<double>()));
|
|
||||||
b.close();
|
|
||||||
} else {
|
|
||||||
::registerWarning(query, "GEO_POLYGON", Result(
|
|
||||||
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
|
||||||
"not a number"));
|
|
||||||
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
::registerWarning(query, "GEO_POLYGON", Result(
|
|
||||||
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
|
||||||
"not a numeric value"));
|
|
||||||
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.close();
|
|
||||||
} else {
|
|
||||||
::registerWarning(query, "GEO_POLYGON", Result(
|
|
||||||
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
|
||||||
"a Polygon needs at least three positions"));
|
|
||||||
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
::registerWarning(query, "GEO_POLYGON", Result(
|
|
||||||
TRI_ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH,
|
|
||||||
"not an array containing positions"));
|
|
||||||
return AqlValue(arangodb::velocypack::Slice::nullSlice());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b.close();
|
b.close();
|
||||||
b.close();
|
b.close();
|
||||||
|
|
||||||
if (unnested) {
|
|
||||||
b.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return AqlValue(b);
|
return AqlValue(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -321,6 +321,8 @@ struct Functions {
|
||||||
VPackFunctionParameters const&);
|
VPackFunctionParameters const&);
|
||||||
static AqlValue GeoLinestring(arangodb::aql::Query*, transaction::Methods*,
|
static AqlValue GeoLinestring(arangodb::aql::Query*, transaction::Methods*,
|
||||||
VPackFunctionParameters const&);
|
VPackFunctionParameters const&);
|
||||||
|
static AqlValue GeoMultiPolygon(arangodb::aql::Query*, transaction::Methods*,
|
||||||
|
VPackFunctionParameters const&);
|
||||||
static AqlValue GeoMultiLinestring(arangodb::aql::Query*, transaction::Methods*,
|
static AqlValue GeoMultiLinestring(arangodb::aql::Query*, transaction::Methods*,
|
||||||
VPackFunctionParameters const&);
|
VPackFunctionParameters const&);
|
||||||
static AqlValue Flatten(arangodb::aql::Query*, transaction::Methods*,
|
static AqlValue Flatten(arangodb::aql::Query*, transaction::Methods*,
|
||||||
|
|
Loading…
Reference in New Issue