mirror of
https://github.com/elastic/elasticsearch.git
synced 2025-04-24 23:27:25 -04:00
This commit moves the legacy geo_shape implementation to its own module and removes the dependency on Spatial4J / JTS from server.
This commit is contained in:
parent
ca5480b9a8
commit
82dc997010
81 changed files with 5634 additions and 3780 deletions
|
@ -11,9 +11,9 @@ package org.elasticsearch.client.documentation;
|
||||||
import org.apache.lucene.search.join.ScoreMode;
|
import org.apache.lucene.search.join.ScoreMode;
|
||||||
import org.elasticsearch.common.geo.GeoPoint;
|
import org.elasticsearch.common.geo.GeoPoint;
|
||||||
import org.elasticsearch.common.geo.ShapeRelation;
|
import org.elasticsearch.common.geo.ShapeRelation;
|
||||||
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiPointBuilder;
|
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
|
import org.elasticsearch.geometry.MultiPoint;
|
||||||
|
import org.elasticsearch.geometry.Point;
|
||||||
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
|
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
|
||||||
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
|
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
|
||||||
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder.FilterFunctionBuilder;
|
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder.FilterFunctionBuilder;
|
||||||
|
@ -178,16 +178,16 @@ public class QueryDSLDocumentationTests extends ESTestCase {
|
||||||
public void testGeoShape() throws IOException {
|
public void testGeoShape() throws IOException {
|
||||||
{
|
{
|
||||||
// tag::geo_shape
|
// tag::geo_shape
|
||||||
|
List<Point> points = new ArrayList<>();
|
||||||
|
points.add(new Point(0, 0));
|
||||||
|
points.add(new Point(0, 10));
|
||||||
|
points.add(new Point(10, 10));
|
||||||
|
points.add(new Point(10, 0));
|
||||||
|
points.add(new Point(0, 0));
|
||||||
GeoShapeQueryBuilder qb = geoShapeQuery(
|
GeoShapeQueryBuilder qb = geoShapeQuery(
|
||||||
"pin.location", // <1>
|
"pin.location", // <1>
|
||||||
new MultiPointBuilder( // <2>
|
new MultiPoint(points) // <2>
|
||||||
new CoordinatesBuilder()
|
);
|
||||||
.coordinate(0, 0)
|
|
||||||
.coordinate(0, 10)
|
|
||||||
.coordinate(10, 10)
|
|
||||||
.coordinate(10, 0)
|
|
||||||
.coordinate(0, 0)
|
|
||||||
.build()));
|
|
||||||
qb.relation(ShapeRelation.WITHIN); // <3>
|
qb.relation(ShapeRelation.WITHIN); // <3>
|
||||||
// end::geo_shape
|
// end::geo_shape
|
||||||
}
|
}
|
||||||
|
|
53
modules/legacy-geo/build.gradle
Normal file
53
modules/legacy-geo/build.gradle
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
apply plugin: 'elasticsearch.internal-cluster-test'
|
||||||
|
apply plugin: 'nebula.optional-base'
|
||||||
|
|
||||||
|
esplugin {
|
||||||
|
description 'Placeholder plugin for geospatial features in ES'
|
||||||
|
classname 'org.elasticsearch.legacygeo.LegacyGeoPlugin'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api "org.apache.lucene:lucene-spatial-extras:${versions.lucene}"
|
||||||
|
api "org.locationtech.spatial4j:spatial4j:${versions.spatial4j}", optional
|
||||||
|
api "org.locationtech.jts:jts-core:${versions.jts}", optional
|
||||||
|
testImplementation project(":test:framework")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("thirdPartyAudit").configure {
|
||||||
|
ignoreMissingClasses(
|
||||||
|
|
||||||
|
// from org.locationtech.spatial4j.io.GeoJSONReader (spatial4j)
|
||||||
|
'org.noggit.JSONParser',
|
||||||
|
|
||||||
|
// from org.locationtech.spatial4j.io.jackson.ShapeAsGeoJSONSerialize
|
||||||
|
'com.fasterxml.jackson.databind.JsonSerializer',
|
||||||
|
'com.fasterxml.jackson.databind.JsonDeserializer',
|
||||||
|
'com.fasterxml.jackson.databind.node.ArrayNode',
|
||||||
|
'com.fasterxml.jackson.databind.DeserializationContext',
|
||||||
|
'com.fasterxml.jackson.databind.JsonNode',
|
||||||
|
'com.fasterxml.jackson.databind.SerializerProvider',
|
||||||
|
'com.fasterxml.jackson.databind.module.SimpleModule',
|
||||||
|
'com.fasterxml.jackson.databind.node.ObjectNode',
|
||||||
|
|
||||||
|
// from lucene-spatial
|
||||||
|
'com.google.common.geometry.S2Cell',
|
||||||
|
'com.google.common.geometry.S2CellId',
|
||||||
|
'com.google.common.geometry.S2Projections',
|
||||||
|
'com.google.common.geometry.S2Point',
|
||||||
|
'com.google.common.geometry.S2$Metric',
|
||||||
|
'com.google.common.geometry.S2LatLng'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("dependencyLicenses").configure {
|
||||||
|
mapping from: /lucene-.*/, to: 'lucene'
|
||||||
|
}
|
||||||
|
|
475
modules/legacy-geo/licenses/lucene-LICENSE.txt
Normal file
475
modules/legacy-geo/licenses/lucene-LICENSE.txt
Normal file
|
@ -0,0 +1,475 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Some code in core/src/java/org/apache/lucene/util/UnicodeUtil.java was
|
||||||
|
derived from unicode conversion examples available at
|
||||||
|
http://www.unicode.org/Public/PROGRAMS/CVTUTF. Here is the copyright
|
||||||
|
from those sources:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2001-2004 Unicode, Inc.
|
||||||
|
*
|
||||||
|
* Disclaimer
|
||||||
|
*
|
||||||
|
* This source code is provided as is by Unicode, Inc. No claims are
|
||||||
|
* made as to fitness for any particular purpose. No warranties of any
|
||||||
|
* kind are expressed or implied. The recipient agrees to determine
|
||||||
|
* applicability of information provided. If this file has been
|
||||||
|
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||||
|
* sole remedy for any claim will be exchange of defective media
|
||||||
|
* within 90 days of receipt.
|
||||||
|
*
|
||||||
|
* Limitations on Rights to Redistribute This Code
|
||||||
|
*
|
||||||
|
* Unicode, Inc. hereby grants the right to freely use the information
|
||||||
|
* supplied in this file in the creation of products supporting the
|
||||||
|
* Unicode Standard, and to make copies of this file in any form
|
||||||
|
* for internal or external distribution as long as this notice
|
||||||
|
* remains attached.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
Some code in core/src/java/org/apache/lucene/util/ArrayUtil.java was
|
||||||
|
derived from Python 2.4.2 sources available at
|
||||||
|
http://www.python.org. Full license is here:
|
||||||
|
|
||||||
|
http://www.python.org/download/releases/2.4.2/license/
|
||||||
|
|
||||||
|
Some code in core/src/java/org/apache/lucene/util/UnicodeUtil.java was
|
||||||
|
derived from Python 3.1.2 sources available at
|
||||||
|
http://www.python.org. Full license is here:
|
||||||
|
|
||||||
|
http://www.python.org/download/releases/3.1.2/license/
|
||||||
|
|
||||||
|
Some code in core/src/java/org/apache/lucene/util/automaton was
|
||||||
|
derived from Brics automaton sources available at
|
||||||
|
www.brics.dk/automaton/. Here is the copyright from those sources:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2009 Anders Moeller
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
The levenshtein automata tables in core/src/java/org/apache/lucene/util/automaton
|
||||||
|
were automatically generated with the moman/finenight FSA package.
|
||||||
|
Here is the copyright for those sources:
|
||||||
|
|
||||||
|
# Copyright (c) 2010, Jean-Philippe Barrette-LaPierre, <jpb@rrette.com>
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person
|
||||||
|
# obtaining a copy of this software and associated documentation
|
||||||
|
# files (the "Software"), to deal in the Software without
|
||||||
|
# restriction, including without limitation the rights to use,
|
||||||
|
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the
|
||||||
|
# Software is furnished to do so, subject to the following
|
||||||
|
# conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be
|
||||||
|
# included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Some code in core/src/java/org/apache/lucene/util/UnicodeUtil.java was
|
||||||
|
derived from ICU (http://www.icu-project.org)
|
||||||
|
The full license is available here:
|
||||||
|
http://source.icu-project.org/repos/icu/icu/trunk/license.html
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 1999-2010, International Business Machines
|
||||||
|
* Corporation and others. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* provided that the above copyright notice(s) and this permission notice appear
|
||||||
|
* in all copies of the Software and that both the above copyright notice(s) and
|
||||||
|
* this permission notice appear in supporting documentation.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE
|
||||||
|
* LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR
|
||||||
|
* ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||||
|
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
* Except as contained in this notice, the name of a copyright holder shall not
|
||||||
|
* be used in advertising or otherwise to promote the sale, use or other
|
||||||
|
* dealings in this Software without prior written authorization of the
|
||||||
|
* copyright holder.
|
||||||
|
*/
|
||||||
|
|
||||||
|
The following license applies to the Snowball stemmers:
|
||||||
|
|
||||||
|
Copyright (c) 2001, Dr Martin Porter
|
||||||
|
Copyright (c) 2002, Richard Boulton
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holders nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
The following license applies to the KStemmer:
|
||||||
|
|
||||||
|
Copyright © 2003,
|
||||||
|
Center for Intelligent Information Retrieval,
|
||||||
|
University of Massachusetts, Amherst.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. The names "Center for Intelligent Information Retrieval" and
|
||||||
|
"University of Massachusetts" must not be used to endorse or promote products
|
||||||
|
derived from this software without prior written permission. To obtain
|
||||||
|
permission, contact info@ciir.cs.umass.edu.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF MASSACHUSETTS AND OTHER CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||||
|
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
The following license applies to the Morfologik project:
|
||||||
|
|
||||||
|
Copyright (c) 2006 Dawid Weiss
|
||||||
|
Copyright (c) 2007-2011 Dawid Weiss, Marcin Miłkowski
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of Morfologik nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The dictionary comes from Morfologik project. Morfologik uses data from
|
||||||
|
Polish ispell/myspell dictionary hosted at http://www.sjp.pl/slownik/en/ and
|
||||||
|
is licenced on the terms of (inter alia) LGPL and Creative Commons
|
||||||
|
ShareAlike. The part-of-speech tags were added in Morfologik project and
|
||||||
|
are not found in the data from sjp.pl. The tagset is similar to IPI PAN
|
||||||
|
tagset.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
The following license applies to the Morfeusz project,
|
||||||
|
used by org.apache.lucene.analysis.morfologik.
|
||||||
|
|
||||||
|
BSD-licensed dictionary of Polish (SGJP)
|
||||||
|
http://sgjp.pl/morfeusz/
|
||||||
|
|
||||||
|
Copyright © 2011 Zygmunt Saloni, Włodzimierz Gruszczyński,
|
||||||
|
Marcin Woliński, Robert Wołosz
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDERS “AS IS” AND ANY EXPRESS
|
||||||
|
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||||
|
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
192
modules/legacy-geo/licenses/lucene-NOTICE.txt
Normal file
192
modules/legacy-geo/licenses/lucene-NOTICE.txt
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
Apache Lucene
|
||||||
|
Copyright 2014 The Apache Software Foundation
|
||||||
|
|
||||||
|
This product includes software developed at
|
||||||
|
The Apache Software Foundation (http://www.apache.org/).
|
||||||
|
|
||||||
|
Includes software from other Apache Software Foundation projects,
|
||||||
|
including, but not limited to:
|
||||||
|
- Apache Ant
|
||||||
|
- Apache Jakarta Regexp
|
||||||
|
- Apache Commons
|
||||||
|
- Apache Xerces
|
||||||
|
|
||||||
|
ICU4J, (under analysis/icu) is licensed under an MIT styles license
|
||||||
|
and Copyright (c) 1995-2008 International Business Machines Corporation and others
|
||||||
|
|
||||||
|
Some data files (under analysis/icu/src/data) are derived from Unicode data such
|
||||||
|
as the Unicode Character Database. See http://unicode.org/copyright.html for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
Brics Automaton (under core/src/java/org/apache/lucene/util/automaton) is
|
||||||
|
BSD-licensed, created by Anders Møller. See http://www.brics.dk/automaton/
|
||||||
|
|
||||||
|
The levenshtein automata tables (under core/src/java/org/apache/lucene/util/automaton) were
|
||||||
|
automatically generated with the moman/finenight FSA library, created by
|
||||||
|
Jean-Philippe Barrette-LaPierre. This library is available under an MIT license,
|
||||||
|
see http://sites.google.com/site/rrettesite/moman and
|
||||||
|
http://bitbucket.org/jpbarrette/moman/overview/
|
||||||
|
|
||||||
|
The class org.apache.lucene.util.WeakIdentityMap was derived from
|
||||||
|
the Apache CXF project and is Apache License 2.0.
|
||||||
|
|
||||||
|
The Google Code Prettify is Apache License 2.0.
|
||||||
|
See http://code.google.com/p/google-code-prettify/
|
||||||
|
|
||||||
|
JUnit (junit-4.10) is licensed under the Common Public License v. 1.0
|
||||||
|
See http://junit.sourceforge.net/cpl-v10.html
|
||||||
|
|
||||||
|
This product includes code (JaspellTernarySearchTrie) from Java Spelling Checkin
|
||||||
|
g Package (jaspell): http://jaspell.sourceforge.net/
|
||||||
|
License: The BSD License (http://www.opensource.org/licenses/bsd-license.php)
|
||||||
|
|
||||||
|
The snowball stemmers in
|
||||||
|
analysis/common/src/java/net/sf/snowball
|
||||||
|
were developed by Martin Porter and Richard Boulton.
|
||||||
|
The snowball stopword lists in
|
||||||
|
analysis/common/src/resources/org/apache/lucene/analysis/snowball
|
||||||
|
were developed by Martin Porter and Richard Boulton.
|
||||||
|
The full snowball package is available from
|
||||||
|
http://snowball.tartarus.org/
|
||||||
|
|
||||||
|
The KStem stemmer in
|
||||||
|
analysis/common/src/org/apache/lucene/analysis/en
|
||||||
|
was developed by Bob Krovetz and Sergio Guzman-Lara (CIIR-UMass Amherst)
|
||||||
|
under the BSD-license.
|
||||||
|
|
||||||
|
The Arabic,Persian,Romanian,Bulgarian, Hindi and Bengali analyzers (common) come with a default
|
||||||
|
stopword list that is BSD-licensed created by Jacques Savoy. These files reside in:
|
||||||
|
analysis/common/src/resources/org/apache/lucene/analysis/ar/stopwords.txt,
|
||||||
|
analysis/common/src/resources/org/apache/lucene/analysis/fa/stopwords.txt,
|
||||||
|
analysis/common/src/resources/org/apache/lucene/analysis/ro/stopwords.txt,
|
||||||
|
analysis/common/src/resources/org/apache/lucene/analysis/bg/stopwords.txt,
|
||||||
|
analysis/common/src/resources/org/apache/lucene/analysis/hi/stopwords.txt,
|
||||||
|
analysis/common/src/resources/org/apache/lucene/analysis/bn/stopwords.txt
|
||||||
|
See http://members.unine.ch/jacques.savoy/clef/index.html.
|
||||||
|
|
||||||
|
The German,Spanish,Finnish,French,Hungarian,Italian,Portuguese,Russian and Swedish light stemmers
|
||||||
|
(common) are based on BSD-licensed reference implementations created by Jacques Savoy and
|
||||||
|
Ljiljana Dolamic. These files reside in:
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/de/GermanLightStemmer.java
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/de/GermanMinimalStemmer.java
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/es/SpanishLightStemmer.java
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/fi/FinnishLightStemmer.java
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/fr/FrenchLightStemmer.java
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/fr/FrenchMinimalStemmer.java
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/hu/HungarianLightStemmer.java
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/it/ItalianLightStemmer.java
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/pt/PortugueseLightStemmer.java
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/ru/RussianLightStemmer.java
|
||||||
|
analysis/common/src/java/org/apache/lucene/analysis/sv/SwedishLightStemmer.java
|
||||||
|
|
||||||
|
The Stempel analyzer (stempel) includes BSD-licensed software developed
|
||||||
|
by the Egothor project http://egothor.sf.net/, created by Leo Galambos, Martin Kvapil,
|
||||||
|
and Edmond Nolan.
|
||||||
|
|
||||||
|
The Polish analyzer (stempel) comes with a default
|
||||||
|
stopword list that is BSD-licensed created by the Carrot2 project. The file resides
|
||||||
|
in stempel/src/resources/org/apache/lucene/analysis/pl/stopwords.txt.
|
||||||
|
See http://project.carrot2.org/license.html.
|
||||||
|
|
||||||
|
The SmartChineseAnalyzer source code (smartcn) was
|
||||||
|
provided by Xiaoping Gao and copyright 2009 by www.imdict.net.
|
||||||
|
|
||||||
|
WordBreakTestUnicode_*.java (under modules/analysis/common/src/test/)
|
||||||
|
is derived from Unicode data such as the Unicode Character Database.
|
||||||
|
See http://unicode.org/copyright.html for more details.
|
||||||
|
|
||||||
|
The Morfologik analyzer (morfologik) includes BSD-licensed software
|
||||||
|
developed by Dawid Weiss and Marcin Miłkowski (http://morfologik.blogspot.com/).
|
||||||
|
|
||||||
|
Morfologik uses data from Polish ispell/myspell dictionary
|
||||||
|
(http://www.sjp.pl/slownik/en/) licenced on the terms of (inter alia)
|
||||||
|
LGPL and Creative Commons ShareAlike.
|
||||||
|
|
||||||
|
Morfologic includes data from BSD-licensed dictionary of Polish (SGJP)
|
||||||
|
(http://sgjp.pl/morfeusz/)
|
||||||
|
|
||||||
|
Servlet-api.jar and javax.servlet-*.jar are under the CDDL license, the original
|
||||||
|
source code for this can be found at http://www.eclipse.org/jetty/downloads.php
|
||||||
|
|
||||||
|
===========================================================================
|
||||||
|
Kuromoji Japanese Morphological Analyzer - Apache Lucene Integration
|
||||||
|
===========================================================================
|
||||||
|
|
||||||
|
This software includes a binary and/or source version of data from
|
||||||
|
|
||||||
|
mecab-ipadic-2.7.0-20070801
|
||||||
|
|
||||||
|
which can be obtained from
|
||||||
|
|
||||||
|
http://atilika.com/releases/mecab-ipadic/mecab-ipadic-2.7.0-20070801.tar.gz
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
http://jaist.dl.sourceforge.net/project/mecab/mecab-ipadic/2.7.0-20070801/mecab-ipadic-2.7.0-20070801.tar.gz
|
||||||
|
|
||||||
|
===========================================================================
|
||||||
|
mecab-ipadic-2.7.0-20070801 Notice
|
||||||
|
===========================================================================
|
||||||
|
|
||||||
|
Nara Institute of Science and Technology (NAIST),
|
||||||
|
the copyright holders, disclaims all warranties with regard to this
|
||||||
|
software, including all implied warranties of merchantability and
|
||||||
|
fitness, in no event shall NAIST be liable for
|
||||||
|
any special, indirect or consequential damages or any damages
|
||||||
|
whatsoever resulting from loss of use, data or profits, whether in an
|
||||||
|
action of contract, negligence or other tortuous action, arising out
|
||||||
|
of or in connection with the use or performance of this software.
|
||||||
|
|
||||||
|
A large portion of the dictionary entries
|
||||||
|
originate from ICOT Free Software. The following conditions for ICOT
|
||||||
|
Free Software applies to the current dictionary as well.
|
||||||
|
|
||||||
|
Each User may also freely distribute the Program, whether in its
|
||||||
|
original form or modified, to any third party or parties, PROVIDED
|
||||||
|
that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear
|
||||||
|
on, or be attached to, the Program, which is distributed substantially
|
||||||
|
in the same form as set out herein and that such intended
|
||||||
|
distribution, if actually made, will neither violate or otherwise
|
||||||
|
contravene any of the laws and regulations of the countries having
|
||||||
|
jurisdiction over the User or the intended distribution itself.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
The program was produced on an experimental basis in the course of the
|
||||||
|
research and development conducted during the project and is provided
|
||||||
|
to users as so produced on an experimental basis. Accordingly, the
|
||||||
|
program is provided without any warranty whatsoever, whether express,
|
||||||
|
implied, statutory or otherwise. The term "warranty" used herein
|
||||||
|
includes, but is not limited to, any warranty of the quality,
|
||||||
|
performance, merchantability and fitness for a particular purpose of
|
||||||
|
the program and the nonexistence of any infringement or violation of
|
||||||
|
any right of any third party.
|
||||||
|
|
||||||
|
Each user of the program will agree and understand, and be deemed to
|
||||||
|
have agreed and understood, that there is no warranty whatsoever for
|
||||||
|
the program and, accordingly, the entire risk arising from or
|
||||||
|
otherwise connected with the program is assumed by the user.
|
||||||
|
|
||||||
|
Therefore, neither ICOT, the copyright holder, or any other
|
||||||
|
organization that participated in or was otherwise related to the
|
||||||
|
development of the program and their respective officials, directors,
|
||||||
|
officers and other employees shall be held liable for any and all
|
||||||
|
damages, including, without limitation, general, special, incidental
|
||||||
|
and consequential damages, arising out of or otherwise in connection
|
||||||
|
with the use or inability to use the program or any product, material
|
||||||
|
or result produced or otherwise obtained by using the program,
|
||||||
|
regardless of whether they have been advised of, or otherwise had
|
||||||
|
knowledge of, the possibility of such damages at any time during the
|
||||||
|
project or thereafter. Each user will be deemed to have agreed to the
|
||||||
|
foregoing by his or her commencement of use of the program. The term
|
||||||
|
"use" as used herein includes, but is not limited to, the use,
|
||||||
|
modification, copying and distribution of the program and the
|
||||||
|
production of secondary products from the program.
|
||||||
|
|
||||||
|
In the case where the program, whether in its original form or
|
||||||
|
modified, was distributed or delivered to or received by a user from
|
||||||
|
any person, organization or entity other than ICOT, unless it makes or
|
||||||
|
grants independently of ICOT any specific warranty to the user in
|
||||||
|
writing, such person, organization or entity, will also be exempted
|
||||||
|
from and not be held liable to the user for any such damages as noted
|
||||||
|
above as far as the program is concerned.
|
|
@ -6,12 +6,13 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.search.geo;
|
package org.elasticsearch.legacygeo.search;
|
||||||
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
|
import org.elasticsearch.legacygeo.test.TestLegacyGeoShapeFieldMapperPlugin;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
import org.elasticsearch.test.TestLegacyGeoShapeFieldMapperPlugin;
|
import org.elasticsearch.search.geo.GeoBoundingBoxQueryIntegTestCase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -31,9 +32,16 @@ public class GeoBoundingBoxQueryLegacyGeoShapeIT extends GeoBoundingBoxQueryInte
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder getMapping() throws IOException {
|
public XContentBuilder getMapping() throws IOException {
|
||||||
return XContentFactory.jsonBuilder().startObject().startObject("type1")
|
return XContentFactory.jsonBuilder()
|
||||||
.startObject("properties").startObject("location").field("type", "geo_shape").field("strategy", "recursive")
|
.startObject()
|
||||||
.endObject().endObject().endObject().endObject();
|
.startObject("type1")
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject("location")
|
||||||
|
.field("type", "geo_shape")
|
||||||
|
.field("strategy", "recursive")
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,15 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.search.geo;
|
package org.elasticsearch.legacygeo.search;
|
||||||
|
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.geometry.Circle;
|
import org.elasticsearch.geometry.Circle;
|
||||||
|
import org.elasticsearch.legacygeo.test.TestLegacyGeoShapeFieldMapperPlugin;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
import org.elasticsearch.test.TestLegacyGeoShapeFieldMapperPlugin;
|
import org.elasticsearch.search.geo.GeoShapeIntegTestCase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -51,21 +52,23 @@ public class LegacyGeoShapeIT extends GeoShapeIntegTestCase {
|
||||||
*/
|
*/
|
||||||
public void testLegacyCircle() throws Exception {
|
public void testLegacyCircle() throws Exception {
|
||||||
// create index
|
// create index
|
||||||
assertAcked(prepareCreate("test")
|
assertAcked(prepareCreate("test").addMapping("shape", "shape", "type=geo_shape,strategy=recursive,tree=geohash").get());
|
||||||
.addMapping("shape", "shape", "type=geo_shape,strategy=recursive,tree=geohash").get());
|
|
||||||
ensureGreen();
|
ensureGreen();
|
||||||
|
|
||||||
indexRandom(true, client().prepareIndex("test", "shape").setId("0").setSource("shape", (ToXContent) (builder, params) -> {
|
indexRandom(true, client().prepareIndex("test", "shape").setId("0").setSource("shape", (ToXContent) (builder, params) -> {
|
||||||
builder.startObject().field("type", "circle")
|
builder.startObject()
|
||||||
.startArray("coordinates").value(30).value(50).endArray()
|
.field("type", "circle")
|
||||||
.field("radius","77km")
|
.startArray("coordinates")
|
||||||
|
.value(30)
|
||||||
|
.value(50)
|
||||||
|
.endArray()
|
||||||
|
.field("radius", "77km")
|
||||||
.endObject();
|
.endObject();
|
||||||
return builder;
|
return builder;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// test self crossing of circles
|
// test self crossing of circles
|
||||||
SearchResponse searchResponse = client().prepareSearch("test").setQuery(geoShapeQuery("shape",
|
SearchResponse searchResponse = client().prepareSearch("test").setQuery(geoShapeQuery("shape", new Circle(30, 50, 77000))).get();
|
||||||
new Circle(30, 50, 77000))).get();
|
|
||||||
assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
|
assertThat(searchResponse.getHits().getTotalHits().value, equalTo(1L));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,23 +5,24 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.common.geo;
|
package org.elasticsearch.legacygeo;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.geo.builders.CircleBuilder;
|
import org.elasticsearch.common.geo.Orientation;
|
||||||
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.EnvelopeBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiLineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiPointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiPolygonBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PolygonBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.elasticsearch.common.geo.parsers.CoordinateNode;
|
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry;
|
import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry;
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
|
import org.elasticsearch.legacygeo.builders.CircleBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.CoordinatesBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.EnvelopeBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.GeometryCollectionBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.LineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiLineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiPointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiPolygonBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PolygonBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.ShapeBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.CoordinateNode;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -36,8 +37,7 @@ import java.util.Map;
|
||||||
public enum GeoShapeType {
|
public enum GeoShapeType {
|
||||||
POINT("point") {
|
POINT("point") {
|
||||||
@Override
|
@Override
|
||||||
public PointBuilder getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
|
public PointBuilder getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius, Orientation orientation, boolean coerce) {
|
||||||
Orientation orientation, boolean coerce) {
|
|
||||||
return new PointBuilder().coordinate(validate(coordinates, coerce).coordinate);
|
return new PointBuilder().coordinate(validate(coordinates, coerce).coordinate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,8 @@ public enum GeoShapeType {
|
||||||
CoordinateNode validate(CoordinateNode coordinates, boolean coerce) {
|
CoordinateNode validate(CoordinateNode coordinates, boolean coerce) {
|
||||||
if (coordinates.isEmpty()) {
|
if (coordinates.isEmpty()) {
|
||||||
throw new ElasticsearchParseException(
|
throw new ElasticsearchParseException(
|
||||||
"invalid number of points (0) provided when expecting a single coordinate ([lat, lng])");
|
"invalid number of points (0) provided when expecting a single coordinate ([lat, lng])"
|
||||||
|
);
|
||||||
} else if (coordinates.children != null) {
|
} else if (coordinates.children != null) {
|
||||||
throw new ElasticsearchParseException("multipoint data provided when single point data expected.");
|
throw new ElasticsearchParseException("multipoint data provided when single point data expected.");
|
||||||
}
|
}
|
||||||
|
@ -54,8 +55,12 @@ public enum GeoShapeType {
|
||||||
},
|
},
|
||||||
MULTIPOINT("multipoint") {
|
MULTIPOINT("multipoint") {
|
||||||
@Override
|
@Override
|
||||||
public MultiPointBuilder getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
|
public MultiPointBuilder getBuilder(
|
||||||
Orientation orientation, boolean coerce) {
|
CoordinateNode coordinates,
|
||||||
|
DistanceUnit.Distance radius,
|
||||||
|
Orientation orientation,
|
||||||
|
boolean coerce
|
||||||
|
) {
|
||||||
validate(coordinates, coerce);
|
validate(coordinates, coerce);
|
||||||
CoordinatesBuilder coordinatesBuilder = new CoordinatesBuilder();
|
CoordinatesBuilder coordinatesBuilder = new CoordinatesBuilder();
|
||||||
for (CoordinateNode node : coordinates.children) {
|
for (CoordinateNode node : coordinates.children) {
|
||||||
|
@ -68,11 +73,14 @@ public enum GeoShapeType {
|
||||||
CoordinateNode validate(CoordinateNode coordinates, boolean coerce) {
|
CoordinateNode validate(CoordinateNode coordinates, boolean coerce) {
|
||||||
if (coordinates.children == null || coordinates.children.isEmpty()) {
|
if (coordinates.children == null || coordinates.children.isEmpty()) {
|
||||||
if (coordinates.coordinate != null) {
|
if (coordinates.coordinate != null) {
|
||||||
throw new ElasticsearchParseException("single coordinate found when expecting an array of " +
|
throw new ElasticsearchParseException(
|
||||||
"coordinates. change type to point or change data to an array of >0 coordinates");
|
"single coordinate found when expecting an array of "
|
||||||
|
+ "coordinates. change type to point or change data to an array of >0 coordinates"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
throw new ElasticsearchParseException("no data provided for multipoint object when expecting " +
|
throw new ElasticsearchParseException(
|
||||||
">0 points (e.g., [[lat, lng]] or [[lat, lng], ...])");
|
"no data provided for multipoint object when expecting " + ">0 points (e.g., [[lat, lng]] or [[lat, lng], ...])"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
for (CoordinateNode point : coordinates.children) {
|
for (CoordinateNode point : coordinates.children) {
|
||||||
POINT.validate(point, coerce);
|
POINT.validate(point, coerce);
|
||||||
|
@ -84,8 +92,12 @@ public enum GeoShapeType {
|
||||||
},
|
},
|
||||||
LINESTRING("linestring") {
|
LINESTRING("linestring") {
|
||||||
@Override
|
@Override
|
||||||
public LineStringBuilder getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
|
public LineStringBuilder getBuilder(
|
||||||
Orientation orientation, boolean coerce) {
|
CoordinateNode coordinates,
|
||||||
|
DistanceUnit.Distance radius,
|
||||||
|
Orientation orientation,
|
||||||
|
boolean coerce
|
||||||
|
) {
|
||||||
validate(coordinates, coerce);
|
validate(coordinates, coerce);
|
||||||
CoordinatesBuilder line = new CoordinatesBuilder();
|
CoordinatesBuilder line = new CoordinatesBuilder();
|
||||||
for (CoordinateNode node : coordinates.children) {
|
for (CoordinateNode node : coordinates.children) {
|
||||||
|
@ -97,16 +109,22 @@ public enum GeoShapeType {
|
||||||
@Override
|
@Override
|
||||||
CoordinateNode validate(CoordinateNode coordinates, boolean coerce) {
|
CoordinateNode validate(CoordinateNode coordinates, boolean coerce) {
|
||||||
if (coordinates.children.size() < 2) {
|
if (coordinates.children.size() < 2) {
|
||||||
throw new ElasticsearchParseException("invalid number of points in LineString (found [{}] - must be >= 2)",
|
throw new ElasticsearchParseException(
|
||||||
coordinates.children.size());
|
"invalid number of points in LineString (found [{}] - must be >= 2)",
|
||||||
|
coordinates.children.size()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return coordinates;
|
return coordinates;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MULTILINESTRING("multilinestring") {
|
MULTILINESTRING("multilinestring") {
|
||||||
@Override
|
@Override
|
||||||
public MultiLineStringBuilder getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
|
public MultiLineStringBuilder getBuilder(
|
||||||
Orientation orientation, boolean coerce) {
|
CoordinateNode coordinates,
|
||||||
|
DistanceUnit.Distance radius,
|
||||||
|
Orientation orientation,
|
||||||
|
boolean coerce
|
||||||
|
) {
|
||||||
validate(coordinates, coerce);
|
validate(coordinates, coerce);
|
||||||
MultiLineStringBuilder multiline = new MultiLineStringBuilder();
|
MultiLineStringBuilder multiline = new MultiLineStringBuilder();
|
||||||
for (CoordinateNode node : coordinates.children) {
|
for (CoordinateNode node : coordinates.children) {
|
||||||
|
@ -118,20 +136,27 @@ public enum GeoShapeType {
|
||||||
@Override
|
@Override
|
||||||
CoordinateNode validate(CoordinateNode coordinates, boolean coerce) {
|
CoordinateNode validate(CoordinateNode coordinates, boolean coerce) {
|
||||||
if (coordinates.children.size() < 1) {
|
if (coordinates.children.size() < 1) {
|
||||||
throw new ElasticsearchParseException("invalid number of lines in MultiLineString (found [{}] - must be >= 1)",
|
throw new ElasticsearchParseException(
|
||||||
coordinates.children.size());
|
"invalid number of lines in MultiLineString (found [{}] - must be >= 1)",
|
||||||
|
coordinates.children.size()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return coordinates;
|
return coordinates;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
POLYGON("polygon") {
|
POLYGON("polygon") {
|
||||||
@Override
|
@Override
|
||||||
public PolygonBuilder getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
|
public PolygonBuilder getBuilder(
|
||||||
Orientation orientation, boolean coerce) {
|
CoordinateNode coordinates,
|
||||||
|
DistanceUnit.Distance radius,
|
||||||
|
Orientation orientation,
|
||||||
|
boolean coerce
|
||||||
|
) {
|
||||||
validate(coordinates, coerce);
|
validate(coordinates, coerce);
|
||||||
// build shell
|
// build shell
|
||||||
LineStringBuilder shell = LineStringBuilder.class.cast(LINESTRING.getBuilder(coordinates.children.get(0),
|
LineStringBuilder shell = LineStringBuilder.class.cast(
|
||||||
radius, orientation, coerce));
|
LINESTRING.getBuilder(coordinates.children.get(0), radius, orientation, coerce)
|
||||||
|
);
|
||||||
// build polygon with shell and holes
|
// build polygon with shell and holes
|
||||||
PolygonBuilder polygon = new PolygonBuilder(shell, orientation);
|
PolygonBuilder polygon = new PolygonBuilder(shell, orientation);
|
||||||
for (int i = 1; i < coordinates.children.size(); ++i) {
|
for (int i = 1; i < coordinates.children.size(); ++i) {
|
||||||
|
@ -145,19 +170,24 @@ public enum GeoShapeType {
|
||||||
void validateLinearRing(CoordinateNode coordinates, boolean coerce) {
|
void validateLinearRing(CoordinateNode coordinates, boolean coerce) {
|
||||||
if (coordinates.children == null || coordinates.children.isEmpty()) {
|
if (coordinates.children == null || coordinates.children.isEmpty()) {
|
||||||
String error = "Invalid LinearRing found.";
|
String error = "Invalid LinearRing found.";
|
||||||
error += (coordinates.coordinate == null) ?
|
error += (coordinates.coordinate == null)
|
||||||
" No coordinate array provided" : " Found a single coordinate when expecting a coordinate array";
|
? " No coordinate array provided"
|
||||||
|
: " Found a single coordinate when expecting a coordinate array";
|
||||||
throw new ElasticsearchParseException(error);
|
throw new ElasticsearchParseException(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int numValidPts = coerce ? 3 : 4;
|
int numValidPts = coerce ? 3 : 4;
|
||||||
if (coordinates.children.size() < numValidPts) {
|
if (coordinates.children.size() < numValidPts) {
|
||||||
throw new ElasticsearchParseException("invalid number of points in LinearRing (found [{}] - must be >= [{}])",
|
throw new ElasticsearchParseException(
|
||||||
coordinates.children.size(), numValidPts);
|
"invalid number of points in LinearRing (found [{}] - must be >= [{}])",
|
||||||
|
coordinates.children.size(),
|
||||||
|
numValidPts
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// close linear ring iff coerce is set and ring is open, otherwise throw parse exception
|
// close linear ring iff coerce is set and ring is open, otherwise throw parse exception
|
||||||
if (coordinates.children.get(0).coordinate.equals(
|
if (coordinates.children.get(0).coordinate.equals(
|
||||||
coordinates.children.get(coordinates.children.size() - 1).coordinate) == false) {
|
coordinates.children.get(coordinates.children.size() - 1).coordinate
|
||||||
|
) == false) {
|
||||||
if (coerce) {
|
if (coerce) {
|
||||||
coordinates.children.add(coordinates.children.get(0));
|
coordinates.children.add(coordinates.children.get(0));
|
||||||
} else {
|
} else {
|
||||||
|
@ -176,7 +206,8 @@ public enum GeoShapeType {
|
||||||
*/
|
*/
|
||||||
if (coordinates.children == null || coordinates.children.isEmpty()) {
|
if (coordinates.children == null || coordinates.children.isEmpty()) {
|
||||||
throw new ElasticsearchParseException(
|
throw new ElasticsearchParseException(
|
||||||
"invalid LinearRing provided for type polygon. Linear ring must be an array of coordinates");
|
"invalid LinearRing provided for type polygon. Linear ring must be an array of coordinates"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for (CoordinateNode ring : coordinates.children) {
|
for (CoordinateNode ring : coordinates.children) {
|
||||||
validateLinearRing(ring, coerce);
|
validateLinearRing(ring, coerce);
|
||||||
|
@ -187,8 +218,12 @@ public enum GeoShapeType {
|
||||||
},
|
},
|
||||||
MULTIPOLYGON("multipolygon") {
|
MULTIPOLYGON("multipolygon") {
|
||||||
@Override
|
@Override
|
||||||
public MultiPolygonBuilder getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
|
public MultiPolygonBuilder getBuilder(
|
||||||
Orientation orientation, boolean coerce) {
|
CoordinateNode coordinates,
|
||||||
|
DistanceUnit.Distance radius,
|
||||||
|
Orientation orientation,
|
||||||
|
boolean coerce
|
||||||
|
) {
|
||||||
validate(coordinates, coerce);
|
validate(coordinates, coerce);
|
||||||
MultiPolygonBuilder polygons = new MultiPolygonBuilder(orientation);
|
MultiPolygonBuilder polygons = new MultiPolygonBuilder(orientation);
|
||||||
for (CoordinateNode node : coordinates.children) {
|
for (CoordinateNode node : coordinates.children) {
|
||||||
|
@ -205,8 +240,12 @@ public enum GeoShapeType {
|
||||||
},
|
},
|
||||||
ENVELOPE("envelope") {
|
ENVELOPE("envelope") {
|
||||||
@Override
|
@Override
|
||||||
public EnvelopeBuilder getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
|
public EnvelopeBuilder getBuilder(
|
||||||
Orientation orientation, boolean coerce) {
|
CoordinateNode coordinates,
|
||||||
|
DistanceUnit.Distance radius,
|
||||||
|
Orientation orientation,
|
||||||
|
boolean coerce
|
||||||
|
) {
|
||||||
validate(coordinates, coerce);
|
validate(coordinates, coerce);
|
||||||
// verify coordinate bounds, correct if necessary
|
// verify coordinate bounds, correct if necessary
|
||||||
Coordinate uL = coordinates.children.get(0).coordinate;
|
Coordinate uL = coordinates.children.get(0).coordinate;
|
||||||
|
@ -220,7 +259,9 @@ public enum GeoShapeType {
|
||||||
if (coordinates.children.size() != 2) {
|
if (coordinates.children.size() != 2) {
|
||||||
throw new ElasticsearchParseException(
|
throw new ElasticsearchParseException(
|
||||||
"invalid number of points [{}] provided for geo_shape [{}] when expecting an array of 2 coordinates",
|
"invalid number of points [{}] provided for geo_shape [{}] when expecting an array of 2 coordinates",
|
||||||
coordinates.children.size(), GeoShapeType.ENVELOPE.shapename);
|
coordinates.children.size(),
|
||||||
|
GeoShapeType.ENVELOPE.shapename
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return coordinates;
|
return coordinates;
|
||||||
}
|
}
|
||||||
|
@ -232,8 +273,7 @@ public enum GeoShapeType {
|
||||||
},
|
},
|
||||||
CIRCLE("circle") {
|
CIRCLE("circle") {
|
||||||
@Override
|
@Override
|
||||||
public CircleBuilder getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
|
public CircleBuilder getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius, Orientation orientation, boolean coerce) {
|
||||||
Orientation orientation, boolean coerce) {
|
|
||||||
return new CircleBuilder().center(coordinates.coordinate).radius(radius);
|
return new CircleBuilder().center(coordinates.coordinate).radius(radius);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -246,8 +286,12 @@ public enum GeoShapeType {
|
||||||
},
|
},
|
||||||
GEOMETRYCOLLECTION("geometrycollection") {
|
GEOMETRYCOLLECTION("geometrycollection") {
|
||||||
@Override
|
@Override
|
||||||
public ShapeBuilder<?, ?, ?> getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
|
public ShapeBuilder<?, ?, ?> getBuilder(
|
||||||
Orientation orientation, boolean coerce) {
|
CoordinateNode coordinates,
|
||||||
|
DistanceUnit.Distance radius,
|
||||||
|
Orientation orientation,
|
||||||
|
boolean coerce
|
||||||
|
) {
|
||||||
// noop, handled in parser
|
// noop, handled in parser
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -283,11 +327,16 @@ public enum GeoShapeType {
|
||||||
if (shapeTypeMap.containsKey(typename)) {
|
if (shapeTypeMap.containsKey(typename)) {
|
||||||
return shapeTypeMap.get(typename);
|
return shapeTypeMap.get(typename);
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("unknown geo_shape ["+geoshapename+"]");
|
throw new IllegalArgumentException("unknown geo_shape [" + geoshapename + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract ShapeBuilder<?, ?, ?> getBuilder(CoordinateNode coordinates, DistanceUnit.Distance radius,
|
public abstract ShapeBuilder<?, ?, ?> getBuilder(
|
||||||
Orientation orientation, boolean coerce);
|
CoordinateNode coordinates,
|
||||||
|
DistanceUnit.Distance radius,
|
||||||
|
Orientation orientation,
|
||||||
|
boolean coerce
|
||||||
|
);
|
||||||
|
|
||||||
abstract CoordinateNode validate(CoordinateNode coordinates, boolean coerce);
|
abstract CoordinateNode validate(CoordinateNode coordinates, boolean coerce);
|
||||||
|
|
||||||
/** wkt shape name */
|
/** wkt shape name */
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.legacygeo;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||||
|
import org.elasticsearch.plugins.ExtensiblePlugin;
|
||||||
|
import org.elasticsearch.plugins.Plugin;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class LegacyGeoPlugin extends Plugin implements ExtensiblePlugin {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
|
||||||
|
if (ShapesAvailability.JTS_AVAILABLE && ShapesAvailability.SPATIAL4J_AVAILABLE) {
|
||||||
|
return new ArrayList<>(GeoShapeType.getShapeWriteables());
|
||||||
|
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo;
|
package org.elasticsearch.legacygeo;
|
||||||
|
|
||||||
public class ShapesAvailability {
|
public class ShapesAvailability {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo;
|
package org.elasticsearch.legacygeo;
|
||||||
|
|
||||||
import org.locationtech.spatial4j.context.SpatialContext;
|
import org.locationtech.spatial4j.context.SpatialContext;
|
||||||
import org.locationtech.spatial4j.shape.Shape;
|
import org.locationtech.spatial4j.shape.Shape;
|
||||||
|
@ -19,17 +19,17 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class XShapeCollection<S extends Shape> extends ShapeCollection<S> {
|
public class XShapeCollection<S extends Shape> extends ShapeCollection<S> {
|
||||||
|
|
||||||
private boolean pointsOnly = false;
|
private boolean pointsOnly = false;
|
||||||
|
|
||||||
public XShapeCollection(List<S> shapes, SpatialContext ctx) {
|
public XShapeCollection(List<S> shapes, SpatialContext ctx) {
|
||||||
super(shapes, ctx);
|
super(shapes, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean pointsOnly() {
|
public boolean pointsOnly() {
|
||||||
return this.pointsOnly;
|
return this.pointsOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPointsOnly(boolean pointsOnly) {
|
public void setPointsOnly(boolean pointsOnly) {
|
||||||
this.pointsOnly = pointsOnly;
|
this.pointsOnly = pointsOnly;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,19 +6,18 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.common.xcontent.ParseField;
|
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.locationtech.spatial4j.shape.Circle;
|
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
import org.elasticsearch.common.unit.DistanceUnit.Distance;
|
import org.elasticsearch.common.unit.DistanceUnit.Distance;
|
||||||
|
import org.elasticsearch.common.xcontent.ParseField;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
import org.locationtech.spatial4j.shape.Circle;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -154,7 +153,7 @@ public class CircleBuilder extends ShapeBuilder<Circle, org.elasticsearch.geomet
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public org.elasticsearch.geometry.Circle buildGeometry() {
|
public org.elasticsearch.geometry.Circle buildGeometry() {
|
||||||
return new org.elasticsearch.geometry.Circle(center.x, center.y, unit.toMeters(radius));
|
return new org.elasticsearch.geometry.Circle(center.x, center.y, unit.toMeters(radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -185,8 +184,8 @@ public class CircleBuilder extends ShapeBuilder<Circle, org.elasticsearch.geomet
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CircleBuilder other = (CircleBuilder) obj;
|
CircleBuilder other = (CircleBuilder) obj;
|
||||||
return Objects.equals(center, other.center) &&
|
return Objects.equals(center, other.center)
|
||||||
Objects.equals(radius, other.radius) &&
|
&& Objects.equals(radius, other.radius)
|
||||||
Objects.equals(unit.ordinal(), other.unit.ordinal());
|
&& Objects.equals(unit.ordinal(), other.unit.ordinal());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,10 +6,10 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -34,9 +34,12 @@ public class CoordinatesBuilder {
|
||||||
int expectedDims;
|
int expectedDims;
|
||||||
int actualDims;
|
int actualDims;
|
||||||
if (points.isEmpty() == false
|
if (points.isEmpty() == false
|
||||||
&& (expectedDims = Double.isNaN(points.get(0).z) ? 2 : 3) != (actualDims = Double.isNaN(coordinate.z) ? 2 : 3)) {
|
&& (expectedDims = Double.isNaN(points.get(0).z) ? 2 : 3) != (actualDims = Double.isNaN(coordinate.z) ? 2 : 3)) {
|
||||||
throw new ElasticsearchException("unable to add coordinate to CoordinateBuilder: " +
|
throw new ElasticsearchException(
|
||||||
"coordinate dimensions do not match. Expected [{}] but found [{}]", expectedDims, actualDims);
|
"unable to add coordinate to CoordinateBuilder: " + "coordinate dimensions do not match. Expected [{}] but found [{}]",
|
||||||
|
expectedDims,
|
||||||
|
actualDims
|
||||||
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.points.add(coordinate);
|
this.points.add(coordinate);
|
||||||
|
@ -60,7 +63,7 @@ public class CoordinatesBuilder {
|
||||||
* @param coordinates array of {@link Coordinate}s to add
|
* @param coordinates array of {@link Coordinate}s to add
|
||||||
* @return this
|
* @return this
|
||||||
*/
|
*/
|
||||||
public CoordinatesBuilder coordinates(Coordinate...coordinates) {
|
public CoordinatesBuilder coordinates(Coordinate... coordinates) {
|
||||||
return this.coordinates(Arrays.asList(coordinates));
|
return this.coordinates(Arrays.asList(coordinates));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,8 +84,8 @@ public class CoordinatesBuilder {
|
||||||
*/
|
*/
|
||||||
public CoordinatesBuilder close() {
|
public CoordinatesBuilder close() {
|
||||||
Coordinate start = points.get(0);
|
Coordinate start = points.get(0);
|
||||||
Coordinate end = points.get(points.size()-1);
|
Coordinate end = points.get(points.size() - 1);
|
||||||
if(start.x != end.x || start.y != end.y) {
|
if (start.x != end.x || start.y != end.y) {
|
||||||
points.add(start);
|
points.add(start);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
|
@ -6,17 +6,16 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.parsers.GeoWKTParser;
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.locationtech.spatial4j.shape.Rectangle;
|
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.GeoWKTParser;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
import org.locationtech.spatial4j.shape.Rectangle;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -130,7 +129,6 @@ public class EnvelopeBuilder extends ShapeBuilder<Rectangle, org.elasticsearch.g
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
EnvelopeBuilder other = (EnvelopeBuilder) obj;
|
EnvelopeBuilder other = (EnvelopeBuilder) obj;
|
||||||
return Objects.equals(topLeft, other.topLeft) &&
|
return Objects.equals(topLeft, other.topLeft) && Objects.equals(bottomRight, other.bottomRight);
|
||||||
Objects.equals(bottomRight, other.bottomRight);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,18 +6,18 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.XShapeCollection;
|
|
||||||
import org.elasticsearch.common.geo.parsers.GeoWKTParser;
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.geometry.Geometry;
|
import org.elasticsearch.geometry.Geometry;
|
||||||
import org.elasticsearch.geometry.GeometryCollection;
|
import org.elasticsearch.geometry.GeometryCollection;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.XShapeCollection;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.GeoWKTParser;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
import org.locationtech.spatial4j.shape.Shape;
|
import org.locationtech.spatial4j.shape.Shape;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -25,8 +25,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class GeometryCollectionBuilder extends ShapeBuilder<Shape,
|
public class GeometryCollectionBuilder extends ShapeBuilder<Shape, GeometryCollection<Geometry>, GeometryCollectionBuilder> {
|
||||||
GeometryCollection<Geometry>, GeometryCollectionBuilder> {
|
|
||||||
|
|
||||||
public static final GeoShapeType TYPE = GeoShapeType.GEOMETRYCOLLECTION;
|
public static final GeoShapeType TYPE = GeoShapeType.GEOMETRYCOLLECTION;
|
||||||
|
|
||||||
|
@ -38,8 +37,7 @@ public class GeometryCollectionBuilder extends ShapeBuilder<Shape,
|
||||||
/**
|
/**
|
||||||
* Build and empty GeometryCollectionBuilder.
|
* Build and empty GeometryCollectionBuilder.
|
||||||
*/
|
*/
|
||||||
public GeometryCollectionBuilder() {
|
public GeometryCollectionBuilder() {}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read from a stream.
|
* Read from a stream.
|
||||||
|
@ -106,8 +104,9 @@ public class GeometryCollectionBuilder extends ShapeBuilder<Shape,
|
||||||
|
|
||||||
public ShapeBuilder<?, ?, ?> getShapeAt(int i) {
|
public ShapeBuilder<?, ?, ?> getShapeAt(int i) {
|
||||||
if (i >= this.shapes.size() || i < 0) {
|
if (i >= this.shapes.size() || i < 0) {
|
||||||
throw new ElasticsearchException("GeometryCollection contains " + this.shapes.size() + " shapes. + " +
|
throw new ElasticsearchException(
|
||||||
"No shape found at index " + i);
|
"GeometryCollection contains " + this.shapes.size() + " shapes. + " + "No shape found at index " + i
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return this.shapes.get(i);
|
return this.shapes.get(i);
|
||||||
}
|
}
|
||||||
|
@ -153,8 +152,7 @@ public class GeometryCollectionBuilder extends ShapeBuilder<Shape,
|
||||||
@Override
|
@Override
|
||||||
public int numDimensions() {
|
public int numDimensions() {
|
||||||
if (shapes == null || shapes.isEmpty()) {
|
if (shapes == null || shapes.isEmpty()) {
|
||||||
throw new IllegalStateException("unable to get number of dimensions, " +
|
throw new IllegalStateException("unable to get number of dimensions, " + "GeometryCollection has not yet been initialized");
|
||||||
"GeometryCollection has not yet been initialized");
|
|
||||||
}
|
}
|
||||||
return shapes.get(0).numDimensions();
|
return shapes.get(0).numDimensions();
|
||||||
}
|
}
|
||||||
|
@ -168,11 +166,9 @@ public class GeometryCollectionBuilder extends ShapeBuilder<Shape,
|
||||||
shapes.add(shape.buildS4J());
|
shapes.add(shape.buildS4J());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shapes.size() == 1)
|
if (shapes.size() == 1) return shapes.get(0);
|
||||||
return shapes.get(0);
|
else return new XShapeCollection<>(shapes, SPATIAL_CONTEXT);
|
||||||
else
|
// note: ShapeCollection is probably faster than a Multi* geom.
|
||||||
return new XShapeCollection<>(shapes, SPATIAL_CONTEXT);
|
|
||||||
//note: ShapeCollection is probably faster than a Multi* geom.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -6,13 +6,13 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.geometry.Line;
|
import org.elasticsearch.geometry.Line;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.jts.geom.Geometry;
|
import org.locationtech.jts.geom.Geometry;
|
||||||
import org.locationtech.jts.geom.GeometryFactory;
|
import org.locationtech.jts.geom.GeometryFactory;
|
||||||
|
@ -37,7 +37,9 @@ public class LineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasticsear
|
||||||
public LineStringBuilder(List<Coordinate> coordinates) {
|
public LineStringBuilder(List<Coordinate> coordinates) {
|
||||||
super(coordinates);
|
super(coordinates);
|
||||||
if (coordinates.size() < 2) {
|
if (coordinates.size() < 2) {
|
||||||
throw new IllegalArgumentException("invalid number of points in LineString (found [" + coordinates.size()+ "] - must be >= 2)");
|
throw new IllegalArgumentException(
|
||||||
|
"invalid number of points in LineString (found [" + coordinates.size() + "] - must be >= 2)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +71,7 @@ public class LineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasticsear
|
||||||
public LineStringBuilder close() {
|
public LineStringBuilder close() {
|
||||||
Coordinate start = coordinates.get(0);
|
Coordinate start = coordinates.get(0);
|
||||||
Coordinate end = coordinates.get(coordinates.size() - 1);
|
Coordinate end = coordinates.get(coordinates.size() - 1);
|
||||||
if(start.x != end.x || start.y != end.y) {
|
if (start.x != end.x || start.y != end.y) {
|
||||||
coordinates.add(start);
|
coordinates.add(start);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -83,8 +85,7 @@ public class LineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasticsear
|
||||||
@Override
|
@Override
|
||||||
public int numDimensions() {
|
public int numDimensions() {
|
||||||
if (coordinates == null || coordinates.isEmpty()) {
|
if (coordinates == null || coordinates.isEmpty()) {
|
||||||
throw new IllegalStateException("unable to get number of dimensions, " +
|
throw new IllegalStateException("unable to get number of dimensions, " + "LineString has not yet been initialized");
|
||||||
"LineString has not yet been initialized");
|
|
||||||
}
|
}
|
||||||
return Double.isNaN(coordinates.get(0).z) ? 2 : 3;
|
return Double.isNaN(coordinates.get(0).z) ? 2 : 3;
|
||||||
}
|
}
|
||||||
|
@ -93,10 +94,10 @@ public class LineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasticsear
|
||||||
public JtsGeometry buildS4J() {
|
public JtsGeometry buildS4J() {
|
||||||
Coordinate[] coordinates = this.coordinates.toArray(new Coordinate[this.coordinates.size()]);
|
Coordinate[] coordinates = this.coordinates.toArray(new Coordinate[this.coordinates.size()]);
|
||||||
Geometry geometry;
|
Geometry geometry;
|
||||||
if(wrapdateline) {
|
if (wrapdateline) {
|
||||||
ArrayList<LineString> strings = decomposeS4J(FACTORY, coordinates, new ArrayList<LineString>());
|
ArrayList<LineString> strings = decomposeS4J(FACTORY, coordinates, new ArrayList<LineString>());
|
||||||
|
|
||||||
if(strings.size() == 1) {
|
if (strings.size() == 1) {
|
||||||
geometry = strings.get(0);
|
geometry = strings.get(0);
|
||||||
} else {
|
} else {
|
||||||
LineString[] linestrings = strings.toArray(new LineString[strings.size()]);
|
LineString[] linestrings = strings.toArray(new LineString[strings.size()]);
|
||||||
|
@ -111,13 +112,12 @@ public class LineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasticsear
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public org.elasticsearch.geometry.Geometry buildGeometry() {
|
public org.elasticsearch.geometry.Geometry buildGeometry() {
|
||||||
return new Line(coordinates.stream().mapToDouble(i->i.x).toArray(), coordinates.stream().mapToDouble(i->i.y).toArray()
|
return new Line(coordinates.stream().mapToDouble(i -> i.x).toArray(), coordinates.stream().mapToDouble(i -> i.y).toArray());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ArrayList<LineString> decomposeS4J(GeometryFactory factory, Coordinate[] coordinates, ArrayList<LineString> strings) {
|
static ArrayList<LineString> decomposeS4J(GeometryFactory factory, Coordinate[] coordinates, ArrayList<LineString> strings) {
|
||||||
for(Coordinate[] part : decompose(+DATELINE, coordinates)) {
|
for (Coordinate[] part : decompose(+DATELINE, coordinates)) {
|
||||||
for(Coordinate[] line : decompose(-DATELINE, part)) {
|
for (Coordinate[] line : decompose(-DATELINE, part)) {
|
||||||
strings.add(factory.createLineString(line));
|
strings.add(factory.createLineString(line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,35 +138,35 @@ public class LineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasticsear
|
||||||
double shift = coordinates[0].x > DATELINE ? DATELINE : (coordinates[0].x < -DATELINE ? -DATELINE : 0);
|
double shift = coordinates[0].x > DATELINE ? DATELINE : (coordinates[0].x < -DATELINE ? -DATELINE : 0);
|
||||||
|
|
||||||
for (int i = 1; i < coordinates.length; i++) {
|
for (int i = 1; i < coordinates.length; i++) {
|
||||||
double t = intersection(coordinates[i-1], coordinates[i], dateline);
|
double t = intersection(coordinates[i - 1], coordinates[i], dateline);
|
||||||
if(Double.isNaN(t) == false) {
|
if (Double.isNaN(t) == false) {
|
||||||
Coordinate[] part;
|
Coordinate[] part;
|
||||||
if(t<1) {
|
if (t < 1) {
|
||||||
part = Arrays.copyOfRange(coordinates, offset, i+1);
|
part = Arrays.copyOfRange(coordinates, offset, i + 1);
|
||||||
part[part.length-1] = Edge.position(coordinates[i-1], coordinates[i], t);
|
part[part.length - 1] = Edge.position(coordinates[i - 1], coordinates[i], t);
|
||||||
coordinates[offset+i-1] = Edge.position(coordinates[i-1], coordinates[i], t);
|
coordinates[offset + i - 1] = Edge.position(coordinates[i - 1], coordinates[i], t);
|
||||||
shift(shift, part);
|
shift(shift, part);
|
||||||
offset = i-1;
|
offset = i - 1;
|
||||||
shift = coordinates[i].x > DATELINE ? DATELINE : (coordinates[i].x < -DATELINE ? -DATELINE : 0);
|
shift = coordinates[i].x > DATELINE ? DATELINE : (coordinates[i].x < -DATELINE ? -DATELINE : 0);
|
||||||
} else {
|
} else {
|
||||||
part = shift(shift, Arrays.copyOfRange(coordinates, offset, i+1));
|
part = shift(shift, Arrays.copyOfRange(coordinates, offset, i + 1));
|
||||||
offset = i;
|
offset = i;
|
||||||
}
|
}
|
||||||
parts.add(part);
|
parts.add(part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(offset == 0) {
|
if (offset == 0) {
|
||||||
parts.add(shift(shift, coordinates));
|
parts.add(shift(shift, coordinates));
|
||||||
} else if(offset < coordinates.length-1) {
|
} else if (offset < coordinates.length - 1) {
|
||||||
Coordinate[] part = Arrays.copyOfRange(coordinates, offset, coordinates.length);
|
Coordinate[] part = Arrays.copyOfRange(coordinates, offset, coordinates.length);
|
||||||
parts.add(shift(shift, part));
|
parts.add(shift(shift, part));
|
||||||
}
|
}
|
||||||
return parts.toArray(new Coordinate[parts.size()][]);
|
return parts.toArray(new Coordinate[parts.size()][]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Coordinate[] shift(double shift, Coordinate...coordinates) {
|
private static Coordinate[] shift(double shift, Coordinate... coordinates) {
|
||||||
if(shift != 0) {
|
if (shift != 0) {
|
||||||
for (int j = 0; j < coordinates.length; j++) {
|
for (int j = 0; j < coordinates.length; j++) {
|
||||||
coordinates[j] = new Coordinate(coordinates[j].x - 2 * shift, coordinates[j].y);
|
coordinates[j] = new Coordinate(coordinates[j].x - 2 * shift, coordinates[j].y);
|
||||||
}
|
}
|
|
@ -6,16 +6,16 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.parsers.GeoWKTParser;
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.geometry.Line;
|
import org.elasticsearch.geometry.Line;
|
||||||
import org.elasticsearch.geometry.MultiLine;
|
import org.elasticsearch.geometry.MultiLine;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.GeoWKTParser;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.jts.geom.Geometry;
|
import org.locationtech.jts.geom.Geometry;
|
||||||
import org.locationtech.jts.geom.LineString;
|
import org.locationtech.jts.geom.LineString;
|
||||||
|
@ -94,8 +94,7 @@ public class MultiLineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasti
|
||||||
|
|
||||||
public int numDimensions() {
|
public int numDimensions() {
|
||||||
if (lines == null || lines.isEmpty()) {
|
if (lines == null || lines.isEmpty()) {
|
||||||
throw new IllegalStateException("unable to get number of dimensions, " +
|
throw new IllegalStateException("unable to get number of dimensions, " + "LineStrings have not yet been initialized");
|
||||||
"LineStrings have not yet been initialized");
|
|
||||||
}
|
}
|
||||||
return lines.get(0).numDimensions();
|
return lines.get(0).numDimensions();
|
||||||
}
|
}
|
||||||
|
@ -106,7 +105,7 @@ public class MultiLineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasti
|
||||||
builder.field(ShapeParser.FIELD_TYPE.getPreferredName(), TYPE.shapeName());
|
builder.field(ShapeParser.FIELD_TYPE.getPreferredName(), TYPE.shapeName());
|
||||||
builder.field(ShapeParser.FIELD_COORDINATES.getPreferredName());
|
builder.field(ShapeParser.FIELD_COORDINATES.getPreferredName());
|
||||||
builder.startArray();
|
builder.startArray();
|
||||||
for(LineStringBuilder line : lines) {
|
for (LineStringBuilder line : lines) {
|
||||||
line.coordinatesToXcontent(builder, false);
|
line.coordinatesToXcontent(builder, false);
|
||||||
}
|
}
|
||||||
builder.endArray();
|
builder.endArray();
|
||||||
|
@ -117,12 +116,12 @@ public class MultiLineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasti
|
||||||
@Override
|
@Override
|
||||||
public JtsGeometry buildS4J() {
|
public JtsGeometry buildS4J() {
|
||||||
final Geometry geometry;
|
final Geometry geometry;
|
||||||
if(wrapdateline) {
|
if (wrapdateline) {
|
||||||
ArrayList<LineString> parts = new ArrayList<>();
|
ArrayList<LineString> parts = new ArrayList<>();
|
||||||
for (LineStringBuilder line : lines) {
|
for (LineStringBuilder line : lines) {
|
||||||
LineStringBuilder.decomposeS4J(FACTORY, line.coordinates(false), parts);
|
LineStringBuilder.decomposeS4J(FACTORY, line.coordinates(false), parts);
|
||||||
}
|
}
|
||||||
if(parts.size() == 1) {
|
if (parts.size() == 1) {
|
||||||
geometry = parts.get(0);
|
geometry = parts.get(0);
|
||||||
} else {
|
} else {
|
||||||
LineString[] lineStrings = parts.toArray(new LineString[parts.size()]);
|
LineString[] lineStrings = parts.toArray(new LineString[parts.size()]);
|
||||||
|
@ -147,9 +146,9 @@ public class MultiLineStringBuilder extends ShapeBuilder<JtsGeometry, org.elasti
|
||||||
List<Line> linestrings = new ArrayList<>(lines.size());
|
List<Line> linestrings = new ArrayList<>(lines.size());
|
||||||
for (int i = 0; i < lines.size(); ++i) {
|
for (int i = 0; i < lines.size(); ++i) {
|
||||||
LineStringBuilder lsb = lines.get(i);
|
LineStringBuilder lsb = lines.get(i);
|
||||||
linestrings.add(new Line(lsb.coordinates.stream().mapToDouble(c->c.x).toArray(),
|
linestrings.add(
|
||||||
lsb.coordinates.stream().mapToDouble(c->c.y).toArray()
|
new Line(lsb.coordinates.stream().mapToDouble(c -> c.x).toArray(), lsb.coordinates.stream().mapToDouble(c -> c.y).toArray())
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
return new MultiLine(linestrings);
|
return new MultiLine(linestrings);
|
||||||
}
|
}
|
|
@ -6,14 +6,14 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.XShapeCollection;
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.geometry.MultiPoint;
|
import org.elasticsearch.geometry.MultiPoint;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.XShapeCollection;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.spatial4j.shape.Point;
|
import org.locationtech.spatial4j.shape.Point;
|
||||||
|
|
||||||
|
@ -60,8 +60,8 @@ public class MultiPointBuilder extends ShapeBuilder<XShapeCollection<Point>, Mul
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XShapeCollection<Point> buildS4J() {
|
public XShapeCollection<Point> buildS4J() {
|
||||||
//Could wrap JtsGeometry but probably slower due to conversions to/from JTS in relate()
|
// Could wrap JtsGeometry but probably slower due to conversions to/from JTS in relate()
|
||||||
//MultiPoint geometry = FACTORY.createMultiPoint(points.toArray(new Coordinate[points.size()]));
|
// MultiPoint geometry = FACTORY.createMultiPoint(points.toArray(new Coordinate[points.size()]));
|
||||||
List<Point> shapes = new ArrayList<>(coordinates.size());
|
List<Point> shapes = new ArrayList<>(coordinates.size());
|
||||||
for (Coordinate coord : coordinates) {
|
for (Coordinate coord : coordinates) {
|
||||||
shapes.add(SPATIAL_CONTEXT.makePoint(coord.x, coord.y));
|
shapes.add(SPATIAL_CONTEXT.makePoint(coord.x, coord.y));
|
||||||
|
@ -76,8 +76,9 @@ public class MultiPointBuilder extends ShapeBuilder<XShapeCollection<Point>, Mul
|
||||||
if (coordinates.isEmpty()) {
|
if (coordinates.isEmpty()) {
|
||||||
return MultiPoint.EMPTY;
|
return MultiPoint.EMPTY;
|
||||||
}
|
}
|
||||||
return new MultiPoint(coordinates.stream().map(coord -> new org.elasticsearch.geometry.Point(coord.x, coord.y))
|
return new MultiPoint(
|
||||||
.collect(Collectors.toList()));
|
coordinates.stream().map(coord -> new org.elasticsearch.geometry.Point(coord.x, coord.y)).collect(Collectors.toList())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -88,8 +89,7 @@ public class MultiPointBuilder extends ShapeBuilder<XShapeCollection<Point>, Mul
|
||||||
@Override
|
@Override
|
||||||
public int numDimensions() {
|
public int numDimensions() {
|
||||||
if (coordinates == null || coordinates.isEmpty()) {
|
if (coordinates == null || coordinates.isEmpty()) {
|
||||||
throw new IllegalStateException("unable to get number of dimensions, " +
|
throw new IllegalStateException("unable to get number of dimensions, " + "LineString has not yet been initialized");
|
||||||
"LineString has not yet been initialized");
|
|
||||||
}
|
}
|
||||||
return Double.isNaN(coordinates.get(0).z) ? 2 : 3;
|
return Double.isNaN(coordinates.get(0).z) ? 2 : 3;
|
||||||
}
|
}
|
|
@ -6,18 +6,18 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.XShapeCollection;
|
|
||||||
import org.elasticsearch.common.geo.Orientation;
|
import org.elasticsearch.common.geo.Orientation;
|
||||||
import org.elasticsearch.common.geo.parsers.GeoWKTParser;
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.geometry.MultiPolygon;
|
import org.elasticsearch.geometry.MultiPolygon;
|
||||||
import org.elasticsearch.geometry.Polygon;
|
import org.elasticsearch.geometry.Polygon;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.XShapeCollection;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.GeoWKTParser;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.spatial4j.shape.Shape;
|
import org.locationtech.spatial4j.shape.Shape;
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ public class MultiPolygonBuilder extends ShapeBuilder<Shape, MultiPolygon, Multi
|
||||||
builder.field(ShapeParser.FIELD_TYPE.getPreferredName(), TYPE.shapeName());
|
builder.field(ShapeParser.FIELD_TYPE.getPreferredName(), TYPE.shapeName());
|
||||||
builder.field(ShapeParser.FIELD_ORIENTATION.getPreferredName(), orientation.name().toLowerCase(Locale.ROOT));
|
builder.field(ShapeParser.FIELD_ORIENTATION.getPreferredName(), orientation.name().toLowerCase(Locale.ROOT));
|
||||||
builder.startArray(ShapeParser.FIELD_COORDINATES.getPreferredName());
|
builder.startArray(ShapeParser.FIELD_COORDINATES.getPreferredName());
|
||||||
for(PolygonBuilder polygon : polygons) {
|
for (PolygonBuilder polygon : polygons) {
|
||||||
builder.startArray();
|
builder.startArray();
|
||||||
polygon.coordinatesArray(builder, params);
|
polygon.coordinatesArray(builder, params);
|
||||||
builder.endArray();
|
builder.endArray();
|
||||||
|
@ -147,8 +147,7 @@ public class MultiPolygonBuilder extends ShapeBuilder<Shape, MultiPolygon, Multi
|
||||||
@Override
|
@Override
|
||||||
public int numDimensions() {
|
public int numDimensions() {
|
||||||
if (polygons == null || polygons.isEmpty()) {
|
if (polygons == null || polygons.isEmpty()) {
|
||||||
throw new IllegalStateException("unable to get number of dimensions, " +
|
throw new IllegalStateException("unable to get number of dimensions, " + "Polygons have not yet been initialized");
|
||||||
"Polygons have not yet been initialized");
|
|
||||||
}
|
}
|
||||||
return polygons.get(0).numDimensions();
|
return polygons.get(0).numDimensions();
|
||||||
}
|
}
|
||||||
|
@ -158,9 +157,9 @@ public class MultiPolygonBuilder extends ShapeBuilder<Shape, MultiPolygon, Multi
|
||||||
|
|
||||||
List<Shape> shapes = new ArrayList<>(this.polygons.size());
|
List<Shape> shapes = new ArrayList<>(this.polygons.size());
|
||||||
|
|
||||||
if(wrapdateline) {
|
if (wrapdateline) {
|
||||||
for (PolygonBuilder polygon : this.polygons) {
|
for (PolygonBuilder polygon : this.polygons) {
|
||||||
for(Coordinate[][] part : polygon.coordinates()) {
|
for (Coordinate[][] part : polygon.coordinates()) {
|
||||||
shapes.add(jtsGeometry(PolygonBuilder.polygonS4J(FACTORY, part)));
|
shapes.add(jtsGeometry(PolygonBuilder.polygonS4J(FACTORY, part)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,14 +168,12 @@ public class MultiPolygonBuilder extends ShapeBuilder<Shape, MultiPolygon, Multi
|
||||||
shapes.add(jtsGeometry(polygon.toPolygonS4J(FACTORY)));
|
shapes.add(jtsGeometry(polygon.toPolygonS4J(FACTORY)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shapes.size() == 1)
|
if (shapes.size() == 1) return shapes.get(0);
|
||||||
return shapes.get(0);
|
else return new XShapeCollection<>(shapes, SPATIAL_CONTEXT);
|
||||||
else
|
// note: ShapeCollection is probably faster than a Multi* geom.
|
||||||
return new XShapeCollection<>(shapes, SPATIAL_CONTEXT);
|
|
||||||
//note: ShapeCollection is probably faster than a Multi* geom.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({ "unchecked" })
|
||||||
@Override
|
@Override
|
||||||
public MultiPolygon buildGeometry() {
|
public MultiPolygon buildGeometry() {
|
||||||
List<Polygon> shapes = new ArrayList<>(this.polygons.size());
|
List<Polygon> shapes = new ArrayList<>(this.polygons.size());
|
||||||
|
@ -186,7 +183,7 @@ public class MultiPolygonBuilder extends ShapeBuilder<Shape, MultiPolygon, Multi
|
||||||
if (poly instanceof List) {
|
if (poly instanceof List) {
|
||||||
shapes.addAll((List<Polygon>) poly);
|
shapes.addAll((List<Polygon>) poly);
|
||||||
} else {
|
} else {
|
||||||
shapes.add((Polygon)poly);
|
shapes.add((Polygon) poly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shapes.isEmpty()) {
|
if (shapes.isEmpty()) {
|
||||||
|
@ -209,7 +206,6 @@ public class MultiPolygonBuilder extends ShapeBuilder<Shape, MultiPolygon, Multi
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MultiPolygonBuilder other = (MultiPolygonBuilder) obj;
|
MultiPolygonBuilder other = (MultiPolygonBuilder) obj;
|
||||||
return Objects.equals(polygons, other.polygons) &&
|
return Objects.equals(polygons, other.polygons) && Objects.equals(orientation, other.orientation);
|
||||||
Objects.equals(orientation, other.orientation);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,12 +6,12 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.spatial4j.shape.Point;
|
import org.locationtech.spatial4j.shape.Point;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ public class PointBuilder extends ShapeBuilder<Point, org.elasticsearch.geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
public PointBuilder(double lon, double lat) {
|
public PointBuilder(double lon, double lat) {
|
||||||
//super(new ArrayList<>(1));
|
// super(new ArrayList<>(1));
|
||||||
super();
|
super();
|
||||||
this.coordinates.add(new Coordinate(lon, lat));
|
this.coordinates.add(new Coordinate(lon, lat));
|
||||||
}
|
}
|
||||||
|
@ -64,11 +64,11 @@ public class PointBuilder extends ShapeBuilder<Point, org.elasticsearch.geometry
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
builder.field(ShapeParser.FIELD_TYPE.getPreferredName(), TYPE.shapeName());
|
builder.field(ShapeParser.FIELD_TYPE.getPreferredName(), TYPE.shapeName());
|
||||||
builder.field(ShapeParser.FIELD_COORDINATES.getPreferredName());
|
builder.field(ShapeParser.FIELD_COORDINATES.getPreferredName());
|
||||||
toXContent(builder, coordinates.get(0));
|
toXContent(builder, coordinates.get(0));
|
||||||
return builder.endObject();
|
return builder.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -6,16 +6,16 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.core.Tuple;
|
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.Orientation;
|
import org.elasticsearch.common.geo.Orientation;
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.util.set.Sets;
|
import org.elasticsearch.common.util.set.Sets;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.core.Tuple;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.jts.geom.Geometry;
|
import org.locationtech.jts.geom.Geometry;
|
||||||
import org.locationtech.jts.geom.GeometryFactory;
|
import org.locationtech.jts.geom.GeometryFactory;
|
||||||
|
@ -157,12 +157,11 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
*/
|
*/
|
||||||
List<Coordinate> points = lineString.coordinates;
|
List<Coordinate> points = lineString.coordinates;
|
||||||
if (points.size() < 4) {
|
if (points.size() < 4) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException("invalid number of points in LinearRing (found [" + points.size() + "] - must be >= 4)");
|
||||||
"invalid number of points in LinearRing (found [" + points.size() + "] - must be >= 4)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (points.get(0).equals(points.get(points.size() - 1)) == false) {
|
if (points.get(0).equals(points.get(points.size() - 1)) == false) {
|
||||||
throw new IllegalArgumentException("invalid LinearRing found (coordinates are not closed)");
|
throw new IllegalArgumentException("invalid LinearRing found (coordinates are not closed)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +202,7 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
final AtomicBoolean translated = new AtomicBoolean(false);
|
final AtomicBoolean translated = new AtomicBoolean(false);
|
||||||
int offset = createEdges(0, orientation, shell, null, edges, 0, translated);
|
int offset = createEdges(0, orientation, shell, null, edges, 0, translated);
|
||||||
for (int i = 0; i < holes.length; i++) {
|
for (int i = 0; i < holes.length; i++) {
|
||||||
int length = createEdges(i+1, orientation, shell, holes[i], edges, offset, translated);
|
int length = createEdges(i + 1, orientation, shell, holes[i], edges, offset, translated);
|
||||||
holeComponents[i] = edges[offset];
|
holeComponents[i] = edges[offset];
|
||||||
offset += length;
|
offset += length;
|
||||||
}
|
}
|
||||||
|
@ -230,9 +229,10 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
// same point
|
// same point
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (linearRing.coordinates.get(i - 1).x == linearRing.coordinates.get(i + 1).x &&
|
if (linearRing.coordinates.get(i - 1).x == linearRing.coordinates.get(i + 1).x
|
||||||
linearRing.coordinates.get(i - 1).y > linearRing.coordinates.get(i).y !=
|
&& linearRing.coordinates.get(i - 1).y > linearRing.coordinates.get(i).y != linearRing.coordinates.get(
|
||||||
linearRing.coordinates.get(i + 1).y > linearRing.coordinates.get(i).y) {
|
i + 1
|
||||||
|
).y > linearRing.coordinates.get(i).y) {
|
||||||
// coplanar
|
// coplanar
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -255,7 +255,7 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
|
|
||||||
protected XContentBuilder coordinatesArray(XContentBuilder builder, Params params) throws IOException {
|
protected XContentBuilder coordinatesArray(XContentBuilder builder, Params params) throws IOException {
|
||||||
shell.coordinatesToXcontent(builder, true);
|
shell.coordinatesToXcontent(builder, true);
|
||||||
for(LineStringBuilder hole : holes) {
|
for (LineStringBuilder hole : holes) {
|
||||||
hole.coordinatesToXcontent(builder, true);
|
hole.coordinatesToXcontent(builder, true);
|
||||||
}
|
}
|
||||||
return builder;
|
return builder;
|
||||||
|
@ -274,11 +274,9 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
}
|
}
|
||||||
|
|
||||||
public Geometry buildS4JGeometry(GeometryFactory factory, boolean fixDateline) {
|
public Geometry buildS4JGeometry(GeometryFactory factory, boolean fixDateline) {
|
||||||
if(fixDateline) {
|
if (fixDateline) {
|
||||||
Coordinate[][][] polygons = coordinates();
|
Coordinate[][][] polygons = coordinates();
|
||||||
return polygons.length == 1
|
return polygons.length == 1 ? polygonS4J(factory, polygons[0]) : multipolygonS4J(factory, polygons);
|
||||||
? polygonS4J(factory, polygons[0])
|
|
||||||
: multipolygonS4J(factory, polygons);
|
|
||||||
} else {
|
} else {
|
||||||
return toPolygonS4J(factory);
|
return toPolygonS4J(factory);
|
||||||
}
|
}
|
||||||
|
@ -307,7 +305,8 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static org.elasticsearch.geometry.LinearRing linearRing(List<Coordinate> coordinates) {
|
protected static org.elasticsearch.geometry.LinearRing linearRing(List<Coordinate> coordinates) {
|
||||||
return new org.elasticsearch.geometry.LinearRing(coordinates.stream().mapToDouble(i -> i.x).toArray(),
|
return new org.elasticsearch.geometry.LinearRing(
|
||||||
|
coordinates.stream().mapToDouble(i -> i.x).toArray(),
|
||||||
coordinates.stream().mapToDouble(i -> i.y).toArray()
|
coordinates.stream().mapToDouble(i -> i.y).toArray()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -324,8 +323,7 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
@Override
|
@Override
|
||||||
public int numDimensions() {
|
public int numDimensions() {
|
||||||
if (shell == null) {
|
if (shell == null) {
|
||||||
throw new IllegalStateException("unable to get number of dimensions, " +
|
throw new IllegalStateException("unable to get number of dimensions, " + "Polygon has not yet been initialized");
|
||||||
"Polygon has not yet been initialized");
|
|
||||||
}
|
}
|
||||||
return shell.numDimensions();
|
return shell.numDimensions();
|
||||||
}
|
}
|
||||||
|
@ -334,10 +332,10 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
LinearRing shell = factory.createLinearRing(polygon[0]);
|
LinearRing shell = factory.createLinearRing(polygon[0]);
|
||||||
LinearRing[] holes;
|
LinearRing[] holes;
|
||||||
|
|
||||||
if(polygon.length > 1) {
|
if (polygon.length > 1) {
|
||||||
holes = new LinearRing[polygon.length-1];
|
holes = new LinearRing[polygon.length - 1];
|
||||||
for (int i = 0; i < holes.length; i++) {
|
for (int i = 0; i < holes.length; i++) {
|
||||||
holes[i] = factory.createLinearRing(polygon[i+1]);
|
holes[i] = factory.createLinearRing(polygon[i + 1]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
holes = null;
|
holes = null;
|
||||||
|
@ -375,8 +373,8 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
private static int component(final Edge edge, final int id, final ArrayList<Edge> edges, double[] partitionPoint) {
|
private static int component(final Edge edge, final int id, final ArrayList<Edge> edges, double[] partitionPoint) {
|
||||||
// find a coordinate that is not part of the dateline
|
// find a coordinate that is not part of the dateline
|
||||||
Edge any = edge;
|
Edge any = edge;
|
||||||
while(any.coordinate.x == +DATELINE || any.coordinate.x == -DATELINE) {
|
while (any.coordinate.x == +DATELINE || any.coordinate.x == -DATELINE) {
|
||||||
if((any = any.next) == edge) {
|
if ((any = any.next) == edge) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,9 +435,9 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
prev = current;
|
prev = current;
|
||||||
}
|
}
|
||||||
length++;
|
length++;
|
||||||
} while(connectedComponents == 0 && (current = current.next) != edge);
|
} while (connectedComponents == 0 && (current = current.next) != edge);
|
||||||
|
|
||||||
return (splitIndex != 1) ? length-splitIndex: length;
|
return (splitIndex != 1) ? length - splitIndex : length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -455,11 +453,11 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
// First and last coordinates must be equal
|
// First and last coordinates must be equal
|
||||||
if (coordinates[0].equals(coordinates[coordinates.length - 1]) == false) {
|
if (coordinates[0].equals(coordinates[coordinates.length - 1]) == false) {
|
||||||
if (Double.isNaN(partitionPoint[2])) {
|
if (Double.isNaN(partitionPoint[2])) {
|
||||||
throw new InvalidShapeException("Self-intersection at or near point ["
|
throw new InvalidShapeException("Self-intersection at or near point [" + partitionPoint[0] + "," + partitionPoint[1] + "]");
|
||||||
+ partitionPoint[0] + "," + partitionPoint[1] + "]");
|
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidShapeException("Self-intersection at or near point ["
|
throw new InvalidShapeException(
|
||||||
+ partitionPoint[0] + "," + partitionPoint[1] + "," + partitionPoint[2] + "]");
|
"Self-intersection at or near point [" + partitionPoint[0] + "," + partitionPoint[1] + "," + partitionPoint[2] + "]"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return coordinates;
|
return coordinates;
|
||||||
|
@ -472,7 +470,7 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
result[i] = component.toArray(new Coordinate[component.size()][]);
|
result[i] = component.toArray(new Coordinate[component.size()][]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(debugEnabled()) {
|
if (debugEnabled()) {
|
||||||
for (int i = 0; i < result.length; i++) {
|
for (int i = 0; i < result.length; i++) {
|
||||||
LOGGER.debug("Component [{}]:", i);
|
LOGGER.debug("Component [{}]:", i);
|
||||||
for (int j = 0; j < result[i].length; j++) {
|
for (int j = 0; j < result[i].length; j++) {
|
||||||
|
@ -491,9 +489,9 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
final Coordinate[][] points = new Coordinate[numHoles][];
|
final Coordinate[][] points = new Coordinate[numHoles][];
|
||||||
|
|
||||||
for (int i = 0; i < numHoles; i++) {
|
for (int i = 0; i < numHoles; i++) {
|
||||||
double[] partitionPoint = new double[3];
|
double[] partitionPoint = new double[3];
|
||||||
int length = component(holes[i], -(i+1), null, partitionPoint); // mark as visited by inverting the sign
|
int length = component(holes[i], -(i + 1), null, partitionPoint); // mark as visited by inverting the sign
|
||||||
points[i] = coordinates(holes[i], new Coordinate[length+1], partitionPoint);
|
points[i] = coordinates(holes[i], new Coordinate[length + 1], partitionPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return points;
|
return points;
|
||||||
|
@ -504,10 +502,10 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
|
|
||||||
for (int i = 0; i < edges.length; i++) {
|
for (int i = 0; i < edges.length; i++) {
|
||||||
if (edges[i].component >= 0) {
|
if (edges[i].component >= 0) {
|
||||||
double[] partitionPoint = new double[3];
|
double[] partitionPoint = new double[3];
|
||||||
int length = component(edges[i], -(components.size()+numHoles+1), mainEdges, partitionPoint);
|
int length = component(edges[i], -(components.size() + numHoles + 1), mainEdges, partitionPoint);
|
||||||
List<Coordinate[]> component = new ArrayList<>();
|
List<Coordinate[]> component = new ArrayList<>();
|
||||||
component.add(coordinates(edges[i], new Coordinate[length+1], partitionPoint));
|
component.add(coordinates(edges[i], new Coordinate[length + 1], partitionPoint));
|
||||||
components.add(component);
|
components.add(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -583,7 +581,7 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
|
|
||||||
final int component = -edges[index].component - numHoles - 1;
|
final int component = -edges[index].component - numHoles - 1;
|
||||||
|
|
||||||
if(debugEnabled()) {
|
if (debugEnabled()) {
|
||||||
LOGGER.debug("\tposition ({}) of edge {}: {}", index, current, edges[index]);
|
LOGGER.debug("\tposition ({}) of edge {}: {}", index, current, edges[index]);
|
||||||
LOGGER.debug("\tComponent: {}", component);
|
LOGGER.debug("\tComponent: {}", component);
|
||||||
LOGGER.debug("\tHole intersections ({}): {}", current.coordinate.x, Arrays.toString(edges));
|
LOGGER.debug("\tHole intersections ({}): {}", current.coordinate.x, Arrays.toString(edges));
|
||||||
|
@ -608,14 +606,14 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
// the second edge only (the first edge is either polygon or
|
// the second edge only (the first edge is either polygon or
|
||||||
// already handled)
|
// already handled)
|
||||||
if (e2.component > 0) {
|
if (e2.component > 0) {
|
||||||
//TODO: Check if we could save the set null step
|
// TODO: Check if we could save the set null step
|
||||||
numHoles--;
|
numHoles--;
|
||||||
holes[e2.component-1] = holes[numHoles];
|
holes[e2.component - 1] = holes[numHoles];
|
||||||
holes[numHoles] = null;
|
holes[numHoles] = null;
|
||||||
}
|
}
|
||||||
// only connect edges if intersections are pairwise
|
// only connect edges if intersections are pairwise
|
||||||
// 1. per the comment above, the edge array is sorted by y-value of the intersection
|
// 1. per the comment above, the edge array is sorted by y-value of the intersection
|
||||||
// with the dateline. Two edges have the same y intercept when they cross the
|
// with the dateline. Two edges have the same y intercept when they cross the
|
||||||
// dateline thus they appear sequentially (pairwise) in the edge array. Two edges
|
// dateline thus they appear sequentially (pairwise) in the edge array. Two edges
|
||||||
// do not have the same y intercept when we're forming a multi-poly from a poly
|
// do not have the same y intercept when we're forming a multi-poly from a poly
|
||||||
// that wraps the dateline (but there are 2 ordered intercepts).
|
// that wraps the dateline (but there are 2 ordered intercepts).
|
||||||
|
@ -623,12 +621,14 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
// For boundary conditions (e.g., intersect but not crossing) there is no sibling edge
|
// For boundary conditions (e.g., intersect but not crossing) there is no sibling edge
|
||||||
// to connect. Thus the first logic check enforces the pairwise rule
|
// to connect. Thus the first logic check enforces the pairwise rule
|
||||||
// 2. the second logic check ensures the two candidate edges aren't already connected by an
|
// 2. the second logic check ensures the two candidate edges aren't already connected by an
|
||||||
// existing edge along the dateline - this is necessary due to a logic change in
|
// existing edge along the dateline - this is necessary due to a logic change in
|
||||||
// ShapeBuilder.intersection that computes dateline edges as valid intersect points
|
// ShapeBuilder.intersection that computes dateline edges as valid intersect points
|
||||||
// in support of OGC standards
|
// in support of OGC standards
|
||||||
if (e1.intersect != Edge.MAX_COORDINATE && e2.intersect != Edge.MAX_COORDINATE
|
if (e1.intersect != Edge.MAX_COORDINATE
|
||||||
&& (e1.next.next.coordinate.equals3D(e2.coordinate) && Math.abs(e1.next.coordinate.x) == DATELINE
|
&& e2.intersect != Edge.MAX_COORDINATE
|
||||||
&& Math.abs(e2.coordinate.x) == DATELINE) == false ) {
|
&& (e1.next.next.coordinate.equals3D(e2.coordinate)
|
||||||
|
&& Math.abs(e1.next.coordinate.x) == DATELINE
|
||||||
|
&& Math.abs(e2.coordinate.x) == DATELINE) == false) {
|
||||||
connect(e1, e2);
|
connect(e1, e2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -641,12 +641,12 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
// Connecting two Edges by inserting the point at
|
// Connecting two Edges by inserting the point at
|
||||||
// dateline intersection and connect these by adding
|
// dateline intersection and connect these by adding
|
||||||
// two edges between this points. One per direction
|
// two edges between this points. One per direction
|
||||||
if(in.intersect != in.next.coordinate) {
|
if (in.intersect != in.next.coordinate) {
|
||||||
// NOTE: the order of the object creation is crucial here! Don't change it!
|
// NOTE: the order of the object creation is crucial here! Don't change it!
|
||||||
// first edge has no point on dateline
|
// first edge has no point on dateline
|
||||||
Edge e1 = new Edge(in.intersect, in.next);
|
Edge e1 = new Edge(in.intersect, in.next);
|
||||||
|
|
||||||
if(out.intersect != out.next.coordinate) {
|
if (out.intersect != out.next.coordinate) {
|
||||||
// second edge has no point on dateline
|
// second edge has no point on dateline
|
||||||
Edge e2 = new Edge(out.intersect, out.next);
|
Edge e2 = new Edge(out.intersect, out.next);
|
||||||
in.next = new Edge(in.intersect, e2, in.intersect);
|
in.next = new Edge(in.intersect, e2, in.intersect);
|
||||||
|
@ -659,7 +659,7 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
// first edge intersects with dateline
|
// first edge intersects with dateline
|
||||||
Edge e2 = new Edge(out.intersect, in.next, out.intersect);
|
Edge e2 = new Edge(out.intersect, in.next, out.intersect);
|
||||||
|
|
||||||
if(out.intersect != out.next.coordinate) {
|
if (out.intersect != out.next.coordinate) {
|
||||||
// second edge has no point on dateline
|
// second edge has no point on dateline
|
||||||
Edge e1 = new Edge(out.intersect, out.next);
|
Edge e1 = new Edge(out.intersect, out.next);
|
||||||
in.next = new Edge(in.intersect, e1, in.intersect);
|
in.next = new Edge(in.intersect, e1, in.intersect);
|
||||||
|
@ -672,15 +672,22 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int createEdges(int component, Orientation orientation, LineStringBuilder shell,
|
private static int createEdges(
|
||||||
LineStringBuilder hole, Edge[] edges, int offset, final AtomicBoolean translated) {
|
int component,
|
||||||
|
Orientation orientation,
|
||||||
|
LineStringBuilder shell,
|
||||||
|
LineStringBuilder hole,
|
||||||
|
Edge[] edges,
|
||||||
|
int offset,
|
||||||
|
final AtomicBoolean translated
|
||||||
|
) {
|
||||||
// inner rings (holes) have an opposite direction than the outer rings
|
// inner rings (holes) have an opposite direction than the outer rings
|
||||||
// XOR will invert the orientation for outer ring cases (Truth Table:, T/T = F, T/F = T, F/T = T, F/F = F)
|
// XOR will invert the orientation for outer ring cases (Truth Table:, T/T = F, T/F = T, F/T = T, F/F = F)
|
||||||
boolean direction = (component == 0 ^ orientation == Orientation.RIGHT);
|
boolean direction = (component == 0 ^ orientation == Orientation.RIGHT);
|
||||||
// set the points array accordingly (shell or hole)
|
// set the points array accordingly (shell or hole)
|
||||||
Coordinate[] points = (hole != null) ? hole.coordinates(false) : shell.coordinates(false);
|
Coordinate[] points = (hole != null) ? hole.coordinates(false) : shell.coordinates(false);
|
||||||
ring(component, direction, orientation == Orientation.LEFT, points, 0, edges, offset, points.length-1, translated);
|
ring(component, direction, orientation == Orientation.LEFT, points, 0, edges, offset, points.length - 1, translated);
|
||||||
return points.length-1;
|
return points.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -694,8 +701,17 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
* number of points
|
* number of points
|
||||||
* @return Array of edges
|
* @return Array of edges
|
||||||
*/
|
*/
|
||||||
private static Edge[] ring(int component, boolean direction, boolean handedness,
|
private static Edge[] ring(
|
||||||
Coordinate[] points, int offset, Edge[] edges, int toffset, int length, final AtomicBoolean translated) {
|
int component,
|
||||||
|
boolean direction,
|
||||||
|
boolean handedness,
|
||||||
|
Coordinate[] points,
|
||||||
|
int offset,
|
||||||
|
Edge[] edges,
|
||||||
|
int toffset,
|
||||||
|
int length,
|
||||||
|
final AtomicBoolean translated
|
||||||
|
) {
|
||||||
double signedArea = 0;
|
double signedArea = 0;
|
||||||
double minX = Double.POSITIVE_INFINITY;
|
double minX = Double.POSITIVE_INFINITY;
|
||||||
double maxX = Double.NEGATIVE_INFINITY;
|
double maxX = Double.NEGATIVE_INFINITY;
|
||||||
|
@ -718,11 +734,11 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
// calculate range
|
// calculate range
|
||||||
final double rng = maxX - minX;
|
final double rng = maxX - minX;
|
||||||
// translate the points if the following is true
|
// translate the points if the following is true
|
||||||
// 1. shell orientation is cw and range is greater than a hemisphere (180 degrees) but not spanning 2 hemispheres
|
// 1. shell orientation is cw and range is greater than a hemisphere (180 degrees) but not spanning 2 hemispheres
|
||||||
// (translation would result in a collapsed poly)
|
// (translation would result in a collapsed poly)
|
||||||
// 2. the shell of the candidate hole has been translated (to preserve the coordinate system)
|
// 2. the shell of the candidate hole has been translated (to preserve the coordinate system)
|
||||||
boolean incorrectOrientation = component == 0 && handedness != orientation;
|
boolean incorrectOrientation = component == 0 && handedness != orientation;
|
||||||
if ( (incorrectOrientation && (rng > DATELINE && rng != 2*DATELINE)) || (translated.get() && component != 0)) {
|
if ((incorrectOrientation && (rng > DATELINE && rng != 2 * DATELINE)) || (translated.get() && component != 0)) {
|
||||||
translate(points);
|
translate(points);
|
||||||
// flip the translation bit if the shell is being translated
|
// flip the translation bit if the shell is being translated
|
||||||
if (component == 0) {
|
if (component == 0) {
|
||||||
|
@ -755,10 +771,17 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
* number of points to use
|
* number of points to use
|
||||||
* @return the edges creates
|
* @return the edges creates
|
||||||
*/
|
*/
|
||||||
private static Edge[] concat(int component, boolean direction, Coordinate[] points, final int pointOffset, Edge[] edges,
|
private static Edge[] concat(
|
||||||
final int edgeOffset, int length) {
|
int component,
|
||||||
assert edges.length >= length+edgeOffset;
|
boolean direction,
|
||||||
assert points.length >= length+pointOffset;
|
Coordinate[] points,
|
||||||
|
final int pointOffset,
|
||||||
|
Edge[] edges,
|
||||||
|
final int edgeOffset,
|
||||||
|
int length
|
||||||
|
) {
|
||||||
|
assert edges.length >= length + edgeOffset;
|
||||||
|
assert points.length >= length + pointOffset;
|
||||||
edges[edgeOffset] = new Edge(points[pointOffset], null);
|
edges[edgeOffset] = new Edge(points[pointOffset], null);
|
||||||
for (int i = 1; i < length; i++) {
|
for (int i = 1; i < length; i++) {
|
||||||
if (direction) {
|
if (direction) {
|
||||||
|
@ -789,7 +812,7 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
private static void translate(Coordinate[] points) {
|
private static void translate(Coordinate[] points) {
|
||||||
for (Coordinate c : points) {
|
for (Coordinate c : points) {
|
||||||
if (c.x < 0) {
|
if (c.x < 0) {
|
||||||
c.x += 2*DATELINE;
|
c.x += 2 * DATELINE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -821,8 +844,6 @@ public class PolygonBuilder extends ShapeBuilder<JtsGeometry, org.elasticsearch.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PolygonBuilder other = (PolygonBuilder) obj;
|
PolygonBuilder other = (PolygonBuilder) obj;
|
||||||
return Objects.equals(shell, other.shell) &&
|
return Objects.equals(shell, other.shell) && Objects.equals(holes, other.holes) && Objects.equals(orientation, other.orientation);
|
||||||
Objects.equals(holes, other.holes) &&
|
|
||||||
Objects.equals(orientation, other.orientation);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,24 +6,23 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
|
||||||
import org.locationtech.jts.geom.Geometry;
|
|
||||||
import org.locationtech.jts.geom.GeometryFactory;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.elasticsearch.Assertions;
|
import org.elasticsearch.Assertions;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.parsers.GeoWKTParser;
|
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteable;
|
import org.elasticsearch.common.io.stream.NamedWriteable;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.GeoWKTParser;
|
||||||
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
import org.locationtech.jts.geom.Geometry;
|
||||||
|
import org.locationtech.jts.geom.GeometryFactory;
|
||||||
import org.locationtech.spatial4j.context.jts.JtsSpatialContext;
|
import org.locationtech.spatial4j.context.jts.JtsSpatialContext;
|
||||||
import org.locationtech.spatial4j.exception.InvalidShapeException;
|
import org.locationtech.spatial4j.exception.InvalidShapeException;
|
||||||
import org.locationtech.spatial4j.shape.Shape;
|
import org.locationtech.spatial4j.shape.Shape;
|
||||||
|
@ -40,8 +39,10 @@ import java.util.Objects;
|
||||||
/**
|
/**
|
||||||
* Basic class for building GeoJSON shapes like Polygons, Linestrings, etc
|
* Basic class for building GeoJSON shapes like Polygons, Linestrings, etc
|
||||||
*/
|
*/
|
||||||
public abstract class ShapeBuilder<T extends Shape, G extends org.elasticsearch.geometry.Geometry,
|
public abstract class ShapeBuilder<T extends Shape, G extends org.elasticsearch.geometry.Geometry, E extends ShapeBuilder<T, G, E>>
|
||||||
E extends ShapeBuilder<T, G, E>> implements NamedWriteable, ToXContentObject {
|
implements
|
||||||
|
NamedWriteable,
|
||||||
|
ToXContentObject {
|
||||||
|
|
||||||
protected static final Logger LOGGER = LogManager.getLogger(ShapeBuilder.class);
|
protected static final Logger LOGGER = LogManager.getLogger(ShapeBuilder.class);
|
||||||
|
|
||||||
|
@ -74,7 +75,7 @@ public abstract class ShapeBuilder<T extends Shape, G extends org.elasticsearch.
|
||||||
/** @see org.locationtech.spatial4j.shape.jts.JtsGeometry#validate() */
|
/** @see org.locationtech.spatial4j.shape.jts.JtsGeometry#validate() */
|
||||||
protected static final boolean AUTO_VALIDATE_JTS_GEOMETRY = true;
|
protected static final boolean AUTO_VALIDATE_JTS_GEOMETRY = true;
|
||||||
/** @see org.locationtech.spatial4j.shape.jts.JtsGeometry#index() */
|
/** @see org.locationtech.spatial4j.shape.jts.JtsGeometry#index() */
|
||||||
protected static final boolean AUTO_INDEX_JTS_GEOMETRY = true;//may want to turn off once SpatialStrategy impls do it.
|
protected static final boolean AUTO_INDEX_JTS_GEOMETRY = true;// may want to turn off once SpatialStrategy impls do it.
|
||||||
|
|
||||||
/** default ctor */
|
/** default ctor */
|
||||||
protected ShapeBuilder() {
|
protected ShapeBuilder() {
|
||||||
|
@ -93,7 +94,7 @@ public abstract class ShapeBuilder<T extends Shape, G extends org.elasticsearch.
|
||||||
protected ShapeBuilder(StreamInput in) throws IOException {
|
protected ShapeBuilder(StreamInput in) throws IOException {
|
||||||
int size = in.readVInt();
|
int size = in.readVInt();
|
||||||
coordinates = new ArrayList<>(size);
|
coordinates = new ArrayList<>(size);
|
||||||
for (int i=0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
coordinates.add(readFromStream(in));
|
coordinates.add(readFromStream(in));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +127,7 @@ public abstract class ShapeBuilder<T extends Shape, G extends org.elasticsearch.
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private E thisRef() {
|
private E thisRef() {
|
||||||
return (E)this;
|
return (E) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -155,7 +156,7 @@ public abstract class ShapeBuilder<T extends Shape, G extends org.elasticsearch.
|
||||||
* @param coordinates array of {@link Coordinate}s to add
|
* @param coordinates array of {@link Coordinate}s to add
|
||||||
* @return this
|
* @return this
|
||||||
*/
|
*/
|
||||||
public E coordinates(Coordinate...coordinates) {
|
public E coordinates(Coordinate... coordinates) {
|
||||||
return this.coordinates(Arrays.asList(coordinates));
|
return this.coordinates(Arrays.asList(coordinates));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,20 +178,18 @@ public abstract class ShapeBuilder<T extends Shape, G extends org.elasticsearch.
|
||||||
* @return Array of coordinates
|
* @return Array of coordinates
|
||||||
*/
|
*/
|
||||||
protected Coordinate[] coordinates(boolean closed) {
|
protected Coordinate[] coordinates(boolean closed) {
|
||||||
Coordinate[] result = coordinates.toArray(new Coordinate[coordinates.size() + (closed?1:0)]);
|
Coordinate[] result = coordinates.toArray(new Coordinate[coordinates.size() + (closed ? 1 : 0)]);
|
||||||
if(closed) {
|
if (closed) {
|
||||||
result[result.length-1] = result[0];
|
result[result.length - 1] = result[0];
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JtsGeometry jtsGeometry(Geometry geom) {
|
protected JtsGeometry jtsGeometry(Geometry geom) {
|
||||||
//dateline180Check is false because ElasticSearch does it's own dateline wrapping
|
// dateline180Check is false because ElasticSearch does it's own dateline wrapping
|
||||||
JtsGeometry jtsGeometry = new JtsGeometry(geom, SPATIAL_CONTEXT, false, MULTI_POLYGON_MAY_OVERLAP);
|
JtsGeometry jtsGeometry = new JtsGeometry(geom, SPATIAL_CONTEXT, false, MULTI_POLYGON_MAY_OVERLAP);
|
||||||
if (AUTO_VALIDATE_JTS_GEOMETRY)
|
if (AUTO_VALIDATE_JTS_GEOMETRY) jtsGeometry.validate();
|
||||||
jtsGeometry.validate();
|
if (AUTO_INDEX_JTS_GEOMETRY) jtsGeometry.index();
|
||||||
if (AUTO_INDEX_JTS_GEOMETRY)
|
|
||||||
jtsGeometry.index();
|
|
||||||
return jtsGeometry;
|
return jtsGeometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,13 +456,13 @@ public abstract class ShapeBuilder<T extends Shape, G extends org.elasticsearch.
|
||||||
*/
|
*/
|
||||||
protected XContentBuilder coordinatesToXcontent(XContentBuilder builder, boolean closed) throws IOException {
|
protected XContentBuilder coordinatesToXcontent(XContentBuilder builder, boolean closed) throws IOException {
|
||||||
builder.startArray();
|
builder.startArray();
|
||||||
for(Coordinate coord : coordinates) {
|
for (Coordinate coord : coordinates) {
|
||||||
toXContent(builder, coord);
|
toXContent(builder, coord);
|
||||||
}
|
}
|
||||||
if(closed) {
|
if (closed) {
|
||||||
Coordinate start = coordinates.get(0);
|
Coordinate start = coordinates.get(0);
|
||||||
Coordinate end = coordinates.get(coordinates.size()-1);
|
Coordinate end = coordinates.get(coordinates.size() - 1);
|
||||||
if(start.x != end.x || start.y != end.y) {
|
if (start.x != end.x || start.y != end.y) {
|
||||||
toXContent(builder, coordinates.get(0));
|
toXContent(builder, coordinates.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,7 +475,7 @@ public abstract class ShapeBuilder<T extends Shape, G extends org.elasticsearch.
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if ((o instanceof ShapeBuilder) == false) return false;
|
if ((o instanceof ShapeBuilder) == false) return false;
|
||||||
|
|
||||||
ShapeBuilder<?,?,?> that = (ShapeBuilder<?,?,?>) o;
|
ShapeBuilder<?, ?, ?> that = (ShapeBuilder<?, ?, ?>) o;
|
||||||
|
|
||||||
return Objects.equals(coordinates, that.coordinates);
|
return Objects.equals(coordinates, that.coordinates);
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.index.mapper;
|
package org.elasticsearch.legacygeo.mapper;
|
||||||
|
|
||||||
import org.apache.lucene.search.Query;
|
import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.spatial.prefix.PrefixTreeStrategy;
|
import org.apache.lucene.spatial.prefix.PrefixTreeStrategy;
|
||||||
|
@ -20,13 +20,9 @@ import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.Explicit;
|
import org.elasticsearch.common.Explicit;
|
||||||
import org.elasticsearch.common.geo.GeoUtils;
|
import org.elasticsearch.common.geo.GeoUtils;
|
||||||
import org.elasticsearch.common.geo.GeometryFormatterFactory;
|
import org.elasticsearch.common.geo.GeometryFormatterFactory;
|
||||||
import org.elasticsearch.common.geo.ShapeRelation;
|
|
||||||
import org.elasticsearch.common.geo.ShapesAvailability;
|
|
||||||
import org.elasticsearch.common.geo.SpatialStrategy;
|
|
||||||
import org.elasticsearch.common.geo.XShapeCollection;
|
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.elasticsearch.common.geo.Orientation;
|
import org.elasticsearch.common.geo.Orientation;
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
import org.elasticsearch.common.geo.ShapeRelation;
|
||||||
|
import org.elasticsearch.common.geo.SpatialStrategy;
|
||||||
import org.elasticsearch.common.logging.DeprecationLogger;
|
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||||
import org.elasticsearch.common.lucene.Lucene;
|
import org.elasticsearch.common.lucene.Lucene;
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
|
@ -34,8 +30,20 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||||
import org.elasticsearch.core.CheckedConsumer;
|
import org.elasticsearch.core.CheckedConsumer;
|
||||||
import org.elasticsearch.geometry.Geometry;
|
import org.elasticsearch.geometry.Geometry;
|
||||||
import org.elasticsearch.index.query.LegacyGeoShapeQueryProcessor;
|
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
|
||||||
|
import org.elasticsearch.index.mapper.DocumentParserContext;
|
||||||
|
import org.elasticsearch.index.mapper.FieldMapper;
|
||||||
|
import org.elasticsearch.index.mapper.GeoShapeQueryable;
|
||||||
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
|
import org.elasticsearch.index.mapper.Mapper;
|
||||||
|
import org.elasticsearch.index.mapper.MapperBuilderContext;
|
||||||
|
import org.elasticsearch.index.mapper.MapperParsingException;
|
||||||
import org.elasticsearch.index.query.SearchExecutionContext;
|
import org.elasticsearch.index.query.SearchExecutionContext;
|
||||||
|
import org.elasticsearch.legacygeo.ShapesAvailability;
|
||||||
|
import org.elasticsearch.legacygeo.XShapeCollection;
|
||||||
|
import org.elasticsearch.legacygeo.builders.ShapeBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
|
import org.elasticsearch.legacygeo.query.LegacyGeoShapeQueryProcessor;
|
||||||
import org.locationtech.spatial4j.shape.Point;
|
import org.locationtech.spatial4j.shape.Point;
|
||||||
import org.locationtech.spatial4j.shape.Shape;
|
import org.locationtech.spatial4j.shape.Shape;
|
||||||
import org.locationtech.spatial4j.shape.jts.JtsGeometry;
|
import org.locationtech.spatial4j.shape.jts.JtsGeometry;
|
||||||
|
@ -71,15 +79,16 @@ import java.util.function.Function;
|
||||||
* <p>
|
* <p>
|
||||||
* "field" : "POLYGON ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0))
|
* "field" : "POLYGON ((100.0 0.0, 101.0 0.0, 101.0 1.0, 100.0 1.0, 100.0 0.0))
|
||||||
*
|
*
|
||||||
* @deprecated use {@link GeoShapeFieldMapper}
|
* @deprecated use {@link org.elasticsearch.index.mapper.GeoShapeFieldMapper}
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<ShapeBuilder<?, ?, ?>> {
|
public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<ShapeBuilder<?, ?, ?>> {
|
||||||
|
|
||||||
public static final String CONTENT_TYPE = "geo_shape";
|
public static final String CONTENT_TYPE = "geo_shape";
|
||||||
|
|
||||||
public static final Set<String> DEPRECATED_PARAMETERS
|
public static final Set<String> DEPRECATED_PARAMETERS = new HashSet<>(
|
||||||
= new HashSet<>(Arrays.asList("strategy", "tree", "tree_levels", "precision", "distance_error_pct", "points_only"));
|
Arrays.asList("strategy", "tree", "tree_levels", "precision", "distance_error_pct", "points_only")
|
||||||
|
);
|
||||||
|
|
||||||
public static boolean containsDeprecatedParameter(Set<String> paramKeys) {
|
public static boolean containsDeprecatedParameter(Set<String> paramKeys) {
|
||||||
return DEPRECATED_PARAMETERS.stream().anyMatch(paramKeys::contains);
|
return DEPRECATED_PARAMETERS.stream().anyMatch(paramKeys::contains);
|
||||||
|
@ -115,8 +124,19 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
public static final String GEOHASH = "geohash";
|
public static final String GEOHASH = "geohash";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static class DeprecatedParameters {
|
||||||
|
|
||||||
|
private static void checkPrefixTreeSupport(String fieldName) {
|
||||||
|
if (ShapesAvailability.JTS_AVAILABLE == false || ShapesAvailability.SPATIAL4J_AVAILABLE == false) {
|
||||||
|
throw new ElasticsearchParseException("Field parameter [{}] is not supported for [{}] field type", fieldName, CONTENT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Builder builder(FieldMapper in) {
|
private static Builder builder(FieldMapper in) {
|
||||||
return ((LegacyGeoShapeFieldMapper)in).builder;
|
return ((LegacyGeoShapeFieldMapper) in).builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder extends FieldMapper.Builder {
|
public static class Builder extends FieldMapper.Builder {
|
||||||
|
@ -128,28 +148,42 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
final Parameter<Explicit<Boolean>> coerce;
|
final Parameter<Explicit<Boolean>> coerce;
|
||||||
Parameter<Explicit<Orientation>> orientation = orientationParam(m -> builder(m).orientation.get());
|
Parameter<Explicit<Orientation>> orientation = orientationParam(m -> builder(m).orientation.get());
|
||||||
|
|
||||||
Parameter<SpatialStrategy> strategy = new Parameter<>("strategy", false, () -> SpatialStrategy.RECURSIVE,
|
Parameter<SpatialStrategy> strategy = new Parameter<>(
|
||||||
(n, c, o) -> SpatialStrategy.fromString(o.toString(), DEPRECATION_LOGGER), m -> builder(m).strategy.get())
|
"strategy",
|
||||||
.deprecated();
|
false,
|
||||||
Parameter<String> tree = Parameter.stringParam("tree", false, m -> builder(m).tree.get(), Defaults.TREE)
|
() -> SpatialStrategy.RECURSIVE,
|
||||||
.deprecated();
|
(n, c, o) -> SpatialStrategy.fromString(o.toString(), DEPRECATION_LOGGER),
|
||||||
Parameter<Integer> treeLevels = new Parameter<>("tree_levels", false, () -> null,
|
m -> builder(m).strategy.get()
|
||||||
(n, c, o) -> o == null ? null : XContentMapValues.nodeIntegerValue(o),
|
).deprecated();
|
||||||
m -> builder(m).treeLevels.get())
|
Parameter<String> tree = Parameter.stringParam("tree", false, m -> builder(m).tree.get(), Defaults.TREE).deprecated();
|
||||||
.deprecated();
|
Parameter<Integer> treeLevels = new Parameter<>(
|
||||||
Parameter<DistanceUnit.Distance> precision = new Parameter<>("precision", false, () -> null,
|
"tree_levels",
|
||||||
(n, c, o) -> o == null ? null : DistanceUnit.Distance.parseDistance(o.toString()),
|
false,
|
||||||
m -> builder(m).precision.get())
|
|
||||||
.deprecated();
|
|
||||||
Parameter<Double> distanceErrorPct = new Parameter<>("distance_error_pct", true, () -> null,
|
|
||||||
(n, c, o) -> o == null ? null : XContentMapValues.nodeDoubleValue(o),
|
|
||||||
m -> builder(m).distanceErrorPct.get())
|
|
||||||
.deprecated()
|
|
||||||
.acceptsNull();
|
|
||||||
Parameter<Boolean> pointsOnly = new Parameter<>("points_only", false,
|
|
||||||
() -> null,
|
() -> null,
|
||||||
(n, c, o) -> XContentMapValues.nodeBooleanValue(o), m -> builder(m).pointsOnly.get())
|
(n, c, o) -> o == null ? null : XContentMapValues.nodeIntegerValue(o),
|
||||||
.deprecated().acceptsNull();
|
m -> builder(m).treeLevels.get()
|
||||||
|
).deprecated();
|
||||||
|
Parameter<DistanceUnit.Distance> precision = new Parameter<>(
|
||||||
|
"precision",
|
||||||
|
false,
|
||||||
|
() -> null,
|
||||||
|
(n, c, o) -> o == null ? null : DistanceUnit.Distance.parseDistance(o.toString()),
|
||||||
|
m -> builder(m).precision.get()
|
||||||
|
).deprecated();
|
||||||
|
Parameter<Double> distanceErrorPct = new Parameter<>(
|
||||||
|
"distance_error_pct",
|
||||||
|
true,
|
||||||
|
() -> null,
|
||||||
|
(n, c, o) -> o == null ? null : XContentMapValues.nodeDoubleValue(o),
|
||||||
|
m -> builder(m).distanceErrorPct.get()
|
||||||
|
).deprecated().acceptsNull();
|
||||||
|
Parameter<Boolean> pointsOnly = new Parameter<>(
|
||||||
|
"points_only",
|
||||||
|
false,
|
||||||
|
() -> null,
|
||||||
|
(n, c, o) -> XContentMapValues.nodeBooleanValue(o),
|
||||||
|
m -> builder(m).pointsOnly.get()
|
||||||
|
).deprecated().acceptsNull();
|
||||||
|
|
||||||
Parameter<Map<String, String>> meta = Parameter.metaParam();
|
Parameter<Map<String, String>> meta = Parameter.metaParam();
|
||||||
|
|
||||||
|
@ -209,8 +243,20 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Parameter<?>> getParameters() {
|
protected List<Parameter<?>> getParameters() {
|
||||||
return Arrays.asList(indexed, ignoreMalformed, ignoreZValue, coerce, orientation,
|
return Arrays.asList(
|
||||||
strategy, tree, treeLevels, precision, distanceErrorPct, pointsOnly, meta);
|
indexed,
|
||||||
|
ignoreMalformed,
|
||||||
|
ignoreZValue,
|
||||||
|
coerce,
|
||||||
|
orientation,
|
||||||
|
strategy,
|
||||||
|
tree,
|
||||||
|
treeLevels,
|
||||||
|
precision,
|
||||||
|
distanceErrorPct,
|
||||||
|
pointsOnly,
|
||||||
|
meta
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder coerce(boolean coerce) {
|
public Builder coerce(boolean coerce) {
|
||||||
|
@ -241,14 +287,20 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
private void setupPrefixTrees(GeoShapeFieldType ft) {
|
private void setupPrefixTrees(GeoShapeFieldType ft) {
|
||||||
SpatialPrefixTree prefixTree;
|
SpatialPrefixTree prefixTree;
|
||||||
if (ft.tree().equals(PrefixTrees.GEOHASH)) {
|
if (ft.tree().equals(PrefixTrees.GEOHASH)) {
|
||||||
prefixTree = new GeohashPrefixTree(ShapeBuilder.SPATIAL_CONTEXT,
|
prefixTree = new GeohashPrefixTree(
|
||||||
getLevels(ft.treeLevels(), ft.precisionInMeters(), Defaults.GEOHASH_TREE_LEVELS, true));
|
ShapeBuilder.SPATIAL_CONTEXT,
|
||||||
|
getLevels(ft.treeLevels(), ft.precisionInMeters(), Defaults.GEOHASH_TREE_LEVELS, true)
|
||||||
|
);
|
||||||
} else if (ft.tree().equals(PrefixTrees.LEGACY_QUADTREE)) {
|
} else if (ft.tree().equals(PrefixTrees.LEGACY_QUADTREE)) {
|
||||||
prefixTree = new QuadPrefixTree(ShapeBuilder.SPATIAL_CONTEXT,
|
prefixTree = new QuadPrefixTree(
|
||||||
getLevels(ft.treeLevels(), ft.precisionInMeters(), Defaults.QUADTREE_LEVELS, false));
|
ShapeBuilder.SPATIAL_CONTEXT,
|
||||||
|
getLevels(ft.treeLevels(), ft.precisionInMeters(), Defaults.QUADTREE_LEVELS, false)
|
||||||
|
);
|
||||||
} else if (ft.tree().equals(PrefixTrees.QUADTREE)) {
|
} else if (ft.tree().equals(PrefixTrees.QUADTREE)) {
|
||||||
prefixTree = new PackedQuadPrefixTree(ShapeBuilder.SPATIAL_CONTEXT,
|
prefixTree = new PackedQuadPrefixTree(
|
||||||
getLevels(ft.treeLevels(), ft.precisionInMeters(), Defaults.QUADTREE_LEVELS, false));
|
ShapeBuilder.SPATIAL_CONTEXT,
|
||||||
|
getLevels(ft.treeLevels(), ft.precisionInMeters(), Defaults.QUADTREE_LEVELS, false)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Unknown prefix tree type [" + ft.tree() + "]");
|
throw new IllegalArgumentException("Unknown prefix tree type [" + ft.tree() + "]");
|
||||||
}
|
}
|
||||||
|
@ -271,8 +323,13 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
}
|
}
|
||||||
|
|
||||||
private GeoShapeFieldType buildFieldType(LegacyGeoShapeParser parser, MapperBuilderContext context) {
|
private GeoShapeFieldType buildFieldType(LegacyGeoShapeParser parser, MapperBuilderContext context) {
|
||||||
GeoShapeFieldType ft =
|
GeoShapeFieldType ft = new GeoShapeFieldType(
|
||||||
new GeoShapeFieldType(context.buildFullName(name), indexed.get(), orientation.get().value(), parser, meta.get());
|
context.buildFullName(name),
|
||||||
|
indexed.get(),
|
||||||
|
orientation.get().value(),
|
||||||
|
parser,
|
||||||
|
meta.get()
|
||||||
|
);
|
||||||
setupFieldTypeDeprecatedParameters(ft);
|
setupFieldTypeDeprecatedParameters(ft);
|
||||||
setupPrefixTrees(ft);
|
setupPrefixTrees(ft);
|
||||||
return ft;
|
return ft;
|
||||||
|
@ -280,8 +337,14 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
|
|
||||||
private static int getLevels(int treeLevels, double precisionInMeters, int defaultLevels, boolean geoHash) {
|
private static int getLevels(int treeLevels, double precisionInMeters, int defaultLevels, boolean geoHash) {
|
||||||
if (treeLevels > 0 || precisionInMeters >= 0) {
|
if (treeLevels > 0 || precisionInMeters >= 0) {
|
||||||
return Math.max(treeLevels, precisionInMeters >= 0 ? (geoHash ? GeoUtils.geoHashLevelsForPrecision(precisionInMeters)
|
return Math.max(
|
||||||
: GeoUtils.quadTreeLevelsForPrecision(precisionInMeters)) : 0);
|
treeLevels,
|
||||||
|
precisionInMeters >= 0
|
||||||
|
? (geoHash
|
||||||
|
? GeoUtils.geoHashLevelsForPrecision(precisionInMeters)
|
||||||
|
: GeoUtils.quadTreeLevelsForPrecision(precisionInMeters))
|
||||||
|
: 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return defaultLevels;
|
return defaultLevels;
|
||||||
}
|
}
|
||||||
|
@ -294,9 +357,7 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
}
|
}
|
||||||
LegacyGeoShapeParser parser = new LegacyGeoShapeParser();
|
LegacyGeoShapeParser parser = new LegacyGeoShapeParser();
|
||||||
GeoShapeFieldType ft = buildFieldType(parser, context);
|
GeoShapeFieldType ft = buildFieldType(parser, context);
|
||||||
return new LegacyGeoShapeFieldMapper(name, ft,
|
return new LegacyGeoShapeFieldMapper(name, ft, multiFieldsBuilder.build(this, context), copyTo.build(), parser, this);
|
||||||
multiFieldsBuilder.build(this, context), copyTo.build(),
|
|
||||||
parser, this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,18 +366,18 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
boolean ignoreMalformedByDefault = IGNORE_MALFORMED_SETTING.get(parserContext.getSettings());
|
boolean ignoreMalformedByDefault = IGNORE_MALFORMED_SETTING.get(parserContext.getSettings());
|
||||||
boolean coerceByDefault = COERCE_SETTING.get(parserContext.getSettings());
|
boolean coerceByDefault = COERCE_SETTING.get(parserContext.getSettings());
|
||||||
FieldMapper.Builder builder = new LegacyGeoShapeFieldMapper.Builder(
|
FieldMapper.Builder builder = new LegacyGeoShapeFieldMapper.Builder(
|
||||||
name,
|
name,
|
||||||
parserContext.indexVersionCreated(),
|
parserContext.indexVersionCreated(),
|
||||||
ignoreMalformedByDefault,
|
ignoreMalformedByDefault,
|
||||||
coerceByDefault);
|
coerceByDefault
|
||||||
|
);
|
||||||
builder.parse(name, parserContext, node);
|
builder.parse(name, parserContext, node);
|
||||||
return builder;
|
return builder;
|
||||||
};
|
};
|
||||||
|
|
||||||
private static class LegacyGeoShapeParser extends Parser<ShapeBuilder<?, ?, ?>> {
|
private static class LegacyGeoShapeParser extends Parser<ShapeBuilder<?, ?, ?>> {
|
||||||
|
|
||||||
private LegacyGeoShapeParser() {
|
private LegacyGeoShapeParser() {}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void parse(
|
public void parse(
|
||||||
|
@ -355,8 +416,13 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
|
|
||||||
private final LegacyGeoShapeQueryProcessor queryProcessor;
|
private final LegacyGeoShapeQueryProcessor queryProcessor;
|
||||||
|
|
||||||
private GeoShapeFieldType(String name, boolean indexed, Orientation orientation,
|
private GeoShapeFieldType(
|
||||||
LegacyGeoShapeParser parser, Map<String, String> meta) {
|
String name,
|
||||||
|
boolean indexed,
|
||||||
|
Orientation orientation,
|
||||||
|
LegacyGeoShapeParser parser,
|
||||||
|
Map<String, String> meta
|
||||||
|
) {
|
||||||
super(name, indexed, false, false, parser, orientation, meta);
|
super(name, indexed, false, false, parser, orientation, meta);
|
||||||
this.queryProcessor = new LegacyGeoShapeQueryProcessor(this);
|
this.queryProcessor = new LegacyGeoShapeQueryProcessor(this);
|
||||||
}
|
}
|
||||||
|
@ -371,8 +437,13 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Query geoShapeQuery(Geometry shape, String fieldName, SpatialStrategy strategy, ShapeRelation relation,
|
public Query geoShapeQuery(
|
||||||
SearchExecutionContext context) {
|
Geometry shape,
|
||||||
|
String fieldName,
|
||||||
|
SpatialStrategy strategy,
|
||||||
|
ShapeRelation relation,
|
||||||
|
SearchExecutionContext context
|
||||||
|
) {
|
||||||
return queryProcessor.geoShapeQuery(shape, fieldName, strategy, relation, context);
|
return queryProcessor.geoShapeQuery(shape, fieldName, strategy, relation, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,6 +478,7 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
public void setPointsOnly(boolean pointsOnly) {
|
public void setPointsOnly(boolean pointsOnly) {
|
||||||
this.pointsOnly = pointsOnly;
|
this.pointsOnly = pointsOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int treeLevels() {
|
public int treeLevels() {
|
||||||
return treeLevels;
|
return treeLevels;
|
||||||
}
|
}
|
||||||
|
@ -462,13 +534,26 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
private final Version indexCreatedVersion;
|
private final Version indexCreatedVersion;
|
||||||
private final Builder builder;
|
private final Builder builder;
|
||||||
|
|
||||||
public LegacyGeoShapeFieldMapper(String simpleName, MappedFieldType mappedFieldType,
|
public LegacyGeoShapeFieldMapper(
|
||||||
MultiFields multiFields, CopyTo copyTo,
|
String simpleName,
|
||||||
LegacyGeoShapeParser parser,
|
MappedFieldType mappedFieldType,
|
||||||
Builder builder) {
|
MultiFields multiFields,
|
||||||
super(simpleName, mappedFieldType, Collections.singletonMap(mappedFieldType.name(), Lucene.KEYWORD_ANALYZER),
|
CopyTo copyTo,
|
||||||
builder.ignoreMalformed.get(), builder.coerce.get(), builder.ignoreZValue.get(), builder.orientation.get(),
|
LegacyGeoShapeParser parser,
|
||||||
multiFields, copyTo, parser);
|
Builder builder
|
||||||
|
) {
|
||||||
|
super(
|
||||||
|
simpleName,
|
||||||
|
mappedFieldType,
|
||||||
|
Collections.singletonMap(mappedFieldType.name(), Lucene.KEYWORD_ANALYZER),
|
||||||
|
builder.ignoreMalformed.get(),
|
||||||
|
builder.coerce.get(),
|
||||||
|
builder.ignoreZValue.get(),
|
||||||
|
builder.orientation.get(),
|
||||||
|
multiFields,
|
||||||
|
copyTo,
|
||||||
|
parser
|
||||||
|
);
|
||||||
this.indexCreatedVersion = builder.indexCreatedVersion;
|
this.indexCreatedVersion = builder.indexCreatedVersion;
|
||||||
this.builder = builder;
|
this.builder = builder;
|
||||||
}
|
}
|
||||||
|
@ -478,7 +563,7 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
return (GeoShapeFieldType) super.fieldType();
|
return (GeoShapeFieldType) super.fieldType();
|
||||||
}
|
}
|
||||||
|
|
||||||
String strategy() {
|
public String strategy() {
|
||||||
return fieldType().strategy().getStrategyName();
|
return fieldType().strategy().getStrategyName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,15 +577,20 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
// index configured for pointsOnly
|
// index configured for pointsOnly
|
||||||
if (shape instanceof XShapeCollection && ((XShapeCollection<?>) shape).pointsOnly()) {
|
if (shape instanceof XShapeCollection && ((XShapeCollection<?>) shape).pointsOnly()) {
|
||||||
// MULTIPOINT data: index each point separately
|
// MULTIPOINT data: index each point separately
|
||||||
@SuppressWarnings("unchecked") List<Shape> shapes = ((XShapeCollection<Shape>) shape).getShapes();
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Shape> shapes = ((XShapeCollection<Shape>) shape).getShapes();
|
||||||
for (Shape s : shapes) {
|
for (Shape s : shapes) {
|
||||||
context.doc().addAll(Arrays.asList(fieldType().defaultPrefixTreeStrategy().createIndexableFields(s)));
|
context.doc().addAll(Arrays.asList(fieldType().defaultPrefixTreeStrategy().createIndexableFields(s)));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (shape instanceof Point == false) {
|
} else if (shape instanceof Point == false) {
|
||||||
throw new MapperParsingException("[{" + fieldType().name() + "}] is configured for points only but a "
|
throw new MapperParsingException(
|
||||||
+ ((shape instanceof JtsGeometry) ? ((JtsGeometry)shape).getGeom().getGeometryType() : shape.getClass())
|
"[{"
|
||||||
+ " was found");
|
+ fieldType().name()
|
||||||
|
+ "}] is configured for points only but a "
|
||||||
|
+ ((shape instanceof JtsGeometry) ? ((JtsGeometry) shape).getGeom().getGeometryType() : shape.getClass())
|
||||||
|
+ " was found"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context.doc().addAll(Arrays.asList(fieldType().defaultPrefixTreeStrategy().createIndexableFields(shape)));
|
context.doc().addAll(Arrays.asList(fieldType().defaultPrefixTreeStrategy().createIndexableFields(shape)));
|
||||||
|
@ -514,16 +604,20 @@ public class LegacyGeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FieldMapper.Builder getMergeBuilder() {
|
public FieldMapper.Builder getMergeBuilder() {
|
||||||
return new Builder(simpleName(), indexCreatedVersion,
|
return new Builder(
|
||||||
builder.ignoreMalformed.getDefaultValue().value(), builder.coerce.getDefaultValue().value()).init(this);
|
simpleName(),
|
||||||
|
indexCreatedVersion,
|
||||||
|
builder.ignoreMalformed.getDefaultValue().value(),
|
||||||
|
builder.coerce.getDefaultValue().value()
|
||||||
|
).init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void checkIncomingMergeType(FieldMapper mergeWith) {
|
protected void checkIncomingMergeType(FieldMapper mergeWith) {
|
||||||
if (mergeWith instanceof AbstractShapeGeometryFieldMapper<?>
|
if (mergeWith instanceof LegacyGeoShapeFieldMapper == false && CONTENT_TYPE.equals(mergeWith.typeName())) {
|
||||||
&& (mergeWith instanceof LegacyGeoShapeFieldMapper) == false) {
|
throw new IllegalArgumentException(
|
||||||
throw new IllegalArgumentException("mapper [" + name()
|
"mapper [" + name() + "] of type [geo_shape] cannot change strategy from [recursive] to [BKD]"
|
||||||
+ "] of type [geo_shape] cannot change strategy from [recursive] to [BKD]");
|
);
|
||||||
}
|
}
|
||||||
super.checkIncomingMergeType(mergeWith);
|
super.checkIncomingMergeType(mergeWith);
|
||||||
}
|
}
|
|
@ -5,12 +5,12 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.common.geo.parsers;
|
package org.elasticsearch.legacygeo.parsers;
|
||||||
|
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
|
@ -5,19 +5,19 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.common.geo.parsers;
|
package org.elasticsearch.legacygeo.parsers;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.geo.GeoPoint;
|
import org.elasticsearch.common.geo.GeoPoint;
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.Orientation;
|
import org.elasticsearch.common.geo.Orientation;
|
||||||
import org.elasticsearch.common.geo.builders.CircleBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.common.xcontent.XContentSubParser;
|
import org.elasticsearch.common.xcontent.XContentSubParser;
|
||||||
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
|
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.builders.CircleBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.GeometryCollectionBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.ShapeBuilder;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -37,9 +37,7 @@ abstract class GeoJsonParser {
|
||||||
CoordinateNode coordinateNode = null;
|
CoordinateNode coordinateNode = null;
|
||||||
GeometryCollectionBuilder geometryCollections = null;
|
GeometryCollectionBuilder geometryCollections = null;
|
||||||
|
|
||||||
Orientation orientation = (shapeMapper == null)
|
Orientation orientation = (shapeMapper == null) ? Orientation.RIGHT : shapeMapper.orientation();
|
||||||
? Orientation.RIGHT
|
|
||||||
: shapeMapper.orientation();
|
|
||||||
boolean coerce = shapeMapper != null && shapeMapper.coerce();
|
boolean coerce = shapeMapper != null && shapeMapper.coerce();
|
||||||
boolean ignoreZValue = shapeMapper == null || shapeMapper.ignoreZValue();
|
boolean ignoreZValue = shapeMapper == null || shapeMapper.ignoreZValue();
|
||||||
|
|
||||||
|
@ -55,8 +53,12 @@ abstract class GeoJsonParser {
|
||||||
subParser.nextToken();
|
subParser.nextToken();
|
||||||
final GeoShapeType type = GeoShapeType.forName(subParser.text());
|
final GeoShapeType type = GeoShapeType.forName(subParser.text());
|
||||||
if (shapeType != null && shapeType.equals(type) == false) {
|
if (shapeType != null && shapeType.equals(type) == false) {
|
||||||
malformedException = ShapeParser.FIELD_TYPE + " already parsed as ["
|
malformedException = ShapeParser.FIELD_TYPE
|
||||||
+ shapeType + "] cannot redefine as [" + type + "]";
|
+ " already parsed as ["
|
||||||
|
+ shapeType
|
||||||
|
+ "] cannot redefine as ["
|
||||||
|
+ type
|
||||||
|
+ "]";
|
||||||
} else {
|
} else {
|
||||||
shapeType = type;
|
shapeType = type;
|
||||||
}
|
}
|
||||||
|
@ -64,16 +66,14 @@ abstract class GeoJsonParser {
|
||||||
subParser.nextToken();
|
subParser.nextToken();
|
||||||
CoordinateNode tempNode = parseCoordinates(subParser, ignoreZValue);
|
CoordinateNode tempNode = parseCoordinates(subParser, ignoreZValue);
|
||||||
if (coordinateNode != null && tempNode.numDimensions() != coordinateNode.numDimensions()) {
|
if (coordinateNode != null && tempNode.numDimensions() != coordinateNode.numDimensions()) {
|
||||||
throw new ElasticsearchParseException("Exception parsing coordinates: " +
|
throw new ElasticsearchParseException("Exception parsing coordinates: " + "number of dimensions do not match");
|
||||||
"number of dimensions do not match");
|
|
||||||
}
|
}
|
||||||
coordinateNode = tempNode;
|
coordinateNode = tempNode;
|
||||||
} else if (ShapeParser.FIELD_GEOMETRIES.match(fieldName, subParser.getDeprecationHandler())) {
|
} else if (ShapeParser.FIELD_GEOMETRIES.match(fieldName, subParser.getDeprecationHandler())) {
|
||||||
if (shapeType == null) {
|
if (shapeType == null) {
|
||||||
shapeType = GeoShapeType.GEOMETRYCOLLECTION;
|
shapeType = GeoShapeType.GEOMETRYCOLLECTION;
|
||||||
} else if (shapeType.equals(GeoShapeType.GEOMETRYCOLLECTION) == false) {
|
} else if (shapeType.equals(GeoShapeType.GEOMETRYCOLLECTION) == false) {
|
||||||
malformedException = "cannot have [" + ShapeParser.FIELD_GEOMETRIES + "] with type set to ["
|
malformedException = "cannot have [" + ShapeParser.FIELD_GEOMETRIES + "] with type set to [" + shapeType + "]";
|
||||||
+ shapeType + "]";
|
|
||||||
}
|
}
|
||||||
subParser.nextToken();
|
subParser.nextToken();
|
||||||
geometryCollections = parseGeometries(subParser, shapeMapper);
|
geometryCollections = parseGeometries(subParser, shapeMapper);
|
||||||
|
@ -81,8 +81,7 @@ abstract class GeoJsonParser {
|
||||||
if (shapeType == null) {
|
if (shapeType == null) {
|
||||||
shapeType = GeoShapeType.CIRCLE;
|
shapeType = GeoShapeType.CIRCLE;
|
||||||
} else if (shapeType.equals(GeoShapeType.CIRCLE) == false) {
|
} else if (shapeType.equals(GeoShapeType.CIRCLE) == false) {
|
||||||
malformedException = "cannot have [" + CircleBuilder.FIELD_RADIUS + "] with type set to ["
|
malformedException = "cannot have [" + CircleBuilder.FIELD_RADIUS + "] with type set to [" + shapeType + "]";
|
||||||
+ shapeType + "]";
|
|
||||||
}
|
}
|
||||||
subParser.nextToken();
|
subParser.nextToken();
|
||||||
radius = DistanceUnit.Distance.parseDistance(subParser.text());
|
radius = DistanceUnit.Distance.parseDistance(subParser.text());
|
||||||
|
@ -110,8 +109,7 @@ abstract class GeoJsonParser {
|
||||||
} else if (geometryCollections == null && GeoShapeType.GEOMETRYCOLLECTION == shapeType) {
|
} else if (geometryCollections == null && GeoShapeType.GEOMETRYCOLLECTION == shapeType) {
|
||||||
throw new ElasticsearchParseException("geometries not included");
|
throw new ElasticsearchParseException("geometries not included");
|
||||||
} else if (radius != null && GeoShapeType.CIRCLE != shapeType) {
|
} else if (radius != null && GeoShapeType.CIRCLE != shapeType) {
|
||||||
throw new ElasticsearchParseException("field [{}] is supported for [{}] only", CircleBuilder.FIELD_RADIUS,
|
throw new ElasticsearchParseException("field [{}] is supported for [{}] only", CircleBuilder.FIELD_RADIUS, CircleBuilder.TYPE);
|
||||||
CircleBuilder.TYPE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shapeType.equals(GeoShapeType.GEOMETRYCOLLECTION)) {
|
if (shapeType.equals(GeoShapeType.GEOMETRYCOLLECTION)) {
|
||||||
|
@ -141,9 +139,9 @@ abstract class GeoJsonParser {
|
||||||
|
|
||||||
XContentParser.Token token = parser.nextToken();
|
XContentParser.Token token = parser.nextToken();
|
||||||
// Base cases
|
// Base cases
|
||||||
if (token != XContentParser.Token.START_ARRAY &&
|
if (token != XContentParser.Token.START_ARRAY
|
||||||
token != XContentParser.Token.END_ARRAY &&
|
&& token != XContentParser.Token.END_ARRAY
|
||||||
token != XContentParser.Token.VALUE_NULL) {
|
&& token != XContentParser.Token.VALUE_NULL) {
|
||||||
return new CoordinateNode(parseCoordinate(parser, ignoreZValue));
|
return new CoordinateNode(parseCoordinate(parser, ignoreZValue));
|
||||||
} else if (token == XContentParser.Token.VALUE_NULL) {
|
} else if (token == XContentParser.Token.VALUE_NULL) {
|
||||||
throw new IllegalArgumentException("coordinates cannot contain NULL values)");
|
throw new IllegalArgumentException("coordinates cannot contain NULL values)");
|
||||||
|
@ -192,8 +190,7 @@ abstract class GeoJsonParser {
|
||||||
* @return Geometry[] geometries of the GeometryCollection
|
* @return Geometry[] geometries of the GeometryCollection
|
||||||
* @throws IOException Thrown if an error occurs while reading from the XContentParser
|
* @throws IOException Thrown if an error occurs while reading from the XContentParser
|
||||||
*/
|
*/
|
||||||
static GeometryCollectionBuilder parseGeometries(XContentParser parser, AbstractShapeGeometryFieldMapper<?> mapper) throws
|
static GeometryCollectionBuilder parseGeometries(XContentParser parser, AbstractShapeGeometryFieldMapper<?> mapper) throws IOException {
|
||||||
IOException {
|
|
||||||
if (parser.currentToken() != XContentParser.Token.START_ARRAY) {
|
if (parser.currentToken() != XContentParser.Token.START_ARRAY) {
|
||||||
throw new ElasticsearchParseException("geometries must be an array of geojson objects");
|
throw new ElasticsearchParseException("geometries must be an array of geojson objects");
|
||||||
}
|
}
|
|
@ -5,25 +5,25 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.common.geo.parsers;
|
package org.elasticsearch.legacygeo.parsers;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.geo.GeoPoint;
|
import org.elasticsearch.common.geo.GeoPoint;
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.EnvelopeBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiLineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiPointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiPolygonBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PolygonBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.elasticsearch.common.geo.Orientation;
|
import org.elasticsearch.common.geo.Orientation;
|
||||||
import org.elasticsearch.common.logging.Loggers;
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
|
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.builders.CoordinatesBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.EnvelopeBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.GeometryCollectionBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.LineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiLineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiPointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiPolygonBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PolygonBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.ShapeBuilder;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -53,19 +53,21 @@ public class GeoWKTParser {
|
||||||
private GeoWKTParser() {}
|
private GeoWKTParser() {}
|
||||||
|
|
||||||
public static ShapeBuilder<?, ?, ?> parse(XContentParser parser, final AbstractShapeGeometryFieldMapper<?> shapeMapper)
|
public static ShapeBuilder<?, ?, ?> parse(XContentParser parser, final AbstractShapeGeometryFieldMapper<?> shapeMapper)
|
||||||
throws IOException, ElasticsearchParseException {
|
throws IOException, ElasticsearchParseException {
|
||||||
return parseExpectedType(parser, null, shapeMapper);
|
return parseExpectedType(parser, null, shapeMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShapeBuilder<?, ?, ?> parseExpectedType(XContentParser parser, final GeoShapeType shapeType)
|
public static ShapeBuilder<?, ?, ?> parseExpectedType(XContentParser parser, final GeoShapeType shapeType) throws IOException,
|
||||||
throws IOException, ElasticsearchParseException {
|
ElasticsearchParseException {
|
||||||
return parseExpectedType(parser, shapeType, null);
|
return parseExpectedType(parser, shapeType, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** throws an exception if the parsed geometry type does not match the expected shape type */
|
/** throws an exception if the parsed geometry type does not match the expected shape type */
|
||||||
public static ShapeBuilder<?, ?, ?> parseExpectedType(XContentParser parser, final GeoShapeType shapeType,
|
public static ShapeBuilder<?, ?, ?> parseExpectedType(
|
||||||
final AbstractShapeGeometryFieldMapper<?> shapeMapper)
|
XContentParser parser,
|
||||||
throws IOException, ElasticsearchParseException {
|
final GeoShapeType shapeType,
|
||||||
|
final AbstractShapeGeometryFieldMapper<?> shapeMapper
|
||||||
|
) throws IOException, ElasticsearchParseException {
|
||||||
try (StringReader reader = new StringReader(parser.text())) {
|
try (StringReader reader = new StringReader(parser.text())) {
|
||||||
boolean coerce = shapeMapper != null && shapeMapper.coerce();
|
boolean coerce = shapeMapper != null && shapeMapper.coerce();
|
||||||
boolean ignoreZValue = shapeMapper == null || shapeMapper.ignoreZValue();
|
boolean ignoreZValue = shapeMapper == null || shapeMapper.ignoreZValue();
|
||||||
|
@ -88,9 +90,12 @@ public class GeoWKTParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** parse geometry from the stream tokenizer */
|
/** parse geometry from the stream tokenizer */
|
||||||
private static ShapeBuilder<?, ?, ?> parseGeometry(StreamTokenizer stream, GeoShapeType shapeType, final boolean ignoreZValue,
|
private static ShapeBuilder<?, ?, ?> parseGeometry(
|
||||||
final boolean coerce)
|
StreamTokenizer stream,
|
||||||
throws IOException, ElasticsearchParseException {
|
GeoShapeType shapeType,
|
||||||
|
final boolean ignoreZValue,
|
||||||
|
final boolean coerce
|
||||||
|
) throws IOException, ElasticsearchParseException {
|
||||||
final GeoShapeType type = GeoShapeType.forName(nextWord(stream));
|
final GeoShapeType type = GeoShapeType.forName(nextWord(stream));
|
||||||
if (shapeType != null && shapeType != GeoShapeType.GEOMETRYCOLLECTION) {
|
if (shapeType != null && shapeType != GeoShapeType.GEOMETRYCOLLECTION) {
|
||||||
if (type.wktName().equals(shapeType.wktName()) == false) {
|
if (type.wktName().equals(shapeType.wktName()) == false) {
|
||||||
|
@ -134,8 +139,8 @@ public class GeoWKTParser {
|
||||||
return new EnvelopeBuilder(new Coordinate(minLon, maxLat), new Coordinate(maxLon, minLat));
|
return new EnvelopeBuilder(new Coordinate(minLon, maxLat), new Coordinate(maxLon, minLat));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PointBuilder parsePoint(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
private static PointBuilder parsePoint(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce) throws IOException,
|
||||||
throws IOException, ElasticsearchParseException {
|
ElasticsearchParseException {
|
||||||
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
|
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -148,7 +153,7 @@ public class GeoWKTParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Coordinate> parseCoordinateList(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
private static List<Coordinate> parseCoordinateList(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
||||||
throws IOException, ElasticsearchParseException {
|
throws IOException, ElasticsearchParseException {
|
||||||
CoordinatesBuilder coordinates = new CoordinatesBuilder();
|
CoordinatesBuilder coordinates = new CoordinatesBuilder();
|
||||||
boolean isOpenParen = false;
|
boolean isOpenParen = false;
|
||||||
if (isNumberNext(stream) || (isOpenParen = nextWord(stream).equals(LPAREN))) {
|
if (isNumberNext(stream) || (isOpenParen = nextWord(stream).equals(LPAREN))) {
|
||||||
|
@ -171,8 +176,8 @@ public class GeoWKTParser {
|
||||||
return coordinates.build();
|
return coordinates.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Coordinate parseCoordinate(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
private static Coordinate parseCoordinate(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce) throws IOException,
|
||||||
throws IOException, ElasticsearchParseException {
|
ElasticsearchParseException {
|
||||||
final double lon = nextNumber(stream);
|
final double lon = nextNumber(stream);
|
||||||
final double lat = nextNumber(stream);
|
final double lat = nextNumber(stream);
|
||||||
Double z = null;
|
Double z = null;
|
||||||
|
@ -183,7 +188,7 @@ public class GeoWKTParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MultiPointBuilder parseMultiPoint(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
private static MultiPointBuilder parseMultiPoint(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
||||||
throws IOException, ElasticsearchParseException {
|
throws IOException, ElasticsearchParseException {
|
||||||
String token = nextEmptyOrOpen(stream);
|
String token = nextEmptyOrOpen(stream);
|
||||||
if (token.equals(EMPTY)) {
|
if (token.equals(EMPTY)) {
|
||||||
return new MultiPointBuilder();
|
return new MultiPointBuilder();
|
||||||
|
@ -191,8 +196,8 @@ public class GeoWKTParser {
|
||||||
return new MultiPointBuilder(parseCoordinateList(stream, ignoreZValue, coerce));
|
return new MultiPointBuilder(parseCoordinateList(stream, ignoreZValue, coerce));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LineStringBuilder parseLine(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
private static LineStringBuilder parseLine(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce) throws IOException,
|
||||||
throws IOException, ElasticsearchParseException {
|
ElasticsearchParseException {
|
||||||
String token = nextEmptyOrOpen(stream);
|
String token = nextEmptyOrOpen(stream);
|
||||||
if (token.equals(EMPTY)) {
|
if (token.equals(EMPTY)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -203,7 +208,7 @@ public class GeoWKTParser {
|
||||||
// A LinearRing is closed LineString with 4 or more positions. The first and last positions
|
// A LinearRing is closed LineString with 4 or more positions. The first and last positions
|
||||||
// are equivalent (they represent equivalent points).
|
// are equivalent (they represent equivalent points).
|
||||||
private static LineStringBuilder parseLinearRing(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
private static LineStringBuilder parseLinearRing(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
||||||
throws IOException, ElasticsearchParseException {
|
throws IOException, ElasticsearchParseException {
|
||||||
String token = nextEmptyOrOpen(stream);
|
String token = nextEmptyOrOpen(stream);
|
||||||
if (token.equals(EMPTY)) {
|
if (token.equals(EMPTY)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -220,14 +225,13 @@ public class GeoWKTParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (coordinates.size() < 4) {
|
if (coordinates.size() < 4) {
|
||||||
throw new ElasticsearchParseException("invalid number of points in LinearRing (found [{}] - must be >= 4)",
|
throw new ElasticsearchParseException("invalid number of points in LinearRing (found [{}] - must be >= 4)", coordinates.size());
|
||||||
coordinates.size());
|
|
||||||
}
|
}
|
||||||
return new LineStringBuilder(coordinates);
|
return new LineStringBuilder(coordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MultiLineStringBuilder parseMultiLine(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
private static MultiLineStringBuilder parseMultiLine(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
||||||
throws IOException, ElasticsearchParseException {
|
throws IOException, ElasticsearchParseException {
|
||||||
String token = nextEmptyOrOpen(stream);
|
String token = nextEmptyOrOpen(stream);
|
||||||
if (token.equals(EMPTY)) {
|
if (token.equals(EMPTY)) {
|
||||||
return new MultiLineStringBuilder();
|
return new MultiLineStringBuilder();
|
||||||
|
@ -240,13 +244,12 @@ public class GeoWKTParser {
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PolygonBuilder parsePolygon(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
private static PolygonBuilder parsePolygon(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce) throws IOException,
|
||||||
throws IOException, ElasticsearchParseException {
|
ElasticsearchParseException {
|
||||||
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
|
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
PolygonBuilder builder = new PolygonBuilder(parseLinearRing(stream, ignoreZValue, coerce),
|
PolygonBuilder builder = new PolygonBuilder(parseLinearRing(stream, ignoreZValue, coerce), Orientation.RIGHT);
|
||||||
Orientation.RIGHT);
|
|
||||||
while (nextCloserOrComma(stream).equals(COMMA)) {
|
while (nextCloserOrComma(stream).equals(COMMA)) {
|
||||||
builder.hole(parseLinearRing(stream, ignoreZValue, coerce));
|
builder.hole(parseLinearRing(stream, ignoreZValue, coerce));
|
||||||
}
|
}
|
||||||
|
@ -254,7 +257,7 @@ public class GeoWKTParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MultiPolygonBuilder parseMultiPolygon(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
private static MultiPolygonBuilder parseMultiPolygon(StreamTokenizer stream, final boolean ignoreZValue, final boolean coerce)
|
||||||
throws IOException, ElasticsearchParseException {
|
throws IOException, ElasticsearchParseException {
|
||||||
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
|
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -265,14 +268,17 @@ public class GeoWKTParser {
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GeometryCollectionBuilder parseGeometryCollection(StreamTokenizer stream, final boolean ignoreZValue,
|
private static GeometryCollectionBuilder parseGeometryCollection(
|
||||||
final boolean coerce)
|
StreamTokenizer stream,
|
||||||
throws IOException, ElasticsearchParseException {
|
final boolean ignoreZValue,
|
||||||
|
final boolean coerce
|
||||||
|
) throws IOException, ElasticsearchParseException {
|
||||||
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
|
if (nextEmptyOrOpen(stream).equals(EMPTY)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
GeometryCollectionBuilder builder = new GeometryCollectionBuilder().shape(
|
GeometryCollectionBuilder builder = new GeometryCollectionBuilder().shape(
|
||||||
parseGeometry(stream, GeoShapeType.GEOMETRYCOLLECTION, ignoreZValue, coerce));
|
parseGeometry(stream, GeoShapeType.GEOMETRYCOLLECTION, ignoreZValue, coerce)
|
||||||
|
);
|
||||||
while (nextCloserOrComma(stream).equals(COMMA)) {
|
while (nextCloserOrComma(stream).equals(COMMA)) {
|
||||||
builder.shape(parseGeometry(stream, null, ignoreZValue, coerce));
|
builder.shape(parseGeometry(stream, null, ignoreZValue, coerce));
|
||||||
}
|
}
|
||||||
|
@ -285,9 +291,12 @@ public class GeoWKTParser {
|
||||||
case StreamTokenizer.TT_WORD:
|
case StreamTokenizer.TT_WORD:
|
||||||
final String word = stream.sval;
|
final String word = stream.sval;
|
||||||
return word.equalsIgnoreCase(EMPTY) ? EMPTY : word;
|
return word.equalsIgnoreCase(EMPTY) ? EMPTY : word;
|
||||||
case '(': return LPAREN;
|
case '(':
|
||||||
case ')': return RPAREN;
|
return LPAREN;
|
||||||
case ',': return COMMA;
|
case ')':
|
||||||
|
return RPAREN;
|
||||||
|
case ',':
|
||||||
|
return COMMA;
|
||||||
}
|
}
|
||||||
throw new ElasticsearchParseException("expected word but found: " + tokenString(stream), stream.lineno());
|
throw new ElasticsearchParseException("expected word but found: " + tokenString(stream), stream.lineno());
|
||||||
}
|
}
|
||||||
|
@ -309,10 +318,14 @@ public class GeoWKTParser {
|
||||||
|
|
||||||
private static String tokenString(StreamTokenizer stream) {
|
private static String tokenString(StreamTokenizer stream) {
|
||||||
switch (stream.ttype) {
|
switch (stream.ttype) {
|
||||||
case StreamTokenizer.TT_WORD: return stream.sval;
|
case StreamTokenizer.TT_WORD:
|
||||||
case StreamTokenizer.TT_EOF: return EOF;
|
return stream.sval;
|
||||||
case StreamTokenizer.TT_EOL: return EOL;
|
case StreamTokenizer.TT_EOF:
|
||||||
case StreamTokenizer.TT_NUMBER: return NUMBER;
|
return EOF;
|
||||||
|
case StreamTokenizer.TT_EOL:
|
||||||
|
return EOL;
|
||||||
|
case StreamTokenizer.TT_NUMBER:
|
||||||
|
return NUMBER;
|
||||||
}
|
}
|
||||||
return "'" + (char) stream.ttype + "'";
|
return "'" + (char) stream.ttype + "'";
|
||||||
}
|
}
|
||||||
|
@ -328,8 +341,10 @@ public class GeoWKTParser {
|
||||||
if (next.equals(EMPTY) || next.equals(LPAREN)) {
|
if (next.equals(EMPTY) || next.equals(LPAREN)) {
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
throw new ElasticsearchParseException("expected " + EMPTY + " or " + LPAREN
|
throw new ElasticsearchParseException(
|
||||||
+ " but found: " + tokenString(stream), stream.lineno());
|
"expected " + EMPTY + " or " + LPAREN + " but found: " + tokenString(stream),
|
||||||
|
stream.lineno()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String nextCloser(StreamTokenizer stream) throws IOException, ElasticsearchParseException {
|
private static String nextCloser(StreamTokenizer stream) throws IOException, ElasticsearchParseException {
|
||||||
|
@ -351,15 +366,19 @@ public class GeoWKTParser {
|
||||||
if (token.equals(COMMA) || token.equals(RPAREN)) {
|
if (token.equals(COMMA) || token.equals(RPAREN)) {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
throw new ElasticsearchParseException("expected " + COMMA + " or " + RPAREN
|
throw new ElasticsearchParseException(
|
||||||
+ " but found: " + tokenString(stream), stream.lineno());
|
"expected " + COMMA + " or " + RPAREN + " but found: " + tokenString(stream),
|
||||||
|
stream.lineno()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** next word in the stream */
|
/** next word in the stream */
|
||||||
private static void checkEOF(StreamTokenizer stream) throws ElasticsearchParseException, IOException {
|
private static void checkEOF(StreamTokenizer stream) throws ElasticsearchParseException, IOException {
|
||||||
if (stream.nextToken() != StreamTokenizer.TT_EOF) {
|
if (stream.nextToken() != StreamTokenizer.TT_EOF) {
|
||||||
throw new ElasticsearchParseException("expected end of WKT string but found additional text: "
|
throw new ElasticsearchParseException(
|
||||||
+ tokenString(stream), stream.lineno());
|
"expected end of WKT string but found additional text: " + tokenString(stream),
|
||||||
|
stream.lineno()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,18 +5,18 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.common.geo.parsers;
|
package org.elasticsearch.legacygeo.parsers;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.xcontent.ParseField;
|
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
||||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||||
|
import org.elasticsearch.common.xcontent.ParseField;
|
||||||
import org.elasticsearch.common.xcontent.XContent;
|
import org.elasticsearch.common.xcontent.XContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.common.xcontent.support.MapXContentParser;
|
import org.elasticsearch.common.xcontent.support.MapXContentParser;
|
||||||
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
|
import org.elasticsearch.index.mapper.AbstractGeometryFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
|
import org.elasticsearch.index.mapper.AbstractShapeGeometryFieldMapper;
|
||||||
|
import org.elasticsearch.legacygeo.builders.ShapeBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -46,11 +46,12 @@ public interface ShapeParser {
|
||||||
if (geometryMapper instanceof AbstractShapeGeometryFieldMapper == false) {
|
if (geometryMapper instanceof AbstractShapeGeometryFieldMapper == false) {
|
||||||
throw new IllegalArgumentException("geometry must be a shape type");
|
throw new IllegalArgumentException("geometry must be a shape type");
|
||||||
}
|
}
|
||||||
shapeMapper = (AbstractShapeGeometryFieldMapper<?>) geometryMapper;
|
shapeMapper = (AbstractShapeGeometryFieldMapper<?>) geometryMapper;
|
||||||
}
|
}
|
||||||
if (parser.currentToken() == XContentParser.Token.VALUE_NULL) {
|
if (parser.currentToken() == XContentParser.Token.VALUE_NULL) {
|
||||||
return null;
|
return null;
|
||||||
} if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
|
}
|
||||||
|
if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
|
||||||
return GeoJsonParser.parse(parser, shapeMapper);
|
return GeoJsonParser.parse(parser, shapeMapper);
|
||||||
} else if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
|
} else if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
|
||||||
return GeoWKTParser.parse(parser, shapeMapper);
|
return GeoWKTParser.parse(parser, shapeMapper);
|
||||||
|
@ -70,8 +71,14 @@ public interface ShapeParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
static ShapeBuilder<?, ?, ?> parse(Object value) throws IOException {
|
static ShapeBuilder<?, ?, ?> parse(Object value) throws IOException {
|
||||||
try (XContentParser parser = new MapXContentParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE,
|
try (
|
||||||
Collections.singletonMap("value", value), null)) {
|
XContentParser parser = new MapXContentParser(
|
||||||
|
NamedXContentRegistry.EMPTY,
|
||||||
|
LoggingDeprecationHandler.INSTANCE,
|
||||||
|
Collections.singletonMap("value", value),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
) {
|
||||||
parser.nextToken(); // start object
|
parser.nextToken(); // start object
|
||||||
parser.nextToken(); // field name
|
parser.nextToken(); // field name
|
||||||
parser.nextToken(); // field value
|
parser.nextToken(); // field value
|
|
@ -6,7 +6,7 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.index.query;
|
package org.elasticsearch.legacygeo.query;
|
||||||
|
|
||||||
import org.apache.lucene.search.BooleanClause;
|
import org.apache.lucene.search.BooleanClause;
|
||||||
import org.apache.lucene.search.BooleanQuery;
|
import org.apache.lucene.search.BooleanQuery;
|
||||||
|
@ -16,19 +16,9 @@ import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy;
|
||||||
import org.apache.lucene.spatial.query.SpatialArgs;
|
import org.apache.lucene.spatial.query.SpatialArgs;
|
||||||
import org.apache.lucene.spatial.query.SpatialOperation;
|
import org.apache.lucene.spatial.query.SpatialOperation;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
|
import org.elasticsearch.common.geo.Orientation;
|
||||||
import org.elasticsearch.common.geo.ShapeRelation;
|
import org.elasticsearch.common.geo.ShapeRelation;
|
||||||
import org.elasticsearch.common.geo.SpatialStrategy;
|
import org.elasticsearch.common.geo.SpatialStrategy;
|
||||||
import org.elasticsearch.common.geo.builders.CircleBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.EnvelopeBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiLineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiPointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiPolygonBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PolygonBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.elasticsearch.common.geo.Orientation;
|
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
import org.elasticsearch.geometry.Circle;
|
import org.elasticsearch.geometry.Circle;
|
||||||
import org.elasticsearch.geometry.Geometry;
|
import org.elasticsearch.geometry.Geometry;
|
||||||
|
@ -42,7 +32,19 @@ import org.elasticsearch.geometry.MultiPolygon;
|
||||||
import org.elasticsearch.geometry.Point;
|
import org.elasticsearch.geometry.Point;
|
||||||
import org.elasticsearch.geometry.Polygon;
|
import org.elasticsearch.geometry.Polygon;
|
||||||
import org.elasticsearch.geometry.Rectangle;
|
import org.elasticsearch.geometry.Rectangle;
|
||||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
|
import org.elasticsearch.index.query.ExistsQueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.SearchExecutionContext;
|
||||||
|
import org.elasticsearch.legacygeo.builders.CircleBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.EnvelopeBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.GeometryCollectionBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.LineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiLineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiPointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiPolygonBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PolygonBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.ShapeBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.mapper.LegacyGeoShapeFieldMapper;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.spatial4j.shape.Shape;
|
import org.locationtech.spatial4j.shape.Shape;
|
||||||
|
|
||||||
|
@ -51,7 +53,7 @@ import java.util.List;
|
||||||
|
|
||||||
import static org.elasticsearch.search.SearchService.ALLOW_EXPENSIVE_QUERIES;
|
import static org.elasticsearch.search.SearchService.ALLOW_EXPENSIVE_QUERIES;
|
||||||
|
|
||||||
public class LegacyGeoShapeQueryProcessor {
|
public class LegacyGeoShapeQueryProcessor {
|
||||||
|
|
||||||
private final LegacyGeoShapeFieldMapper.GeoShapeFieldType shapeFieldType;
|
private final LegacyGeoShapeFieldMapper.GeoShapeFieldType shapeFieldType;
|
||||||
|
|
||||||
|
@ -59,11 +61,19 @@ public class LegacyGeoShapeQueryProcessor {
|
||||||
this.shapeFieldType = shapeFieldType;
|
this.shapeFieldType = shapeFieldType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Query geoShapeQuery(Geometry shape, String fieldName, SpatialStrategy strategy,
|
public Query geoShapeQuery(
|
||||||
ShapeRelation relation, SearchExecutionContext context) {
|
Geometry shape,
|
||||||
|
String fieldName,
|
||||||
|
SpatialStrategy strategy,
|
||||||
|
ShapeRelation relation,
|
||||||
|
SearchExecutionContext context
|
||||||
|
) {
|
||||||
if (context.allowExpensiveQueries() == false) {
|
if (context.allowExpensiveQueries() == false) {
|
||||||
throw new ElasticsearchException("[geo-shape] queries on [PrefixTree geo shapes] cannot be executed when '"
|
throw new ElasticsearchException(
|
||||||
+ ALLOW_EXPENSIVE_QUERIES.getKey() + "' is set to false.");
|
"[geo-shape] queries on [PrefixTree geo shapes] cannot be executed when '"
|
||||||
|
+ ALLOW_EXPENSIVE_QUERIES.getKey()
|
||||||
|
+ "' is set to false."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpatialStrategy spatialStrategy = shapeFieldType.strategy();
|
SpatialStrategy spatialStrategy = shapeFieldType.strategy();
|
||||||
|
@ -175,9 +185,11 @@ public class LegacyGeoShapeQueryProcessor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShapeBuilder<?, ?, ?> visit(Polygon polygon) {
|
public ShapeBuilder<?, ?, ?> visit(Polygon polygon) {
|
||||||
PolygonBuilder polygonBuilder =
|
PolygonBuilder polygonBuilder = new PolygonBuilder(
|
||||||
new PolygonBuilder((LineStringBuilder) visit((Line) polygon.getPolygon()),
|
(LineStringBuilder) visit((Line) polygon.getPolygon()),
|
||||||
Orientation.RIGHT, false);
|
Orientation.RIGHT,
|
||||||
|
false
|
||||||
|
);
|
||||||
for (int i = 0; i < polygon.getNumberOfHoles(); i++) {
|
for (int i = 0; i < polygon.getNumberOfHoles(); i++) {
|
||||||
polygonBuilder.hole((LineStringBuilder) visit((Line) polygon.getHole(i)));
|
polygonBuilder.hole((LineStringBuilder) visit((Line) polygon.getHole(i)));
|
||||||
}
|
}
|
||||||
|
@ -186,8 +198,10 @@ public class LegacyGeoShapeQueryProcessor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ShapeBuilder<?, ?, ?> visit(Rectangle rectangle) {
|
public ShapeBuilder<?, ?, ?> visit(Rectangle rectangle) {
|
||||||
return new EnvelopeBuilder(new Coordinate(rectangle.getMinX(), rectangle.getMaxY()),
|
return new EnvelopeBuilder(
|
||||||
new Coordinate(rectangle.getMaxX(), rectangle.getMinY()));
|
new Coordinate(rectangle.getMinX(), rectangle.getMaxY()),
|
||||||
|
new Coordinate(rectangle.getMaxX(), rectangle.getMinY())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return shapeBuilder;
|
return shapeBuilder;
|
|
@ -5,15 +5,15 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.common.geo;
|
package org.elasticsearch.legacygeo;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
import org.elasticsearch.common.geo.GeometryParser;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.geometry.utils.GeographyValidator;
|
|
||||||
import org.elasticsearch.index.mapper.GeoShapeIndexer;
|
import org.elasticsearch.index.mapper.GeoShapeIndexer;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
|
import org.elasticsearch.legacygeo.test.ElasticsearchGeoAssertions;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.test.hamcrest.ElasticsearchGeoAssertions;
|
|
||||||
import org.locationtech.jts.geom.Geometry;
|
import org.locationtech.jts.geom.Geometry;
|
||||||
import org.locationtech.jts.geom.GeometryFactory;
|
import org.locationtech.jts.geom.GeometryFactory;
|
||||||
import org.locationtech.spatial4j.shape.Shape;
|
import org.locationtech.spatial4j.shape.Shape;
|
||||||
|
@ -26,19 +26,26 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.elasticsearch.common.geo.builders.ShapeBuilder.SPATIAL_CONTEXT;
|
import static org.elasticsearch.legacygeo.builders.ShapeBuilder.SPATIAL_CONTEXT;
|
||||||
|
|
||||||
/** Base class for all geo parsing tests */
|
/** Base class for all geo parsing tests */
|
||||||
abstract class BaseGeoParsingTestCase extends ESTestCase {
|
abstract class BaseGeoParsingTestCase extends ESTestCase {
|
||||||
protected static final GeometryFactory GEOMETRY_FACTORY = SPATIAL_CONTEXT.getGeometryFactory();
|
protected static final GeometryFactory GEOMETRY_FACTORY = SPATIAL_CONTEXT.getGeometryFactory();
|
||||||
|
|
||||||
public abstract void testParsePoint() throws IOException, ParseException;
|
public abstract void testParsePoint() throws IOException, ParseException;
|
||||||
|
|
||||||
public abstract void testParseMultiPoint() throws IOException, ParseException;
|
public abstract void testParseMultiPoint() throws IOException, ParseException;
|
||||||
|
|
||||||
public abstract void testParseLineString() throws IOException, ParseException;
|
public abstract void testParseLineString() throws IOException, ParseException;
|
||||||
|
|
||||||
public abstract void testParseMultiLineString() throws IOException, ParseException;
|
public abstract void testParseMultiLineString() throws IOException, ParseException;
|
||||||
|
|
||||||
public abstract void testParsePolygon() throws IOException, ParseException;
|
public abstract void testParsePolygon() throws IOException, ParseException;
|
||||||
|
|
||||||
public abstract void testParseMultiPolygon() throws IOException, ParseException;
|
public abstract void testParseMultiPolygon() throws IOException, ParseException;
|
||||||
|
|
||||||
public abstract void testParseEnvelope() throws IOException, ParseException;
|
public abstract void testParseEnvelope() throws IOException, ParseException;
|
||||||
|
|
||||||
public abstract void testParseGeometryCollection() throws IOException, ParseException;
|
public abstract void testParseGeometryCollection() throws IOException, ParseException;
|
||||||
|
|
||||||
protected void assertValidException(XContentBuilder builder, Class<?> expectedException) throws IOException {
|
protected void assertValidException(XContentBuilder builder, Class<?> expectedException) throws IOException {
|
||||||
|
@ -62,13 +69,6 @@ abstract class BaseGeoParsingTestCase extends ESTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertGeometryEquals(org.elasticsearch.geometry.Geometry expected, XContentBuilder geoJson) throws IOException {
|
|
||||||
try (XContentParser parser = createParser(geoJson)) {
|
|
||||||
parser.nextToken();
|
|
||||||
assertEquals(expected, GeoJson.fromXContent(GeographyValidator.instance(false), false, true, parser));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ShapeCollection<Shape> shapeCollection(Shape... shapes) {
|
protected ShapeCollection<Shape> shapeCollection(Shape... shapes) {
|
||||||
return new ShapeCollection<>(Arrays.asList(shapes), SPATIAL_CONTEXT);
|
return new ShapeCollection<>(Arrays.asList(shapes), SPATIAL_CONTEXT);
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -5,24 +5,13 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.common.geo;
|
package org.elasticsearch.legacygeo;
|
||||||
|
|
||||||
import org.apache.lucene.geo.GeoTestUtil;
|
import org.apache.lucene.geo.GeoTestUtil;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
|
import org.elasticsearch.common.geo.GeoPoint;
|
||||||
import org.elasticsearch.common.geo.builders.EnvelopeBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiLineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiPointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiPolygonBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PolygonBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.elasticsearch.common.geo.parsers.GeoWKTParser;
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
@ -33,9 +22,21 @@ import org.elasticsearch.geometry.MultiLine;
|
||||||
import org.elasticsearch.geometry.MultiPoint;
|
import org.elasticsearch.geometry.MultiPoint;
|
||||||
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
|
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.GeoShapeIndexer;
|
import org.elasticsearch.index.mapper.GeoShapeIndexer;
|
||||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
|
|
||||||
import org.elasticsearch.index.mapper.MapperBuilderContext;
|
import org.elasticsearch.index.mapper.MapperBuilderContext;
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
import org.elasticsearch.legacygeo.builders.CoordinatesBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.EnvelopeBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.GeometryCollectionBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.LineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiLineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiPointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiPolygonBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PolygonBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.ShapeBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.mapper.LegacyGeoShapeFieldMapper;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.GeoWKTParser;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.jts.geom.LineString;
|
import org.locationtech.jts.geom.LineString;
|
||||||
import org.locationtech.jts.geom.LinearRing;
|
import org.locationtech.jts.geom.LinearRing;
|
||||||
|
@ -55,7 +56,7 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.elasticsearch.common.geo.builders.ShapeBuilder.SPATIAL_CONTEXT;
|
import static org.elasticsearch.legacygeo.builders.ShapeBuilder.SPATIAL_CONTEXT;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.hasToString;
|
import static org.hamcrest.Matchers.hasToString;
|
||||||
|
|
||||||
|
@ -64,8 +65,7 @@ import static org.hamcrest.Matchers.hasToString;
|
||||||
*/
|
*/
|
||||||
public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
|
|
||||||
private static XContentBuilder toWKTContent(ShapeBuilder<?, ?, ?> builder, boolean generateMalformed)
|
private static XContentBuilder toWKTContent(ShapeBuilder<?, ?, ?> builder, boolean generateMalformed) throws IOException {
|
||||||
throws IOException {
|
|
||||||
String wkt = builder.toWKT();
|
String wkt = builder.toWKT();
|
||||||
if (generateMalformed) {
|
if (generateMalformed) {
|
||||||
// malformed - extra paren
|
// malformed - extra paren
|
||||||
|
@ -172,7 +172,7 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
MultiLineStringBuilder builder = new MultiLineStringBuilder();
|
MultiLineStringBuilder builder = new MultiLineStringBuilder();
|
||||||
for (int j = 0; j < numLineStrings; ++j) {
|
for (int j = 0; j < numLineStrings; ++j) {
|
||||||
List<Coordinate> lsc = randomLineStringCoords();
|
List<Coordinate> lsc = randomLineStringCoords();
|
||||||
Coordinate [] coords = lsc.toArray(new Coordinate[lsc.size()]);
|
Coordinate[] coords = lsc.toArray(new Coordinate[lsc.size()]);
|
||||||
lineStrings.add(GEOMETRY_FACTORY.createLineString(coords));
|
lineStrings.add(GEOMETRY_FACTORY.createLineString(coords));
|
||||||
builder.linestring(new LineStringBuilder(lsc));
|
builder.linestring(new LineStringBuilder(lsc));
|
||||||
}
|
}
|
||||||
|
@ -180,8 +180,7 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
List<Line> lines = new ArrayList<>(lineStrings.size());
|
List<Line> lines = new ArrayList<>(lineStrings.size());
|
||||||
for (int j = 0; j < lineStrings.size(); ++j) {
|
for (int j = 0; j < lineStrings.size(); ++j) {
|
||||||
Coordinate[] c = lineStrings.get(j).getCoordinates();
|
Coordinate[] c = lineStrings.get(j).getCoordinates();
|
||||||
lines.add(new Line(Arrays.stream(c).mapToDouble(i->i.x).toArray(), Arrays.stream(c).mapToDouble(i->i.y).toArray()
|
lines.add(new Line(Arrays.stream(c).mapToDouble(i -> i.x).toArray(), Arrays.stream(c).mapToDouble(i -> i.y).toArray()));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Geometry expectedGeom;
|
Geometry expectedGeom;
|
||||||
if (lines.isEmpty()) {
|
if (lines.isEmpty()) {
|
||||||
|
@ -194,8 +193,7 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
assertExpected(expectedGeom, builder, false);
|
assertExpected(expectedGeom, builder, false);
|
||||||
assertMalformed(builder);
|
assertMalformed(builder);
|
||||||
|
|
||||||
MultiLineString expected = GEOMETRY_FACTORY.createMultiLineString(
|
MultiLineString expected = GEOMETRY_FACTORY.createMultiLineString(lineStrings.toArray(new LineString[lineStrings.size()]));
|
||||||
lineStrings.toArray(new LineString[lineStrings.size()]));
|
|
||||||
assumeTrue("JTS test path cannot handle empty multilinestrings", numLineStrings > 1);
|
assumeTrue("JTS test path cannot handle empty multilinestrings", numLineStrings > 1);
|
||||||
assertExpected(jtsGeom(expected), builder, true);
|
assertExpected(jtsGeom(expected), builder, true);
|
||||||
}
|
}
|
||||||
|
@ -203,7 +201,8 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
@Override
|
@Override
|
||||||
public void testParsePolygon() throws IOException, ParseException {
|
public void testParsePolygon() throws IOException, ParseException {
|
||||||
PolygonBuilder builder = PolygonBuilder.class.cast(
|
PolygonBuilder builder = PolygonBuilder.class.cast(
|
||||||
RandomShapeGenerator.createShape(random(), RandomShapeGenerator.ShapeType.POLYGON));
|
RandomShapeGenerator.createShape(random(), RandomShapeGenerator.ShapeType.POLYGON)
|
||||||
|
);
|
||||||
Coordinate[] coords = builder.coordinates()[0][0];
|
Coordinate[] coords = builder.coordinates()[0][0];
|
||||||
|
|
||||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(coords);
|
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(coords);
|
||||||
|
@ -252,20 +251,20 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
PolygonBuilder polygonWithHole = new PolygonBuilder(new CoordinatesBuilder().coordinates(shellCoordinates));
|
PolygonBuilder polygonWithHole = new PolygonBuilder(new CoordinatesBuilder().coordinates(shellCoordinates));
|
||||||
polygonWithHole.hole(new LineStringBuilder(holeCoordinates));
|
polygonWithHole.hole(new LineStringBuilder(holeCoordinates));
|
||||||
|
|
||||||
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(
|
LinearRing shell = GEOMETRY_FACTORY.createLinearRing(shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
||||||
shellCoordinates.toArray(new Coordinate[shellCoordinates.size()]));
|
|
||||||
LinearRing[] holes = new LinearRing[1];
|
LinearRing[] holes = new LinearRing[1];
|
||||||
holes[0] = GEOMETRY_FACTORY.createLinearRing(
|
holes[0] = GEOMETRY_FACTORY.createLinearRing(holeCoordinates.toArray(new Coordinate[holeCoordinates.size()]));
|
||||||
holeCoordinates.toArray(new Coordinate[holeCoordinates.size()]));
|
|
||||||
Polygon expected = GEOMETRY_FACTORY.createPolygon(shell, holes);
|
Polygon expected = GEOMETRY_FACTORY.createPolygon(shell, holes);
|
||||||
assertExpected(jtsGeom(expected), polygonWithHole, true);
|
assertExpected(jtsGeom(expected), polygonWithHole, true);
|
||||||
|
|
||||||
org.elasticsearch.geometry.LinearRing hole =
|
org.elasticsearch.geometry.LinearRing hole = new org.elasticsearch.geometry.LinearRing(
|
||||||
new org.elasticsearch.geometry.LinearRing(
|
new double[] { 100.2d, 100.8d, 100.8d, 100.2d, 100.2d },
|
||||||
new double[] {100.2d, 100.8d, 100.8d, 100.2d, 100.2d}, new double[] {0.8d, 0.8d, 0.2d, 0.2d, 0.8d});
|
new double[] { 0.8d, 0.8d, 0.2d, 0.2d, 0.8d }
|
||||||
org.elasticsearch.geometry.Polygon p =
|
);
|
||||||
new org.elasticsearch.geometry.Polygon(new org.elasticsearch.geometry.LinearRing(
|
org.elasticsearch.geometry.Polygon p = new org.elasticsearch.geometry.Polygon(
|
||||||
new double[] {101d, 101d, 100d, 100d, 101d}, new double[] {0d, 1d, 1d, 0d, 0d}), Collections.singletonList(hole));
|
new org.elasticsearch.geometry.LinearRing(new double[] { 101d, 101d, 100d, 100d, 101d }, new double[] { 0d, 1d, 1d, 0d, 0d }),
|
||||||
|
Collections.singletonList(hole)
|
||||||
|
);
|
||||||
assertExpected(p, polygonWithHole, false);
|
assertExpected(p, polygonWithHole, false);
|
||||||
assertMalformed(polygonWithHole);
|
assertMalformed(polygonWithHole);
|
||||||
}
|
}
|
||||||
|
@ -293,13 +292,11 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
XContentParser parser = createParser(xContentBuilder);
|
XContentParser parser = createParser(xContentBuilder);
|
||||||
parser.nextToken();
|
parser.nextToken();
|
||||||
|
|
||||||
final GeoShapeFieldMapper mapperBuilder = new GeoShapeFieldMapper.Builder("test", false, true)
|
final GeoShapeFieldMapper mapperBuilder = new GeoShapeFieldMapper.Builder("test", false, true).ignoreZValue(false)
|
||||||
.ignoreZValue(false)
|
.build(MapperBuilderContext.ROOT);
|
||||||
.build(MapperBuilderContext.ROOT);
|
|
||||||
|
|
||||||
// test store z disabled
|
// test store z disabled
|
||||||
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class,
|
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, () -> ShapeParser.parse(parser, mapperBuilder));
|
||||||
() -> ShapeParser.parse(parser, mapperBuilder));
|
|
||||||
assertThat(e, hasToString(containsString("but [ignore_z_value] parameter is [false]")));
|
assertThat(e, hasToString(containsString("but [ignore_z_value] parameter is [false]")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,13 +323,12 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
XContentParser parser = createParser(xContentBuilder);
|
XContentParser parser = createParser(xContentBuilder);
|
||||||
parser.nextToken();
|
parser.nextToken();
|
||||||
|
|
||||||
final LegacyGeoShapeFieldMapper mapperBuilder =
|
final LegacyGeoShapeFieldMapper mapperBuilder = new LegacyGeoShapeFieldMapper.Builder("test", Version.V_6_3_0, false, true).build(
|
||||||
new LegacyGeoShapeFieldMapper.Builder("test", Version.V_6_3_0, false, true)
|
MapperBuilderContext.ROOT
|
||||||
.build(MapperBuilderContext.ROOT);
|
);
|
||||||
|
|
||||||
// test store z disabled
|
// test store z disabled
|
||||||
ElasticsearchException e = expectThrows(ElasticsearchException.class,
|
ElasticsearchException e = expectThrows(ElasticsearchException.class, () -> ShapeParser.parse(parser, mapperBuilder));
|
||||||
() -> ShapeParser.parse(parser, mapperBuilder));
|
|
||||||
assertThat(e, hasToString(containsString("unable to add coordinate to CoordinateBuilder: coordinate dimensions do not match")));
|
assertThat(e, hasToString(containsString("unable to add coordinate to CoordinateBuilder: coordinate dimensions do not match")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,9 +346,9 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
XContentParser parser = createParser(xContentBuilder);
|
XContentParser parser = createParser(xContentBuilder);
|
||||||
parser.nextToken();
|
parser.nextToken();
|
||||||
|
|
||||||
final LegacyGeoShapeFieldMapper mapperBuilder =
|
final LegacyGeoShapeFieldMapper mapperBuilder = new LegacyGeoShapeFieldMapper.Builder("test", Version.V_6_3_0, false, true).build(
|
||||||
new LegacyGeoShapeFieldMapper.Builder("test", Version.V_6_3_0, false, true)
|
MapperBuilderContext.ROOT
|
||||||
.build(MapperBuilderContext.ROOT);
|
);
|
||||||
|
|
||||||
ShapeBuilder<?, ?, ?> shapeBuilder = ShapeParser.parse(parser, mapperBuilder);
|
ShapeBuilder<?, ?, ?> shapeBuilder = ShapeParser.parse(parser, mapperBuilder);
|
||||||
assertEquals(shapeBuilder.numDimensions(), 3);
|
assertEquals(shapeBuilder.numDimensions(), 3);
|
||||||
|
@ -365,16 +361,18 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
XContentParser parser = createParser(xContentBuilder);
|
XContentParser parser = createParser(xContentBuilder);
|
||||||
parser.nextToken();
|
parser.nextToken();
|
||||||
|
|
||||||
final LegacyGeoShapeFieldMapper defaultMapperBuilder =
|
final LegacyGeoShapeFieldMapper defaultMapperBuilder = new LegacyGeoShapeFieldMapper.Builder("test", Version.V_6_3_0, false, true)
|
||||||
new LegacyGeoShapeFieldMapper.Builder("test", Version.V_6_3_0, false, true)
|
.coerce(false)
|
||||||
.coerce(false).build(MapperBuilderContext.ROOT);
|
.build(MapperBuilderContext.ROOT);
|
||||||
ElasticsearchParseException exception = expectThrows(ElasticsearchParseException.class,
|
ElasticsearchParseException exception = expectThrows(
|
||||||
() -> ShapeParser.parse(parser, defaultMapperBuilder));
|
ElasticsearchParseException.class,
|
||||||
|
() -> ShapeParser.parse(parser, defaultMapperBuilder)
|
||||||
|
);
|
||||||
assertEquals("invalid LinearRing found (coordinates are not closed)", exception.getMessage());
|
assertEquals("invalid LinearRing found (coordinates are not closed)", exception.getMessage());
|
||||||
|
|
||||||
final LegacyGeoShapeFieldMapper coercingMapperBuilder =
|
final LegacyGeoShapeFieldMapper coercingMapperBuilder = new LegacyGeoShapeFieldMapper.Builder("test", Version.CURRENT, false, true)
|
||||||
new LegacyGeoShapeFieldMapper.Builder("test", Version.CURRENT, false, true)
|
.coerce(true)
|
||||||
.coerce(true).build(MapperBuilderContext.ROOT);
|
.build(MapperBuilderContext.ROOT);
|
||||||
ShapeBuilder<?, ?, ?> shapeBuilder = ShapeParser.parse(parser, coercingMapperBuilder);
|
ShapeBuilder<?, ?, ?> shapeBuilder = ShapeParser.parse(parser, coercingMapperBuilder);
|
||||||
assertNotNull(shapeBuilder);
|
assertNotNull(shapeBuilder);
|
||||||
assertEquals("polygon ((100.0 5.0, 100.0 10.0, 90.0 10.0, 90.0 5.0, 100.0 5.0))", shapeBuilder.toWKT());
|
assertEquals("polygon ((100.0 5.0, 100.0 10.0, 90.0 10.0, 90.0 5.0, 100.0 5.0))", shapeBuilder.toWKT());
|
||||||
|
@ -441,8 +439,10 @@ public class GeoWKTShapeParserTests extends BaseGeoParsingTestCase {
|
||||||
XContentBuilder builder = toWKTContent(new PointBuilder(-1, 2), false);
|
XContentBuilder builder = toWKTContent(new PointBuilder(-1, 2), false);
|
||||||
XContentParser parser = createParser(builder);
|
XContentParser parser = createParser(builder);
|
||||||
parser.nextToken();
|
parser.nextToken();
|
||||||
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class,
|
ElasticsearchParseException e = expectThrows(
|
||||||
() -> GeoWKTParser.parseExpectedType(parser, GeoShapeType.POLYGON));
|
ElasticsearchParseException.class,
|
||||||
|
() -> GeoWKTParser.parseExpectedType(parser, GeoShapeType.POLYGON)
|
||||||
|
);
|
||||||
assertThat(e, hasToString(containsString("Expected geometry type [polygon] but found [point]")));
|
assertThat(e, hasToString(containsString("Expected geometry type [polygon] but found [point]")));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.legacygeo;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.geo.GeometryIO;
|
||||||
|
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||||
|
import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.geometry.Geometry;
|
||||||
|
import org.elasticsearch.geometry.GeometryCollection;
|
||||||
|
import org.elasticsearch.geometry.ShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.builders.ShapeBuilder;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
import static org.elasticsearch.geo.GeometryTestUtils.randomGeometry;
|
||||||
|
import static org.elasticsearch.legacygeo.query.LegacyGeoShapeQueryProcessor.geometryToShapeBuilder;
|
||||||
|
|
||||||
|
public class GeometryIOTests extends ESTestCase {
|
||||||
|
|
||||||
|
public void testRandomSerialization() throws Exception {
|
||||||
|
for (int i = 0; i < randomIntBetween(1, 20); i++) {
|
||||||
|
boolean hasAlt = randomBoolean();
|
||||||
|
Geometry geometry = randomGeometry(hasAlt);
|
||||||
|
if (shapeSupported(geometry) && randomBoolean()) {
|
||||||
|
// Shape builder conversion doesn't support altitude
|
||||||
|
ShapeBuilder<?, ?, ?> shapeBuilder = geometryToShapeBuilder(geometry);
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Geometry actual = shapeBuilder.buildGeometry();
|
||||||
|
assertEquals(geometry, actual);
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
// Test ShapeBuilder -> Geometry Serialization
|
||||||
|
try (BytesStreamOutput out = new BytesStreamOutput()) {
|
||||||
|
out.writeNamedWriteable(shapeBuilder);
|
||||||
|
try (StreamInput in = out.bytes().streamInput()) {
|
||||||
|
Geometry actual = GeometryIO.readGeometry(in);
|
||||||
|
assertEquals(geometry, actual);
|
||||||
|
assertEquals(0, in.available());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Test Geometry -> ShapeBuilder Serialization
|
||||||
|
try (BytesStreamOutput out = new BytesStreamOutput()) {
|
||||||
|
GeometryIO.writeGeometry(out, geometry);
|
||||||
|
try (StreamInput in = out.bytes().streamInput()) {
|
||||||
|
try (StreamInput nin = new NamedWriteableAwareStreamInput(in, this.writableRegistry())) {
|
||||||
|
ShapeBuilder<?, ?, ?> actual = nin.readNamedWriteable(ShapeBuilder.class);
|
||||||
|
assertEquals(shapeBuilder, actual);
|
||||||
|
assertEquals(0, in.available());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Test Geometry -> Geometry
|
||||||
|
try (BytesStreamOutput out = new BytesStreamOutput()) {
|
||||||
|
GeometryIO.writeGeometry(out, geometry);
|
||||||
|
;
|
||||||
|
try (StreamInput in = out.bytes().streamInput()) {
|
||||||
|
Geometry actual = GeometryIO.readGeometry(in);
|
||||||
|
assertEquals(geometry, actual);
|
||||||
|
assertEquals(0, in.available());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shapeSupported(Geometry geometry) {
|
||||||
|
if (geometry.hasZ()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geometry.type() == ShapeType.GEOMETRYCOLLECTION) {
|
||||||
|
GeometryCollection<?> collection = (GeometryCollection<?>) geometry;
|
||||||
|
for (Geometry g : collection) {
|
||||||
|
if (shapeSupported(g) == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected NamedWriteableRegistry writableRegistry() {
|
||||||
|
return new NamedWriteableRegistry(GeoShapeType.getShapeWriteables());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,805 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.legacygeo;
|
||||||
|
|
||||||
|
import org.elasticsearch.geometry.LinearRing;
|
||||||
|
import org.elasticsearch.index.mapper.GeoShapeIndexer;
|
||||||
|
import org.elasticsearch.legacygeo.builders.CircleBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.CoordinatesBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.EnvelopeBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.LineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiLineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PolygonBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.ShapeBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.test.ElasticsearchGeoAssertions;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
import org.locationtech.jts.geom.LineString;
|
||||||
|
import org.locationtech.jts.geom.Polygon;
|
||||||
|
import org.locationtech.spatial4j.exception.InvalidShapeException;
|
||||||
|
import org.locationtech.spatial4j.shape.Circle;
|
||||||
|
import org.locationtech.spatial4j.shape.Point;
|
||||||
|
import org.locationtech.spatial4j.shape.Rectangle;
|
||||||
|
import org.locationtech.spatial4j.shape.impl.PointImpl;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link ShapeBuilder}
|
||||||
|
*/
|
||||||
|
public class ShapeBuilderTests extends ESTestCase {
|
||||||
|
|
||||||
|
public void testNewPoint() {
|
||||||
|
PointBuilder pb = new PointBuilder().coordinate(-100, 45);
|
||||||
|
Point point = pb.buildS4J();
|
||||||
|
assertEquals(-100D, point.getX(), 0.0d);
|
||||||
|
assertEquals(45D, point.getY(), 0.0d);
|
||||||
|
org.elasticsearch.geometry.Point geoPoint = pb.buildGeometry();
|
||||||
|
assertEquals(-100D, geoPoint.getX(), 0.0d);
|
||||||
|
assertEquals(45D, geoPoint.getY(), 0.0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNewRectangle() {
|
||||||
|
EnvelopeBuilder eb = new EnvelopeBuilder(new Coordinate(-45, 30), new Coordinate(45, -30));
|
||||||
|
Rectangle rectangle = eb.buildS4J();
|
||||||
|
assertEquals(-45D, rectangle.getMinX(), 0.0d);
|
||||||
|
assertEquals(-30D, rectangle.getMinY(), 0.0d);
|
||||||
|
assertEquals(45D, rectangle.getMaxX(), 0.0d);
|
||||||
|
assertEquals(30D, rectangle.getMaxY(), 0.0d);
|
||||||
|
|
||||||
|
org.elasticsearch.geometry.Rectangle luceneRectangle = eb.buildGeometry();
|
||||||
|
assertEquals(-45D, luceneRectangle.getMinX(), 0.0d);
|
||||||
|
assertEquals(-30D, luceneRectangle.getMinY(), 0.0d);
|
||||||
|
assertEquals(45D, luceneRectangle.getMaxX(), 0.0d);
|
||||||
|
assertEquals(30D, luceneRectangle.getMaxY(), 0.0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNewPolygon() {
|
||||||
|
PolygonBuilder pb = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-45, 30).coordinate(45, 30).coordinate(45, -30).coordinate(-45, -30).coordinate(-45, 30)
|
||||||
|
);
|
||||||
|
|
||||||
|
Polygon poly = pb.toPolygonS4J();
|
||||||
|
LineString exterior = poly.getExteriorRing();
|
||||||
|
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
||||||
|
assertEquals(exterior.getCoordinateN(1), new Coordinate(45, 30));
|
||||||
|
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
|
||||||
|
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
|
||||||
|
|
||||||
|
LinearRing polygon = pb.toPolygonGeometry().getPolygon();
|
||||||
|
assertEquals(polygon.getY(0), 30, 0d);
|
||||||
|
assertEquals(polygon.getX(0), -45, 0d);
|
||||||
|
assertEquals(polygon.getY(1), 30, 0d);
|
||||||
|
assertEquals(polygon.getX(1), 45, 0d);
|
||||||
|
assertEquals(polygon.getY(2), -30, 0d);
|
||||||
|
assertEquals(polygon.getX(2), 45, 0d);
|
||||||
|
assertEquals(polygon.getY(3), -30, 0d);
|
||||||
|
assertEquals(polygon.getX(3), -45, 0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNewPolygon_coordinate() {
|
||||||
|
PolygonBuilder pb = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(new Coordinate(-45, 30))
|
||||||
|
.coordinate(new Coordinate(45, 30))
|
||||||
|
.coordinate(new Coordinate(45, -30))
|
||||||
|
.coordinate(new Coordinate(-45, -30))
|
||||||
|
.coordinate(new Coordinate(-45, 30))
|
||||||
|
);
|
||||||
|
|
||||||
|
Polygon poly = pb.toPolygonS4J();
|
||||||
|
LineString exterior = poly.getExteriorRing();
|
||||||
|
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
||||||
|
assertEquals(exterior.getCoordinateN(1), new Coordinate(45, 30));
|
||||||
|
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
|
||||||
|
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
|
||||||
|
|
||||||
|
LinearRing polygon = pb.toPolygonGeometry().getPolygon();
|
||||||
|
assertEquals(polygon.getY(0), 30, 0d);
|
||||||
|
assertEquals(polygon.getX(0), -45, 0d);
|
||||||
|
assertEquals(polygon.getY(1), 30, 0d);
|
||||||
|
assertEquals(polygon.getX(1), 45, 0d);
|
||||||
|
assertEquals(polygon.getY(2), -30, 0d);
|
||||||
|
assertEquals(polygon.getX(2), 45, 0d);
|
||||||
|
assertEquals(polygon.getY(3), -30, 0d);
|
||||||
|
assertEquals(polygon.getX(3), -45, 0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNewPolygon_coordinates() {
|
||||||
|
PolygonBuilder pb = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinates(
|
||||||
|
new Coordinate(-45, 30),
|
||||||
|
new Coordinate(45, 30),
|
||||||
|
new Coordinate(45, -30),
|
||||||
|
new Coordinate(-45, -30),
|
||||||
|
new Coordinate(-45, 30)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
Polygon poly = pb.toPolygonS4J();
|
||||||
|
LineString exterior = poly.getExteriorRing();
|
||||||
|
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
||||||
|
assertEquals(exterior.getCoordinateN(1), new Coordinate(45, 30));
|
||||||
|
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
|
||||||
|
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
|
||||||
|
|
||||||
|
LinearRing polygon = pb.toPolygonGeometry().getPolygon();
|
||||||
|
assertEquals(polygon.getY(0), 30, 0d);
|
||||||
|
assertEquals(polygon.getX(0), -45, 0d);
|
||||||
|
assertEquals(polygon.getY(1), 30, 0d);
|
||||||
|
assertEquals(polygon.getX(1), 45, 0d);
|
||||||
|
assertEquals(polygon.getY(2), -30, 0d);
|
||||||
|
assertEquals(polygon.getX(2), 45, 0d);
|
||||||
|
assertEquals(polygon.getY(3), -30, 0d);
|
||||||
|
assertEquals(polygon.getX(3), -45, 0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLineStringBuilder() {
|
||||||
|
// Building a simple LineString
|
||||||
|
LineStringBuilder lsb = new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-130.0, 55.0)
|
||||||
|
.coordinate(-130.0, -40.0)
|
||||||
|
.coordinate(-15.0, -40.0)
|
||||||
|
.coordinate(-20.0, 50.0)
|
||||||
|
.coordinate(-45.0, 50.0)
|
||||||
|
.coordinate(-45.0, -15.0)
|
||||||
|
.coordinate(-110.0, -15.0)
|
||||||
|
.coordinate(-110.0, 55.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
lsb.buildS4J();
|
||||||
|
buildGeometry(lsb);
|
||||||
|
|
||||||
|
// Building a linestring that needs to be wrapped
|
||||||
|
lsb = new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(100.0, 50.0)
|
||||||
|
.coordinate(110.0, -40.0)
|
||||||
|
.coordinate(240.0, -40.0)
|
||||||
|
.coordinate(230.0, 60.0)
|
||||||
|
.coordinate(200.0, 60.0)
|
||||||
|
.coordinate(200.0, -30.0)
|
||||||
|
.coordinate(130.0, -30.0)
|
||||||
|
.coordinate(130.0, 60.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
lsb.buildS4J();
|
||||||
|
buildGeometry(lsb);
|
||||||
|
|
||||||
|
// Building a lineString on the dateline
|
||||||
|
lsb = new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-180.0, 80.0).coordinate(-180.0, 40.0).coordinate(-180.0, -40.0).coordinate(-180.0, -80.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
lsb.buildS4J();
|
||||||
|
buildGeometry(lsb);
|
||||||
|
|
||||||
|
// Building a lineString on the dateline
|
||||||
|
lsb = new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(180.0, 80.0).coordinate(180.0, 40.0).coordinate(180.0, -40.0).coordinate(180.0, -80.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
lsb.buildS4J();
|
||||||
|
buildGeometry(lsb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultiLineString() {
|
||||||
|
MultiLineStringBuilder mlsb = new MultiLineStringBuilder().linestring(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-100.0, 50.0).coordinate(50.0, 50.0).coordinate(50.0, 20.0).coordinate(-100.0, 20.0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.linestring(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-100.0, 20.0).coordinate(50.0, 20.0).coordinate(50.0, 0.0).coordinate(-100.0, 0.0)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
mlsb.buildS4J();
|
||||||
|
buildGeometry(mlsb);
|
||||||
|
|
||||||
|
// LineString that needs to be wrapped
|
||||||
|
new MultiLineStringBuilder().linestring(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(150.0, 60.0).coordinate(200.0, 60.0).coordinate(200.0, 40.0).coordinate(150.0, 40.0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.linestring(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(150.0, 20.0).coordinate(200.0, 20.0).coordinate(200.0, 0.0).coordinate(150.0, 0.0)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
mlsb.buildS4J();
|
||||||
|
buildGeometry(mlsb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPolygonSelfIntersection() {
|
||||||
|
PolygonBuilder newPolygon = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-40.0, 50.0).coordinate(40.0, 50.0).coordinate(-40.0, -50.0).coordinate(40.0, -50.0).close()
|
||||||
|
);
|
||||||
|
Exception e = expectThrows(InvalidShapeException.class, () -> newPolygon.buildS4J());
|
||||||
|
assertThat(e.getMessage(), containsString("Cannot determine orientation: signed area equal to 0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** note: only supported by S4J at the moment */
|
||||||
|
public void testGeoCircle() {
|
||||||
|
double earthCircumference = 40075016.69;
|
||||||
|
Circle circle = new CircleBuilder().center(0, 0).radius("100m").buildS4J();
|
||||||
|
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
|
||||||
|
assertEquals(new PointImpl(0, 0, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
||||||
|
circle = new CircleBuilder().center(+180, 0).radius("100m").buildS4J();
|
||||||
|
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
|
||||||
|
assertEquals(new PointImpl(180, 0, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
||||||
|
circle = new CircleBuilder().center(-180, 0).radius("100m").buildS4J();
|
||||||
|
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
|
||||||
|
assertEquals(new PointImpl(-180, 0, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
||||||
|
circle = new CircleBuilder().center(0, 90).radius("100m").buildS4J();
|
||||||
|
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
|
||||||
|
assertEquals(new PointImpl(0, 90, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
||||||
|
circle = new CircleBuilder().center(0, -90).radius("100m").buildS4J();
|
||||||
|
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
|
||||||
|
assertEquals(new PointImpl(0, -90, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
||||||
|
double randomLat = (randomDouble() * 180) - 90;
|
||||||
|
double randomLon = (randomDouble() * 360) - 180;
|
||||||
|
double randomRadius = randomIntBetween(1, (int) earthCircumference / 4);
|
||||||
|
circle = new CircleBuilder().center(randomLon, randomLat).radius(randomRadius + "m").buildS4J();
|
||||||
|
assertEquals((360 * randomRadius) / earthCircumference, circle.getRadius(), 0.00000001);
|
||||||
|
assertEquals(new PointImpl(randomLon, randomLat, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPolygonWrapping() {
|
||||||
|
PolygonBuilder pb = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-150.0, 65.0)
|
||||||
|
.coordinate(-250.0, 65.0)
|
||||||
|
.coordinate(-250.0, -65.0)
|
||||||
|
.coordinate(-150.0, -65.0)
|
||||||
|
.close()
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(pb.buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(buildGeometry(pb), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLineStringWrapping() {
|
||||||
|
LineStringBuilder lsb = new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-150.0, 65.0)
|
||||||
|
.coordinate(-250.0, 65.0)
|
||||||
|
.coordinate(-250.0, -65.0)
|
||||||
|
.coordinate(-150.0, -65.0)
|
||||||
|
.close()
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertMultiLineString(lsb.buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertMultiLineString(buildGeometry(lsb), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDatelineOGC() {
|
||||||
|
// tests that the following shape (defined in counterclockwise OGC order)
|
||||||
|
// https://gist.github.com/anonymous/7f1bb6d7e9cd72f5977c crosses the dateline
|
||||||
|
// expected results: 3 polygons, 1 with a hole
|
||||||
|
|
||||||
|
// a giant c shape
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(174, 0)
|
||||||
|
.coordinate(-176, 0)
|
||||||
|
.coordinate(-176, 3)
|
||||||
|
.coordinate(177, 3)
|
||||||
|
.coordinate(177, 5)
|
||||||
|
.coordinate(-176, 5)
|
||||||
|
.coordinate(-176, 8)
|
||||||
|
.coordinate(174, 8)
|
||||||
|
.coordinate(174, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3/4 of an embedded 'c', crossing dateline once
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(175, 1)
|
||||||
|
.coordinate(175, 7)
|
||||||
|
.coordinate(-178, 7)
|
||||||
|
.coordinate(-178, 6)
|
||||||
|
.coordinate(176, 6)
|
||||||
|
.coordinate(176, 2)
|
||||||
|
.coordinate(179, 2)
|
||||||
|
.coordinate(179, 1)
|
||||||
|
.coordinate(175, 1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// embedded hole right of the dateline
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-179, 1).coordinate(-179, 2).coordinate(-177, 2).coordinate(-177, 1).coordinate(-179, 1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDateline() {
|
||||||
|
// tests that the following shape (defined in clockwise non-OGC order)
|
||||||
|
// https://gist.github.com/anonymous/7f1bb6d7e9cd72f5977c crosses the dateline
|
||||||
|
// expected results: 3 polygons, 1 with a hole
|
||||||
|
|
||||||
|
// a giant c shape
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-186, 0)
|
||||||
|
.coordinate(-176, 0)
|
||||||
|
.coordinate(-176, 3)
|
||||||
|
.coordinate(-183, 3)
|
||||||
|
.coordinate(-183, 5)
|
||||||
|
.coordinate(-176, 5)
|
||||||
|
.coordinate(-176, 8)
|
||||||
|
.coordinate(-186, 8)
|
||||||
|
.coordinate(-186, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3/4 of an embedded 'c', crossing dateline once
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-185, 1)
|
||||||
|
.coordinate(-181, 1)
|
||||||
|
.coordinate(-181, 2)
|
||||||
|
.coordinate(-184, 2)
|
||||||
|
.coordinate(-184, 6)
|
||||||
|
.coordinate(-178, 6)
|
||||||
|
.coordinate(-178, 7)
|
||||||
|
.coordinate(-185, 7)
|
||||||
|
.coordinate(-185, 1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// embedded hole right of the dateline
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-179, 1).coordinate(-177, 1).coordinate(-177, 2).coordinate(-179, 2).coordinate(-179, 1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testComplexShapeWithHole() {
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-85.0018514, 37.1311314)
|
||||||
|
.coordinate(-85.0016645, 37.1315293)
|
||||||
|
.coordinate(-85.0016246, 37.1317069)
|
||||||
|
.coordinate(-85.0016526, 37.1318183)
|
||||||
|
.coordinate(-85.0017119, 37.1319196)
|
||||||
|
.coordinate(-85.0019371, 37.1321182)
|
||||||
|
.coordinate(-85.0019972, 37.1322115)
|
||||||
|
.coordinate(-85.0019942, 37.1323234)
|
||||||
|
.coordinate(-85.0019543, 37.1324336)
|
||||||
|
.coordinate(-85.001906, 37.1324985)
|
||||||
|
.coordinate(-85.001834, 37.1325497)
|
||||||
|
.coordinate(-85.0016965, 37.1325907)
|
||||||
|
.coordinate(-85.0016011, 37.1325873)
|
||||||
|
.coordinate(-85.0014816, 37.1325353)
|
||||||
|
.coordinate(-85.0011755, 37.1323509)
|
||||||
|
.coordinate(-85.000955, 37.1322802)
|
||||||
|
.coordinate(-85.0006241, 37.1322529)
|
||||||
|
.coordinate(-85.0000002, 37.1322307)
|
||||||
|
.coordinate(-84.9994, 37.1323001)
|
||||||
|
.coordinate(-84.999109, 37.1322864)
|
||||||
|
.coordinate(-84.998934, 37.1322415)
|
||||||
|
.coordinate(-84.9988639, 37.1321888)
|
||||||
|
.coordinate(-84.9987841, 37.1320944)
|
||||||
|
.coordinate(-84.9987208, 37.131954)
|
||||||
|
.coordinate(-84.998736, 37.1316611)
|
||||||
|
.coordinate(-84.9988091, 37.131334)
|
||||||
|
.coordinate(-84.9989283, 37.1311337)
|
||||||
|
.coordinate(-84.9991943, 37.1309198)
|
||||||
|
.coordinate(-84.9993573, 37.1308459)
|
||||||
|
.coordinate(-84.9995888, 37.1307924)
|
||||||
|
.coordinate(-84.9998746, 37.130806)
|
||||||
|
.coordinate(-85.0000002, 37.1308358)
|
||||||
|
.coordinate(-85.0004984, 37.1310658)
|
||||||
|
.coordinate(-85.0008008, 37.1311625)
|
||||||
|
.coordinate(-85.0009461, 37.1311684)
|
||||||
|
.coordinate(-85.0011373, 37.1311515)
|
||||||
|
.coordinate(-85.0016455, 37.1310491)
|
||||||
|
.coordinate(-85.0018514, 37.1311314)
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-85.0000002, 37.1317672)
|
||||||
|
.coordinate(-85.0001983, 37.1317538)
|
||||||
|
.coordinate(-85.0003378, 37.1317582)
|
||||||
|
.coordinate(-85.0004697, 37.131792)
|
||||||
|
.coordinate(-85.0008048, 37.1319439)
|
||||||
|
.coordinate(-85.0009342, 37.1319838)
|
||||||
|
.coordinate(-85.0010184, 37.1319463)
|
||||||
|
.coordinate(-85.0010618, 37.13184)
|
||||||
|
.coordinate(-85.0010057, 37.1315102)
|
||||||
|
.coordinate(-85.000977, 37.1314403)
|
||||||
|
.coordinate(-85.0009182, 37.1313793)
|
||||||
|
.coordinate(-85.0005366, 37.1312209)
|
||||||
|
.coordinate(-85.000224, 37.1311466)
|
||||||
|
.coordinate(-85.000087, 37.1311356)
|
||||||
|
.coordinate(-85.0000002, 37.1311433)
|
||||||
|
.coordinate(-84.9995021, 37.1312336)
|
||||||
|
.coordinate(-84.9993308, 37.1312859)
|
||||||
|
.coordinate(-84.9992567, 37.1313252)
|
||||||
|
.coordinate(-84.9991868, 37.1314277)
|
||||||
|
.coordinate(-84.9991593, 37.1315381)
|
||||||
|
.coordinate(-84.9991841, 37.1316527)
|
||||||
|
.coordinate(-84.9992329, 37.1317117)
|
||||||
|
.coordinate(-84.9993527, 37.1317788)
|
||||||
|
.coordinate(-84.9994931, 37.1318061)
|
||||||
|
.coordinate(-84.9996815, 37.1317979)
|
||||||
|
.coordinate(-85.0000002, 37.1317672)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShapeWithHoleAtEdgeEndPoints() {
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-4, 2)
|
||||||
|
.coordinate(4, 2)
|
||||||
|
.coordinate(6, 0)
|
||||||
|
.coordinate(4, -2)
|
||||||
|
.coordinate(-4, -2)
|
||||||
|
.coordinate(-6, 0)
|
||||||
|
.coordinate(-4, 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(4, 1).coordinate(4, -1).coordinate(-4, -1).coordinate(-4, 1).coordinate(4, 1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShapeWithPointOnDateline() {
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(180, 0).coordinate(176, 4).coordinate(176, -4).coordinate(180, 0)
|
||||||
|
);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShapeWithEdgeAlongDateline() {
|
||||||
|
// test case 1: test the positive side of the dateline
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(180, 0).coordinate(176, 4).coordinate(180, -4).coordinate(180, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(buildGeometry(builder.close()), false);
|
||||||
|
|
||||||
|
// test case 2: test the negative side of the dateline
|
||||||
|
builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-176, 4).coordinate(-180, 0).coordinate(-180, -4).coordinate(-176, 4)
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShapeWithBoundaryHoles() {
|
||||||
|
// test case 1: test the positive side of the dateline
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-177, 10)
|
||||||
|
.coordinate(176, 15)
|
||||||
|
.coordinate(172, 0)
|
||||||
|
.coordinate(176, -15)
|
||||||
|
.coordinate(-177, -10)
|
||||||
|
.coordinate(-177, 10)
|
||||||
|
);
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(176, 10).coordinate(180, 5).coordinate(180, -5).coordinate(176, -10).coordinate(176, 10)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(buildGeometry(builder.close()), false);
|
||||||
|
|
||||||
|
// test case 2: test the negative side of the dateline
|
||||||
|
builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-176, 15)
|
||||||
|
.coordinate(179, 10)
|
||||||
|
.coordinate(179, -10)
|
||||||
|
.coordinate(-176, -15)
|
||||||
|
.coordinate(-172, 0)
|
||||||
|
.close()
|
||||||
|
);
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-176, 10)
|
||||||
|
.coordinate(-176, -10)
|
||||||
|
.coordinate(-180, -5)
|
||||||
|
.coordinate(-180, 5)
|
||||||
|
.coordinate(-176, 10)
|
||||||
|
.close()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShapeWithHoleTouchingAtDateline() throws Exception {
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-180, 90)
|
||||||
|
.coordinate(-180, -90)
|
||||||
|
.coordinate(180, -90)
|
||||||
|
.coordinate(180, 90)
|
||||||
|
.coordinate(-180, 90)
|
||||||
|
);
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(180.0, -16.14)
|
||||||
|
.coordinate(178.53, -16.64)
|
||||||
|
.coordinate(178.49, -16.82)
|
||||||
|
.coordinate(178.73, -17.02)
|
||||||
|
.coordinate(178.86, -16.86)
|
||||||
|
.coordinate(180.0, -16.14)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShapeWithTangentialHole() {
|
||||||
|
// test a shape with one tangential (shared) vertex (should pass)
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(179, 10)
|
||||||
|
.coordinate(168, 15)
|
||||||
|
.coordinate(164, 0)
|
||||||
|
.coordinate(166, -15)
|
||||||
|
.coordinate(179, -10)
|
||||||
|
.coordinate(179, 10)
|
||||||
|
);
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-177, 10)
|
||||||
|
.coordinate(-178, -10)
|
||||||
|
.coordinate(-180, -5)
|
||||||
|
.coordinate(-180, 5)
|
||||||
|
.coordinate(-177, 10)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShapeWithInvalidTangentialHole() {
|
||||||
|
// test a shape with one invalid tangential (shared) vertex (should throw exception)
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(179, 10)
|
||||||
|
.coordinate(168, 15)
|
||||||
|
.coordinate(164, 0)
|
||||||
|
.coordinate(166, -15)
|
||||||
|
.coordinate(179, -10)
|
||||||
|
.coordinate(179, 10)
|
||||||
|
);
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(164, 0).coordinate(175, 10).coordinate(175, 5).coordinate(179, -10).coordinate(164, 0)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
Exception e;
|
||||||
|
|
||||||
|
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildS4J());
|
||||||
|
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
|
||||||
|
e = expectThrows(IllegalArgumentException.class, () -> buildGeometry(builder.close()));
|
||||||
|
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBoundaryShapeWithTangentialHole() {
|
||||||
|
// test a shape with one tangential (shared) vertex for each hole (should pass)
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-177, 10)
|
||||||
|
.coordinate(176, 15)
|
||||||
|
.coordinate(172, 0)
|
||||||
|
.coordinate(176, -15)
|
||||||
|
.coordinate(-177, -10)
|
||||||
|
.coordinate(-177, 10)
|
||||||
|
);
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-177, 10)
|
||||||
|
.coordinate(-178, -10)
|
||||||
|
.coordinate(-180, -5)
|
||||||
|
.coordinate(-180, 5)
|
||||||
|
.coordinate(-177, 10)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(new CoordinatesBuilder().coordinate(172, 0).coordinate(176, 10).coordinate(176, -5).coordinate(172, 0))
|
||||||
|
);
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBoundaryShapeWithInvalidTangentialHole() {
|
||||||
|
// test shape with two tangential (shared) vertices (should throw exception)
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-177, 10)
|
||||||
|
.coordinate(176, 15)
|
||||||
|
.coordinate(172, 0)
|
||||||
|
.coordinate(176, -15)
|
||||||
|
.coordinate(-177, -10)
|
||||||
|
.coordinate(-177, 10)
|
||||||
|
);
|
||||||
|
builder.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-177, 10)
|
||||||
|
.coordinate(172, 0)
|
||||||
|
.coordinate(180, -5)
|
||||||
|
.coordinate(176, -10)
|
||||||
|
.coordinate(-177, 10)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
Exception e;
|
||||||
|
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildS4J());
|
||||||
|
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
|
||||||
|
e = expectThrows(IllegalArgumentException.class, () -> buildGeometry(builder.close()));
|
||||||
|
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test an enveloping polygon around the max mercator bounds
|
||||||
|
*/
|
||||||
|
public void testBoundaryShape() {
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-180, 90).coordinate(180, 90).coordinate(180, -90).coordinate(-180, 90)
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShapeWithAlternateOrientation() {
|
||||||
|
// cw: should produce a multi polygon spanning hemispheres
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(180, 0).coordinate(176, 4).coordinate(-176, 4).coordinate(180, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertPolygon(buildGeometry(builder.close()), false);
|
||||||
|
|
||||||
|
// cw: geo core will convert to ccw across the dateline
|
||||||
|
builder = new PolygonBuilder(new CoordinatesBuilder().coordinate(180, 0).coordinate(-176, 4).coordinate(176, 4).coordinate(180, 0));
|
||||||
|
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(builder.close().buildS4J(), true);
|
||||||
|
ElasticsearchGeoAssertions.assertMultiPolygon(buildGeometry(builder.close()), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShapeWithConsecutiveDuplicatePoints() {
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(180, 0).coordinate(176, 4).coordinate(176, 4).coordinate(-176, 4).coordinate(180, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
// duplicated points are removed
|
||||||
|
PolygonBuilder expected = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(180, 0).coordinate(176, 4).coordinate(-176, 4).coordinate(180, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals(buildGeometry(expected.close()), buildGeometry(builder.close()));
|
||||||
|
assertEquals(expected.close().buildS4J(), builder.close().buildS4J());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testShapeWithCoplanarVerticalPoints() throws Exception {
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(180, -36)
|
||||||
|
.coordinate(180, 90)
|
||||||
|
.coordinate(-180, 90)
|
||||||
|
.coordinate(-180, 79)
|
||||||
|
.coordinate(16, 58)
|
||||||
|
.coordinate(8, 13)
|
||||||
|
.coordinate(-180, 74)
|
||||||
|
.coordinate(-180, -85)
|
||||||
|
.coordinate(-180, -90)
|
||||||
|
.coordinate(180, -90)
|
||||||
|
.coordinate(180, -85)
|
||||||
|
.coordinate(26, 6)
|
||||||
|
.coordinate(33, 62)
|
||||||
|
.coordinate(180, -36)
|
||||||
|
);
|
||||||
|
|
||||||
|
// coplanar points on vertical edge are removed.
|
||||||
|
PolygonBuilder expected = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(180, -36)
|
||||||
|
.coordinate(180, 90)
|
||||||
|
.coordinate(-180, 90)
|
||||||
|
.coordinate(-180, 79)
|
||||||
|
.coordinate(16, 58)
|
||||||
|
.coordinate(8, 13)
|
||||||
|
.coordinate(-180, 74)
|
||||||
|
.coordinate(-180, -90)
|
||||||
|
.coordinate(180, -90)
|
||||||
|
.coordinate(180, -85)
|
||||||
|
.coordinate(26, 6)
|
||||||
|
.coordinate(33, 62)
|
||||||
|
.coordinate(180, -36)
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals(buildGeometry(expected.close()), buildGeometry(builder.close()));
|
||||||
|
assertEquals(expected.close().buildS4J(), builder.close().buildS4J());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPolygon3D() {
|
||||||
|
String expected = "{\n"
|
||||||
|
+ " \"type\" : \"polygon\",\n"
|
||||||
|
+ " \"orientation\" : \"right\",\n"
|
||||||
|
+ " \"coordinates\" : [\n"
|
||||||
|
+ " [\n"
|
||||||
|
+ " [\n"
|
||||||
|
+ " -45.0,\n"
|
||||||
|
+ " 30.0,\n"
|
||||||
|
+ " 100.0\n"
|
||||||
|
+ " ],\n"
|
||||||
|
+ " [\n"
|
||||||
|
+ " 45.0,\n"
|
||||||
|
+ " 30.0,\n"
|
||||||
|
+ " 75.0\n"
|
||||||
|
+ " ],\n"
|
||||||
|
+ " [\n"
|
||||||
|
+ " 45.0,\n"
|
||||||
|
+ " -30.0,\n"
|
||||||
|
+ " 77.0\n"
|
||||||
|
+ " ],\n"
|
||||||
|
+ " [\n"
|
||||||
|
+ " -45.0,\n"
|
||||||
|
+ " -30.0,\n"
|
||||||
|
+ " 101.0\n"
|
||||||
|
+ " ],\n"
|
||||||
|
+ " [\n"
|
||||||
|
+ " -45.0,\n"
|
||||||
|
+ " 30.0,\n"
|
||||||
|
+ " 110.0\n"
|
||||||
|
+ " ]\n"
|
||||||
|
+ " ]\n"
|
||||||
|
+ " ]\n"
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
PolygonBuilder pb = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(new Coordinate(-45, 30, 100))
|
||||||
|
.coordinate(new Coordinate(45, 30, 75))
|
||||||
|
.coordinate(new Coordinate(45, -30, 77))
|
||||||
|
.coordinate(new Coordinate(-45, -30, 101))
|
||||||
|
.coordinate(new Coordinate(-45, 30, 110))
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEquals(expected, pb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testInvalidSelfCrossingPolygon() {
|
||||||
|
PolygonBuilder builder = new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(0, 0)
|
||||||
|
.coordinate(0, 2)
|
||||||
|
.coordinate(1, 1.9)
|
||||||
|
.coordinate(0.5, 1.8)
|
||||||
|
.coordinate(1.5, 1.8)
|
||||||
|
.coordinate(1, 1.9)
|
||||||
|
.coordinate(2, 2)
|
||||||
|
.coordinate(2, 0)
|
||||||
|
.coordinate(0, 0)
|
||||||
|
);
|
||||||
|
Exception e = expectThrows(InvalidShapeException.class, () -> builder.close().buildS4J());
|
||||||
|
assertThat(e.getMessage(), containsString("Self-intersection at or near point ["));
|
||||||
|
assertThat(e.getMessage(), not(containsString("NaN")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object buildGeometry(ShapeBuilder<?, ?, ?> builder) {
|
||||||
|
return new GeoShapeIndexer(true, "name").prepareForIndexing(builder.buildGeometry());
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,10 +6,8 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteable;
|
import org.elasticsearch.common.io.stream.NamedWriteable;
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||||
import org.elasticsearch.common.io.stream.Writeable.Reader;
|
import org.elasticsearch.common.io.stream.Writeable.Reader;
|
||||||
|
@ -18,6 +16,8 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.legacygeo.GeoShapeType;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
@ -26,7 +26,7 @@ import java.io.IOException;
|
||||||
|
|
||||||
import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode;
|
import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode;
|
||||||
|
|
||||||
public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder<?,?,?>> extends ESTestCase {
|
public abstract class AbstractShapeBuilderTestCase<SB extends ShapeBuilder<?, ?, ?>> extends ESTestCase {
|
||||||
|
|
||||||
private static final int NUMBER_OF_TESTBUILDERS = 20;
|
private static final int NUMBER_OF_TESTBUILDERS = 20;
|
||||||
private static NamedWriteableRegistry namedWriteableRegistry;
|
private static NamedWriteableRegistry namedWriteableRegistry;
|
|
@ -6,7 +6,7 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
@ -32,14 +32,14 @@ public class CircleBuilderTests extends AbstractShapeBuilderTestCase<CircleBuild
|
||||||
|
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
if (original.center().x > 0.0 || original.center().y > 0.0) {
|
if (original.center().x > 0.0 || original.center().y > 0.0) {
|
||||||
mutation.center(new Coordinate(original.center().x/2, original.center().y/2));
|
mutation.center(new Coordinate(original.center().x / 2, original.center().y / 2));
|
||||||
} else {
|
} else {
|
||||||
// original center was 0.0, 0.0
|
// original center was 0.0, 0.0
|
||||||
mutation.center(randomDouble() + 0.1, randomDouble() + 0.1);
|
mutation.center(randomDouble() + 0.1, randomDouble() + 0.1);
|
||||||
}
|
}
|
||||||
} else if (randomBoolean()) {
|
} else if (randomBoolean()) {
|
||||||
if (radius > 0) {
|
if (radius > 0) {
|
||||||
radius = radius/2;
|
radius = radius / 2;
|
||||||
} else {
|
} else {
|
||||||
radius = randomDouble() + 0.1;
|
radius = randomDouble() + 0.1;
|
||||||
}
|
}
|
|
@ -6,11 +6,10 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
|
||||||
import org.locationtech.spatial4j.shape.Rectangle;
|
import org.locationtech.spatial4j.shape.Rectangle;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -39,31 +38,40 @@ public class EnvelopeBuilderTests extends AbstractShapeBuilderTestCase<EnvelopeB
|
||||||
EnvelopeBuilder mutation = copyShape(original);
|
EnvelopeBuilder mutation = copyShape(original);
|
||||||
// move one corner to the middle of original
|
// move one corner to the middle of original
|
||||||
switch (randomIntBetween(0, 3)) {
|
switch (randomIntBetween(0, 3)) {
|
||||||
case 0:
|
case 0:
|
||||||
mutation = new EnvelopeBuilder(
|
mutation = new EnvelopeBuilder(
|
||||||
new Coordinate(randomDoubleBetween(-180.0, original.bottomRight().x, true), original.topLeft().y),
|
new Coordinate(randomDoubleBetween(-180.0, original.bottomRight().x, true), original.topLeft().y),
|
||||||
original.bottomRight());
|
original.bottomRight()
|
||||||
break;
|
);
|
||||||
case 1:
|
break;
|
||||||
mutation = new EnvelopeBuilder(new Coordinate(original.topLeft().x, randomDoubleBetween(original.bottomRight().y, 90.0, true)),
|
case 1:
|
||||||
original.bottomRight());
|
mutation = new EnvelopeBuilder(
|
||||||
break;
|
new Coordinate(original.topLeft().x, randomDoubleBetween(original.bottomRight().y, 90.0, true)),
|
||||||
case 2:
|
original.bottomRight()
|
||||||
mutation = new EnvelopeBuilder(original.topLeft(),
|
);
|
||||||
new Coordinate(randomDoubleBetween(original.topLeft().x, 180.0, true), original.bottomRight().y));
|
break;
|
||||||
break;
|
case 2:
|
||||||
case 3:
|
mutation = new EnvelopeBuilder(
|
||||||
mutation = new EnvelopeBuilder(original.topLeft(),
|
original.topLeft(),
|
||||||
new Coordinate(original.bottomRight().x, randomDoubleBetween(-90.0, original.topLeft().y, true)));
|
new Coordinate(randomDoubleBetween(original.topLeft().x, 180.0, true), original.bottomRight().y)
|
||||||
break;
|
);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mutation = new EnvelopeBuilder(
|
||||||
|
original.topLeft(),
|
||||||
|
new Coordinate(original.bottomRight().x, randomDoubleBetween(-90.0, original.topLeft().y, true))
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return mutation;
|
return mutation;
|
||||||
}
|
}
|
||||||
|
|
||||||
static EnvelopeBuilder createRandomShape() {
|
static EnvelopeBuilder createRandomShape() {
|
||||||
Rectangle box = RandomShapeGenerator.xRandomRectangle(random(), RandomShapeGenerator.xRandomPoint(random()));
|
Rectangle box = RandomShapeGenerator.xRandomRectangle(random(), RandomShapeGenerator.xRandomPoint(random()));
|
||||||
EnvelopeBuilder envelope = new EnvelopeBuilder(new Coordinate(box.getMinX(), box.getMaxY()),
|
EnvelopeBuilder envelope = new EnvelopeBuilder(
|
||||||
new Coordinate(box.getMaxX(), box.getMinY()));
|
new Coordinate(box.getMinX(), box.getMaxY()),
|
||||||
|
new Coordinate(box.getMaxX(), box.getMinY())
|
||||||
|
);
|
||||||
return envelope;
|
return envelope;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class GeometryCollectionBuilderTests extends AbstractShapeBuilderTestCase<GeometryCollectionBuilder> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected GeometryCollectionBuilder createTestShapeBuilder() {
|
||||||
|
GeometryCollectionBuilder geometryCollection = new GeometryCollectionBuilder();
|
||||||
|
int shapes = randomIntBetween(0, 8);
|
||||||
|
for (int i = 0; i < shapes; i++) {
|
||||||
|
switch (randomIntBetween(0, 7)) {
|
||||||
|
case 0:
|
||||||
|
geometryCollection.shape(PointBuilderTests.createRandomShape());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
geometryCollection.shape(CircleBuilderTests.createRandomShape());
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
geometryCollection.shape(EnvelopeBuilderTests.createRandomShape());
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
geometryCollection.shape(LineStringBuilderTests.createRandomShape());
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
geometryCollection.shape(MultiLineStringBuilderTests.createRandomShape());
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
geometryCollection.shape(MultiPolygonBuilderTests.createRandomShape());
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
geometryCollection.shape(MultiPointBuilderTests.createRandomShape());
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
geometryCollection.shape(PolygonBuilderTests.createRandomShape());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return geometryCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected GeometryCollectionBuilder createMutation(GeometryCollectionBuilder original) throws IOException {
|
||||||
|
return mutate(original);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GeometryCollectionBuilder mutate(GeometryCollectionBuilder original) throws IOException {
|
||||||
|
GeometryCollectionBuilder mutation = copyShape(original);
|
||||||
|
if (mutation.shapes.size() > 0) {
|
||||||
|
int shapePosition = randomIntBetween(0, mutation.shapes.size() - 1);
|
||||||
|
ShapeBuilder<?, ?, ?> shapeToChange = mutation.shapes.get(shapePosition);
|
||||||
|
switch (shapeToChange.type()) {
|
||||||
|
case POINT:
|
||||||
|
shapeToChange = PointBuilderTests.mutate((PointBuilder) shapeToChange);
|
||||||
|
break;
|
||||||
|
case CIRCLE:
|
||||||
|
shapeToChange = CircleBuilderTests.mutate((CircleBuilder) shapeToChange);
|
||||||
|
break;
|
||||||
|
case ENVELOPE:
|
||||||
|
shapeToChange = EnvelopeBuilderTests.mutate((EnvelopeBuilder) shapeToChange);
|
||||||
|
break;
|
||||||
|
case LINESTRING:
|
||||||
|
shapeToChange = LineStringBuilderTests.mutate((LineStringBuilder) shapeToChange);
|
||||||
|
break;
|
||||||
|
case MULTILINESTRING:
|
||||||
|
shapeToChange = MultiLineStringBuilderTests.mutate((MultiLineStringBuilder) shapeToChange);
|
||||||
|
break;
|
||||||
|
case MULTIPOLYGON:
|
||||||
|
shapeToChange = MultiPolygonBuilderTests.mutate((MultiPolygonBuilder) shapeToChange);
|
||||||
|
break;
|
||||||
|
case MULTIPOINT:
|
||||||
|
shapeToChange = MultiPointBuilderTests.mutate((MultiPointBuilder) shapeToChange);
|
||||||
|
break;
|
||||||
|
case POLYGON:
|
||||||
|
shapeToChange = PolygonBuilderTests.mutate((PolygonBuilder) shapeToChange);
|
||||||
|
break;
|
||||||
|
case GEOMETRYCOLLECTION:
|
||||||
|
throw new UnsupportedOperationException("GeometryCollection should not be nested inside each other");
|
||||||
|
}
|
||||||
|
mutation.shapes.set(shapePosition, shapeToChange);
|
||||||
|
} else {
|
||||||
|
mutation.shape(RandomShapeGenerator.createShape(random()));
|
||||||
|
}
|
||||||
|
return mutation;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,10 +6,10 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator;
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator.ShapeType;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
|
@ -6,11 +6,11 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator;
|
||||||
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator.ShapeType;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
|
@ -6,13 +6,12 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator;
|
||||||
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator.ShapeType;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -57,7 +56,7 @@ public class MultiPointBuilderTests extends AbstractShapeBuilderTestCase<MultiPo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
coordinates = new Coordinate[]{new Coordinate(1.0, 1.0)};
|
coordinates = new Coordinate[] { new Coordinate(1.0, 1.0) };
|
||||||
}
|
}
|
||||||
return MultiPointBuilder.class.cast(mutation.coordinates(coordinates));
|
return MultiPointBuilder.class.cast(mutation.coordinates(coordinates));
|
||||||
}
|
}
|
|
@ -6,11 +6,11 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.Orientation;
|
import org.elasticsearch.common.geo.Orientation;
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator;
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator.ShapeType;
|
||||||
import org.locationtech.spatial4j.exception.InvalidShapeException;
|
import org.locationtech.spatial4j.exception.InvalidShapeException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -59,82 +59,79 @@ public class MultiPolygonBuilderTests extends AbstractShapeBuilderTestCase<Multi
|
||||||
public void testInvalidPolygonBuilders() {
|
public void testInvalidPolygonBuilders() {
|
||||||
try {
|
try {
|
||||||
// self intersection polygon
|
// self intersection polygon
|
||||||
new PolygonBuilder(new CoordinatesBuilder()
|
new PolygonBuilder(
|
||||||
.coordinate(-10, -10)
|
new CoordinatesBuilder().coordinate(-10, -10).coordinate(10, 10).coordinate(-10, 10).coordinate(10, -10).close()
|
||||||
.coordinate(10, 10)
|
).buildS4J();
|
||||||
.coordinate(-10, 10)
|
|
||||||
.coordinate(10, -10)
|
|
||||||
.close())
|
|
||||||
.buildS4J();
|
|
||||||
fail("Self intersection not detected");
|
fail("Self intersection not detected");
|
||||||
} catch (InvalidShapeException e) {
|
} catch (InvalidShapeException e) {}
|
||||||
}
|
|
||||||
|
|
||||||
// polygon with hole
|
// polygon with hole
|
||||||
new PolygonBuilder(new CoordinatesBuilder()
|
new PolygonBuilder(new CoordinatesBuilder().coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close())
|
||||||
.coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close())
|
.hole(
|
||||||
.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(-5, -5).coordinate(-5, 5).coordinate(5, 5)
|
new LineStringBuilder(
|
||||||
.coordinate(5, -5).close()))
|
new CoordinatesBuilder().coordinate(-5, -5).coordinate(-5, 5).coordinate(5, 5).coordinate(5, -5).close()
|
||||||
|
)
|
||||||
|
)
|
||||||
.buildS4J();
|
.buildS4J();
|
||||||
try {
|
try {
|
||||||
// polygon with overlapping hole
|
// polygon with overlapping hole
|
||||||
new PolygonBuilder(new CoordinatesBuilder()
|
new PolygonBuilder(
|
||||||
.coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close())
|
new CoordinatesBuilder().coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close()
|
||||||
.hole(new LineStringBuilder(new CoordinatesBuilder()
|
).hole(
|
||||||
.coordinate(-5, -5).coordinate(-5, 11).coordinate(5, 11).coordinate(5, -5).close()))
|
new LineStringBuilder(
|
||||||
.buildS4J();
|
new CoordinatesBuilder().coordinate(-5, -5).coordinate(-5, 11).coordinate(5, 11).coordinate(5, -5).close()
|
||||||
|
)
|
||||||
|
).buildS4J();
|
||||||
|
|
||||||
fail("Self intersection not detected");
|
fail("Self intersection not detected");
|
||||||
} catch (InvalidShapeException e) {
|
} catch (InvalidShapeException e) {}
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// polygon with intersection holes
|
// polygon with intersection holes
|
||||||
new PolygonBuilder(new CoordinatesBuilder()
|
new PolygonBuilder(
|
||||||
.coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close())
|
new CoordinatesBuilder().coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close()
|
||||||
.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(-5, -5).coordinate(-5, 5).coordinate(5, 5)
|
).hole(
|
||||||
.coordinate(5, -5).close()))
|
new LineStringBuilder(
|
||||||
.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(-5, -6).coordinate(5, -6).coordinate(5, -4)
|
new CoordinatesBuilder().coordinate(-5, -5).coordinate(-5, 5).coordinate(5, 5).coordinate(5, -5).close()
|
||||||
.coordinate(-5, -4).close()))
|
)
|
||||||
|
)
|
||||||
|
.hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-5, -6).coordinate(5, -6).coordinate(5, -4).coordinate(-5, -4).close()
|
||||||
|
)
|
||||||
|
)
|
||||||
.buildS4J();
|
.buildS4J();
|
||||||
fail("Intersection of holes not detected");
|
fail("Intersection of holes not detected");
|
||||||
} catch (InvalidShapeException e) {
|
} catch (InvalidShapeException e) {}
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Common line in polygon
|
// Common line in polygon
|
||||||
new PolygonBuilder(new CoordinatesBuilder()
|
new PolygonBuilder(
|
||||||
.coordinate(-10, -10)
|
|
||||||
.coordinate(-10, 10)
|
|
||||||
.coordinate(-5, 10)
|
|
||||||
.coordinate(-5, -5)
|
|
||||||
.coordinate(-5, 20)
|
|
||||||
.coordinate(10, 20)
|
|
||||||
.coordinate(10, -10)
|
|
||||||
.close())
|
|
||||||
.buildS4J();
|
|
||||||
fail("Self intersection not detected");
|
|
||||||
} catch (InvalidShapeException e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Multipolygon: polygon with hole and polygon within the whole
|
|
||||||
new MultiPolygonBuilder()
|
|
||||||
.polygon(new PolygonBuilder(
|
|
||||||
new CoordinatesBuilder().coordinate(-10, -10)
|
new CoordinatesBuilder().coordinate(-10, -10)
|
||||||
.coordinate(-10, 10)
|
.coordinate(-10, 10)
|
||||||
.coordinate(10, 10)
|
.coordinate(-5, 10)
|
||||||
.coordinate(10, -10).close())
|
.coordinate(-5, -5)
|
||||||
.hole(new LineStringBuilder(
|
.coordinate(-5, 20)
|
||||||
new CoordinatesBuilder().coordinate(-5, -5)
|
.coordinate(10, 20)
|
||||||
.coordinate(-5, 5)
|
.coordinate(10, -10)
|
||||||
.coordinate(5, 5)
|
.close()
|
||||||
.coordinate(5, -5).close())))
|
).buildS4J();
|
||||||
.polygon(new PolygonBuilder(
|
fail("Self intersection not detected");
|
||||||
new CoordinatesBuilder()
|
} catch (InvalidShapeException e) {}
|
||||||
.coordinate(-4, -4)
|
|
||||||
.coordinate(-4, 4)
|
// Multipolygon: polygon with hole and polygon within the whole
|
||||||
.coordinate(4, 4)
|
new MultiPolygonBuilder().polygon(
|
||||||
.coordinate(4, -4).close()))
|
new PolygonBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-10, -10).coordinate(-10, 10).coordinate(10, 10).coordinate(10, -10).close()
|
||||||
|
).hole(
|
||||||
|
new LineStringBuilder(
|
||||||
|
new CoordinatesBuilder().coordinate(-5, -5).coordinate(-5, 5).coordinate(5, 5).coordinate(5, -5).close()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.polygon(
|
||||||
|
new PolygonBuilder(new CoordinatesBuilder().coordinate(-4, -4).coordinate(-4, 4).coordinate(4, 4).coordinate(4, -4).close())
|
||||||
|
)
|
||||||
.buildS4J();
|
.buildS4J();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,11 +6,11 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator;
|
||||||
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator.ShapeType;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -34,5 +34,4 @@ public class PointBuilderTests extends AbstractShapeBuilderTestCase<PointBuilder
|
||||||
return (PointBuilder) RandomShapeGenerator.createShape(random(), ShapeType.POINT);
|
return (PointBuilder) RandomShapeGenerator.createShape(random(), ShapeType.POINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -6,12 +6,12 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
package org.elasticsearch.legacygeo.builders;
|
||||||
|
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
|
||||||
import org.elasticsearch.common.geo.Orientation;
|
import org.elasticsearch.common.geo.Orientation;
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator;
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator.ShapeType;
|
import org.elasticsearch.legacygeo.test.RandomShapeGenerator.ShapeType;
|
||||||
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.spatial4j.exception.InvalidShapeException;
|
import org.locationtech.spatial4j.exception.InvalidShapeException;
|
||||||
import org.locationtech.spatial4j.shape.jts.JtsGeometry;
|
import org.locationtech.spatial4j.shape.jts.JtsGeometry;
|
||||||
|
|
||||||
|
@ -70,8 +70,10 @@ public class PolygonBuilderTests extends AbstractShapeBuilderTestCase<PolygonBui
|
||||||
* This is done so we don't have to expose a setter for orientation in the actual class
|
* This is done so we don't have to expose a setter for orientation in the actual class
|
||||||
*/
|
*/
|
||||||
private static PolygonBuilder polyWithOposingOrientation(PolygonBuilder pb) {
|
private static PolygonBuilder polyWithOposingOrientation(PolygonBuilder pb) {
|
||||||
PolygonBuilder mutation = new PolygonBuilder(pb.shell(),
|
PolygonBuilder mutation = new PolygonBuilder(
|
||||||
pb.orientation() == Orientation.LEFT ? Orientation.RIGHT : Orientation.LEFT);
|
pb.shell(),
|
||||||
|
pb.orientation() == Orientation.LEFT ? Orientation.RIGHT : Orientation.LEFT
|
||||||
|
);
|
||||||
for (LineStringBuilder hole : pb.holes()) {
|
for (LineStringBuilder hole : pb.holes()) {
|
||||||
mutation.hole(hole);
|
mutation.hole(hole);
|
||||||
}
|
}
|
||||||
|
@ -87,30 +89,39 @@ public class PolygonBuilderTests extends AbstractShapeBuilderTestCase<PolygonBui
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCoerceShell() {
|
public void testCoerceShell() {
|
||||||
try{
|
try {
|
||||||
new PolygonBuilder(new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0)
|
new PolygonBuilder(
|
||||||
.coordinate(1.0, 0.0).coordinate(1.0, 1.0).build()), Orientation.RIGHT);
|
new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0).coordinate(1.0, 0.0).coordinate(1.0, 1.0).build()),
|
||||||
|
Orientation.RIGHT
|
||||||
|
);
|
||||||
fail("should raise validation exception");
|
fail("should raise validation exception");
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
assertEquals("invalid number of points in LinearRing (found [3] - must be >= 4)", e.getMessage());
|
assertEquals("invalid number of points in LinearRing (found [3] - must be >= 4)", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
PolygonBuilder pb = new PolygonBuilder(new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0)
|
PolygonBuilder pb = new PolygonBuilder(
|
||||||
.coordinate(1.0, 0.0).coordinate(1.0, 1.0).build()), Orientation.RIGHT, true);
|
new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0).coordinate(1.0, 0.0).coordinate(1.0, 1.0).build()),
|
||||||
|
Orientation.RIGHT,
|
||||||
|
true
|
||||||
|
);
|
||||||
assertThat("Shell should have been closed via coerce", pb.shell().coordinates(false).length, equalTo(4));
|
assertThat("Shell should have been closed via coerce", pb.shell().coordinates(false).length, equalTo(4));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCoerceHole() {
|
public void testCoerceHole() {
|
||||||
PolygonBuilder pb = new PolygonBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0)
|
PolygonBuilder pb = new PolygonBuilder(
|
||||||
.coordinate(2.0, 0.0).coordinate(2.0, 2.0).coordinate(0.0, 0.0));
|
new CoordinatesBuilder().coordinate(0.0, 0.0).coordinate(2.0, 0.0).coordinate(2.0, 2.0).coordinate(0.0, 0.0)
|
||||||
try{
|
);
|
||||||
pb.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0,0.0).coordinate(1.0,0.0).coordinate(1.0,1.0).build()));
|
try {
|
||||||
|
pb.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0).coordinate(1.0, 0.0).coordinate(1.0, 1.0).build()));
|
||||||
fail("should raise validation exception");
|
fail("should raise validation exception");
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
assertEquals("invalid number of points in LinearRing (found [3] - must be >= 4)", e.getMessage());
|
assertEquals("invalid number of points in LinearRing (found [3] - must be >= 4)", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
pb.hole(new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0,0.0).coordinate(1.0,0.0).coordinate(1.0,1.0).build()), true);
|
pb.hole(
|
||||||
|
new LineStringBuilder(new CoordinatesBuilder().coordinate(0.0, 0.0).coordinate(1.0, 0.0).coordinate(1.0, 1.0).build()),
|
||||||
|
true
|
||||||
|
);
|
||||||
assertThat("hole should have been closed via coerce", pb.holes().get(0).coordinates(false).length, equalTo(4));
|
assertThat("hole should have been closed via coerce", pb.holes().get(0).coordinates(false).length, equalTo(4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,26 +151,43 @@ public class PolygonBuilderTests extends AbstractShapeBuilderTestCase<PolygonBui
|
||||||
// ES to believe that it crosses the dateline and "fixing" it in a way
|
// ES to believe that it crosses the dateline and "fixing" it in a way
|
||||||
// that self-intersects.
|
// that self-intersects.
|
||||||
|
|
||||||
PolygonBuilder pb = new PolygonBuilder(new CoordinatesBuilder()
|
PolygonBuilder pb = new PolygonBuilder(
|
||||||
.coordinate(10, -20).coordinate(100, 0).coordinate(-100, 0).coordinate(20, -45).coordinate(40, -60).close());
|
new CoordinatesBuilder().coordinate(10, -20)
|
||||||
|
.coordinate(100, 0)
|
||||||
|
.coordinate(-100, 0)
|
||||||
|
.coordinate(20, -45)
|
||||||
|
.coordinate(40, -60)
|
||||||
|
.close()
|
||||||
|
);
|
||||||
pb.buildS4J(); // Should not throw an exception
|
pb.buildS4J(); // Should not throw an exception
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPolygonWithUndefinedOrientationDueToCollinearPoints() {
|
public void testPolygonWithUndefinedOrientationDueToCollinearPoints() {
|
||||||
PolygonBuilder pb = new PolygonBuilder(new CoordinatesBuilder()
|
PolygonBuilder pb = new PolygonBuilder(
|
||||||
.coordinate(0.0, 0.0).coordinate(1.0, 1.0).coordinate(-1.0, -1.0).close());
|
new CoordinatesBuilder().coordinate(0.0, 0.0).coordinate(1.0, 1.0).coordinate(-1.0, -1.0).close()
|
||||||
|
);
|
||||||
InvalidShapeException e = expectThrows(InvalidShapeException.class, pb::buildS4J);
|
InvalidShapeException e = expectThrows(InvalidShapeException.class, pb::buildS4J);
|
||||||
assertEquals("Cannot determine orientation: signed area equal to 0", e.getMessage());
|
assertEquals("Cannot determine orientation: signed area equal to 0", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCrossingDateline() {
|
public void testCrossingDateline() {
|
||||||
PolygonBuilder pb = new PolygonBuilder(new CoordinatesBuilder()
|
PolygonBuilder pb = new PolygonBuilder(
|
||||||
.coordinate(170, -10).coordinate(-170, -10).coordinate(-170, 10).coordinate(170, 10).coordinate(170, -10));
|
new CoordinatesBuilder().coordinate(170, -10)
|
||||||
|
.coordinate(-170, -10)
|
||||||
|
.coordinate(-170, 10)
|
||||||
|
.coordinate(170, 10)
|
||||||
|
.coordinate(170, -10)
|
||||||
|
);
|
||||||
JtsGeometry geometry = pb.buildS4J();
|
JtsGeometry geometry = pb.buildS4J();
|
||||||
|
|
||||||
assertTrue(geometry.getGeom() instanceof org.locationtech.jts.geom.MultiPolygon);
|
assertTrue(geometry.getGeom() instanceof org.locationtech.jts.geom.MultiPolygon);
|
||||||
pb = new PolygonBuilder(new CoordinatesBuilder()
|
pb = new PolygonBuilder(
|
||||||
.coordinate(180, -10).coordinate(-170, -5).coordinate(-170, 15).coordinate(170, -15).coordinate(180, -10));
|
new CoordinatesBuilder().coordinate(180, -10)
|
||||||
|
.coordinate(-170, -5)
|
||||||
|
.coordinate(-170, 15)
|
||||||
|
.coordinate(170, -15)
|
||||||
|
.coordinate(180, -10)
|
||||||
|
);
|
||||||
geometry = pb.buildS4J();
|
geometry = pb.buildS4J();
|
||||||
assertTrue(geometry.getGeom() instanceof org.locationtech.jts.geom.MultiPolygon);
|
assertTrue(geometry.getGeom() instanceof org.locationtech.jts.geom.MultiPolygon);
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.index.mapper;
|
package org.elasticsearch.legacygeo.mapper;
|
||||||
|
|
||||||
import org.apache.lucene.index.IndexableField;
|
import org.apache.lucene.index.IndexableField;
|
||||||
import org.apache.lucene.spatial.prefix.PrefixTreeStrategy;
|
import org.apache.lucene.spatial.prefix.PrefixTreeStrategy;
|
||||||
|
@ -13,19 +13,26 @@ import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy;
|
||||||
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
|
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
|
||||||
import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
|
import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.core.CheckedConsumer;
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.core.List;
|
|
||||||
import org.elasticsearch.common.geo.GeoUtils;
|
import org.elasticsearch.common.geo.GeoUtils;
|
||||||
import org.elasticsearch.common.geo.Orientation;
|
import org.elasticsearch.common.geo.Orientation;
|
||||||
import org.elasticsearch.common.geo.ShapeRelation;
|
import org.elasticsearch.common.geo.ShapeRelation;
|
||||||
import org.elasticsearch.common.geo.SpatialStrategy;
|
import org.elasticsearch.common.geo.SpatialStrategy;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.core.CheckedConsumer;
|
||||||
|
import org.elasticsearch.core.List;
|
||||||
import org.elasticsearch.geometry.Point;
|
import org.elasticsearch.geometry.Point;
|
||||||
|
import org.elasticsearch.index.mapper.DocumentMapper;
|
||||||
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
|
import org.elasticsearch.index.mapper.Mapper;
|
||||||
|
import org.elasticsearch.index.mapper.MapperParsingException;
|
||||||
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
|
import org.elasticsearch.index.mapper.MapperTestCase;
|
||||||
|
import org.elasticsearch.index.mapper.ParsedDocument;
|
||||||
import org.elasticsearch.index.query.SearchExecutionContext;
|
import org.elasticsearch.index.query.SearchExecutionContext;
|
||||||
|
import org.elasticsearch.legacygeo.test.TestLegacyGeoShapeFieldMapperPlugin;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
import org.elasticsearch.test.TestLegacyGeoShapeFieldMapperPlugin;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -62,12 +69,10 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
@Override
|
@Override
|
||||||
protected void registerParameters(ParameterChecker checker) throws IOException {
|
protected void registerParameters(ParameterChecker checker) throws IOException {
|
||||||
|
|
||||||
checker.registerConflictCheck("strategy",
|
checker.registerConflictCheck("strategy", fieldMapping(this::minimalMapping), fieldMapping(b -> {
|
||||||
fieldMapping(this::minimalMapping),
|
b.field("type", "geo_shape");
|
||||||
fieldMapping(b -> {
|
b.field("strategy", "term");
|
||||||
b.field("type", "geo_shape");
|
}));
|
||||||
b.field("strategy", "term");
|
|
||||||
}));
|
|
||||||
|
|
||||||
checker.registerConflictCheck("tree", b -> b.field("tree", "geohash"));
|
checker.registerConflictCheck("tree", b -> b.field("tree", "geohash"));
|
||||||
checker.registerConflictCheck("tree_levels", b -> b.field("tree_levels", 5));
|
checker.registerConflictCheck("tree_levels", b -> b.field("tree_levels", 5));
|
||||||
|
@ -87,7 +92,7 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
});
|
});
|
||||||
checker.registerUpdateCheck(b -> b.field("coerce", true), m -> {
|
checker.registerUpdateCheck(b -> b.field("coerce", true), m -> {
|
||||||
LegacyGeoShapeFieldMapper gpfm = (LegacyGeoShapeFieldMapper) m;
|
LegacyGeoShapeFieldMapper gpfm = (LegacyGeoShapeFieldMapper) m;
|
||||||
assertTrue(gpfm.coerce.value());
|
assertTrue(gpfm.coerce());
|
||||||
});
|
});
|
||||||
// TODO - distance_error_pct ends up being subsumed into a calculated value, how to test
|
// TODO - distance_error_pct ends up being subsumed into a calculated value, how to test
|
||||||
checker.registerUpdateCheck(b -> b.field("distance_error_pct", 0.8), m -> {});
|
checker.registerUpdateCheck(b -> b.field("distance_error_pct", 0.8), m -> {});
|
||||||
|
@ -133,15 +138,11 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
assertEquals(Strings.toString(mapping), mapper.mappingSource().toString());
|
assertEquals(Strings.toString(mapping), mapper.mappingSource().toString());
|
||||||
|
|
||||||
LegacyGeoShapeFieldMapper geoShapeFieldMapper = (LegacyGeoShapeFieldMapper) fieldMapper;
|
LegacyGeoShapeFieldMapper geoShapeFieldMapper = (LegacyGeoShapeFieldMapper) fieldMapper;
|
||||||
assertThat(geoShapeFieldMapper.fieldType().tree(),
|
assertThat(geoShapeFieldMapper.fieldType().tree(), equalTo(LegacyGeoShapeFieldMapper.Defaults.TREE));
|
||||||
equalTo(LegacyGeoShapeFieldMapper.Defaults.TREE));
|
|
||||||
assertThat(geoShapeFieldMapper.fieldType().treeLevels(), equalTo(0));
|
assertThat(geoShapeFieldMapper.fieldType().treeLevels(), equalTo(0));
|
||||||
assertThat(geoShapeFieldMapper.fieldType().pointsOnly(),
|
assertThat(geoShapeFieldMapper.fieldType().pointsOnly(), equalTo(LegacyGeoShapeFieldMapper.Defaults.POINTS_ONLY));
|
||||||
equalTo(LegacyGeoShapeFieldMapper.Defaults.POINTS_ONLY));
|
assertThat(geoShapeFieldMapper.fieldType().distanceErrorPct(), equalTo(LegacyGeoShapeFieldMapper.Defaults.DISTANCE_ERROR_PCT));
|
||||||
assertThat(geoShapeFieldMapper.fieldType().distanceErrorPct(),
|
assertThat(geoShapeFieldMapper.fieldType().orientation(), equalTo(Orientation.RIGHT));
|
||||||
equalTo(LegacyGeoShapeFieldMapper.Defaults.DISTANCE_ERROR_PCT));
|
|
||||||
assertThat(geoShapeFieldMapper.fieldType().orientation(),
|
|
||||||
equalTo(Orientation.RIGHT));
|
|
||||||
assertFieldWarnings("strategy");
|
assertFieldWarnings("strategy");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +155,7 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
);
|
);
|
||||||
Mapper fieldMapper = mapper.mappers().getMapper("field");
|
Mapper fieldMapper = mapper.mappers().getMapper("field");
|
||||||
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
||||||
Orientation orientation = ((LegacyGeoShapeFieldMapper)fieldMapper).fieldType().orientation();
|
Orientation orientation = ((LegacyGeoShapeFieldMapper) fieldMapper).fieldType().orientation();
|
||||||
assertThat(orientation, equalTo(Orientation.CLOCKWISE));
|
assertThat(orientation, equalTo(Orientation.CLOCKWISE));
|
||||||
assertThat(orientation, equalTo(Orientation.LEFT));
|
assertThat(orientation, equalTo(Orientation.LEFT));
|
||||||
assertThat(orientation, equalTo(Orientation.CW));
|
assertThat(orientation, equalTo(Orientation.CW));
|
||||||
|
@ -165,7 +166,7 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
);
|
);
|
||||||
fieldMapper = mapper.mappers().getMapper("field");
|
fieldMapper = mapper.mappers().getMapper("field");
|
||||||
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
||||||
orientation = ((LegacyGeoShapeFieldMapper)fieldMapper).fieldType().orientation();
|
orientation = ((LegacyGeoShapeFieldMapper) fieldMapper).fieldType().orientation();
|
||||||
assertThat(orientation, equalTo(Orientation.COUNTER_CLOCKWISE));
|
assertThat(orientation, equalTo(Orientation.COUNTER_CLOCKWISE));
|
||||||
assertThat(orientation, equalTo(Orientation.RIGHT));
|
assertThat(orientation, equalTo(Orientation.RIGHT));
|
||||||
assertThat(orientation, equalTo(Orientation.CCW));
|
assertThat(orientation, equalTo(Orientation.CCW));
|
||||||
|
@ -181,16 +182,14 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
);
|
);
|
||||||
Mapper fieldMapper = mapper.mappers().getMapper("field");
|
Mapper fieldMapper = mapper.mappers().getMapper("field");
|
||||||
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
||||||
boolean coerce = ((LegacyGeoShapeFieldMapper)fieldMapper).coerce();
|
boolean coerce = ((LegacyGeoShapeFieldMapper) fieldMapper).coerce();
|
||||||
assertThat(coerce, equalTo(true));
|
assertThat(coerce, equalTo(true));
|
||||||
|
|
||||||
// explicit false coerce test
|
// explicit false coerce test
|
||||||
mapper = createDocumentMapper(
|
mapper = createDocumentMapper(fieldMapping(b -> b.field("type", "geo_shape").field("tree", "quadtree").field("coerce", false)));
|
||||||
fieldMapping(b -> b.field("type", "geo_shape").field("tree", "quadtree").field("coerce", false))
|
|
||||||
);
|
|
||||||
fieldMapper = mapper.mappers().getMapper("field");
|
fieldMapper = mapper.mappers().getMapper("field");
|
||||||
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
||||||
coerce = ((LegacyGeoShapeFieldMapper)fieldMapper).coerce();
|
coerce = ((LegacyGeoShapeFieldMapper) fieldMapper).coerce();
|
||||||
assertThat(coerce, equalTo(false));
|
assertThat(coerce, equalTo(false));
|
||||||
assertFieldWarnings("tree", "strategy");
|
assertFieldWarnings("tree", "strategy");
|
||||||
}
|
}
|
||||||
|
@ -204,7 +203,7 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
);
|
);
|
||||||
Mapper fieldMapper = mapper.mappers().getMapper("field");
|
Mapper fieldMapper = mapper.mappers().getMapper("field");
|
||||||
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
||||||
boolean ignoreZValue = ((LegacyGeoShapeFieldMapper)fieldMapper).ignoreZValue();
|
boolean ignoreZValue = ((LegacyGeoShapeFieldMapper) fieldMapper).ignoreZValue();
|
||||||
assertThat(ignoreZValue, equalTo(true));
|
assertThat(ignoreZValue, equalTo(true));
|
||||||
|
|
||||||
// explicit false accept_z_value test
|
// explicit false accept_z_value test
|
||||||
|
@ -213,7 +212,7 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
);
|
);
|
||||||
fieldMapper = mapper.mappers().getMapper("field");
|
fieldMapper = mapper.mappers().getMapper("field");
|
||||||
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
||||||
ignoreZValue = ((LegacyGeoShapeFieldMapper)fieldMapper).ignoreZValue();
|
ignoreZValue = ((LegacyGeoShapeFieldMapper) fieldMapper).ignoreZValue();
|
||||||
assertThat(ignoreZValue, equalTo(false));
|
assertThat(ignoreZValue, equalTo(false));
|
||||||
assertFieldWarnings("strategy", "tree");
|
assertFieldWarnings("strategy", "tree");
|
||||||
}
|
}
|
||||||
|
@ -227,7 +226,7 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
);
|
);
|
||||||
Mapper fieldMapper = mapper.mappers().getMapper("field");
|
Mapper fieldMapper = mapper.mappers().getMapper("field");
|
||||||
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
||||||
boolean ignoreMalformed = ((LegacyGeoShapeFieldMapper)fieldMapper).ignoreMalformed();
|
boolean ignoreMalformed = ((LegacyGeoShapeFieldMapper) fieldMapper).ignoreMalformed();
|
||||||
assertThat(ignoreMalformed, equalTo(true));
|
assertThat(ignoreMalformed, equalTo(true));
|
||||||
|
|
||||||
// explicit false ignore_malformed test
|
// explicit false ignore_malformed test
|
||||||
|
@ -236,7 +235,7 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
);
|
);
|
||||||
fieldMapper = mapper.mappers().getMapper("field");
|
fieldMapper = mapper.mappers().getMapper("field");
|
||||||
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
||||||
ignoreMalformed = ((LegacyGeoShapeFieldMapper)fieldMapper).ignoreMalformed();
|
ignoreMalformed = ((LegacyGeoShapeFieldMapper) fieldMapper).ignoreMalformed();
|
||||||
assertThat(ignoreMalformed, equalTo(false));
|
assertThat(ignoreMalformed, equalTo(false));
|
||||||
assertFieldWarnings("tree", "strategy");
|
assertFieldWarnings("tree", "strategy");
|
||||||
}
|
}
|
||||||
|
@ -465,11 +464,21 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
LegacyGeoShapeFieldMapper geoShapeFieldMapper = (LegacyGeoShapeFieldMapper) fieldMapper;
|
LegacyGeoShapeFieldMapper geoShapeFieldMapper = (LegacyGeoShapeFieldMapper) fieldMapper;
|
||||||
assertThat(geoShapeFieldMapper.fieldType().orientation(), equalTo(Orientation.CCW));
|
assertThat(geoShapeFieldMapper.fieldType().orientation(), equalTo(Orientation.CCW));
|
||||||
|
|
||||||
Exception e = expectThrows(IllegalArgumentException.class, () -> merge(mapperService, fieldMapping(b -> b.field("type", "geo_shape")
|
Exception e = expectThrows(
|
||||||
.field("tree", "quadtree")
|
IllegalArgumentException.class,
|
||||||
.field("strategy", "term").field("precision", "1km")
|
() -> merge(
|
||||||
.field("tree_levels", 26).field("distance_error_pct", 26)
|
mapperService,
|
||||||
.field("orientation", "cw"))));
|
fieldMapping(
|
||||||
|
b -> b.field("type", "geo_shape")
|
||||||
|
.field("tree", "quadtree")
|
||||||
|
.field("strategy", "term")
|
||||||
|
.field("precision", "1km")
|
||||||
|
.field("tree_levels", 26)
|
||||||
|
.field("distance_error_pct", 26)
|
||||||
|
.field("orientation", "cw")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
assertThat(e.getMessage(), containsString("Cannot update parameter [strategy] from [recursive] to [term]"));
|
assertThat(e.getMessage(), containsString("Cannot update parameter [strategy] from [recursive] to [term]"));
|
||||||
assertThat(e.getMessage(), containsString("Cannot update parameter [tree] from [geohash] to [quadtree]"));
|
assertThat(e.getMessage(), containsString("Cannot update parameter [tree] from [geohash] to [quadtree]"));
|
||||||
assertThat(e.getMessage(), containsString("Cannot update parameter [tree_levels] from [8] to [26]"));
|
assertThat(e.getMessage(), containsString("Cannot update parameter [tree_levels] from [8] to [26]"));
|
||||||
|
@ -488,12 +497,18 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
assertThat(geoShapeFieldMapper.fieldType().orientation(), equalTo(Orientation.CCW));
|
assertThat(geoShapeFieldMapper.fieldType().orientation(), equalTo(Orientation.CCW));
|
||||||
|
|
||||||
// correct mapping
|
// correct mapping
|
||||||
merge(mapperService, fieldMapping(b -> b.field("type", "geo_shape")
|
merge(
|
||||||
.field("tree", "geohash")
|
mapperService,
|
||||||
.field("strategy", "recursive")
|
fieldMapping(
|
||||||
.field("precision", "1m")
|
b -> b.field("type", "geo_shape")
|
||||||
.field("tree_levels", 8).field("distance_error_pct", 0.001)
|
.field("tree", "geohash")
|
||||||
.field("orientation", "cw")));
|
.field("strategy", "recursive")
|
||||||
|
.field("precision", "1m")
|
||||||
|
.field("tree_levels", 8)
|
||||||
|
.field("distance_error_pct", 0.001)
|
||||||
|
.field("orientation", "cw")
|
||||||
|
)
|
||||||
|
);
|
||||||
fieldMapper = mapperService.documentMapper().mappers().getMapper("field");
|
fieldMapper = mapperService.documentMapper().mappers().getMapper("field");
|
||||||
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
||||||
|
|
||||||
|
@ -594,29 +609,32 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
assertThat(fieldMapper, instanceOf(LegacyGeoShapeFieldMapper.class));
|
||||||
LegacyGeoShapeFieldMapper geoShapeFieldMapper = (LegacyGeoShapeFieldMapper) fieldMapper;
|
LegacyGeoShapeFieldMapper geoShapeFieldMapper = (LegacyGeoShapeFieldMapper) fieldMapper;
|
||||||
|
|
||||||
ElasticsearchException e = expectThrows(ElasticsearchException.class,
|
ElasticsearchException e = expectThrows(
|
||||||
() -> geoShapeFieldMapper.fieldType().geoShapeQuery(
|
ElasticsearchException.class,
|
||||||
new Point(-10, 10), "location", SpatialStrategy.TERM, ShapeRelation.INTERSECTS, searchExecutionContext));
|
() -> geoShapeFieldMapper.fieldType()
|
||||||
assertEquals("[geo-shape] queries on [PrefixTree geo shapes] cannot be executed when " +
|
.geoShapeQuery(new Point(-10, 10), "location", SpatialStrategy.TERM, ShapeRelation.INTERSECTS, searchExecutionContext)
|
||||||
"'search.allow_expensive_queries' is set to false.", e.getMessage());
|
);
|
||||||
|
assertEquals(
|
||||||
|
"[geo-shape] queries on [PrefixTree geo shapes] cannot be executed when " + "'search.allow_expensive_queries' is set to false.",
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
assertFieldWarnings("tree", "strategy");
|
assertFieldWarnings("tree", "strategy");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String[] getParseMinimalWarnings() {
|
protected String[] getParseMinimalWarnings() {
|
||||||
return new String[]{"Parameter [strategy] is deprecated and will be removed in a future version"};
|
return new String[] { "Parameter [strategy] is deprecated and will be removed in a future version" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String[] getParseMaximalWarnings() {
|
protected String[] getParseMaximalWarnings() {
|
||||||
return new String[]{
|
return new String[] {
|
||||||
"Parameter [strategy] is deprecated and will be removed in a future version",
|
"Parameter [strategy] is deprecated and will be removed in a future version",
|
||||||
"Parameter [tree] is deprecated and will be removed in a future version",
|
"Parameter [tree] is deprecated and will be removed in a future version",
|
||||||
"Parameter [tree_levels] is deprecated and will be removed in a future version",
|
"Parameter [tree_levels] is deprecated and will be removed in a future version",
|
||||||
"Parameter [precision] is deprecated and will be removed in a future version",
|
"Parameter [precision] is deprecated and will be removed in a future version",
|
||||||
"Parameter [distance_error_pct] is deprecated and will be removed in a future version",
|
"Parameter [distance_error_pct] is deprecated and will be removed in a future version",
|
||||||
"Parameter [points_only] is deprecated and will be removed in a future version"
|
"Parameter [points_only] is deprecated and will be removed in a future version" };
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGeoShapeArrayParsing() throws Exception {
|
public void testGeoShapeArrayParsing() throws Exception {
|
||||||
|
@ -636,7 +654,7 @@ public class LegacyGeoShapeFieldMapperTests extends MapperTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertSearchable(MappedFieldType fieldType) {
|
protected void assertSearchable(MappedFieldType fieldType) {
|
||||||
//always searchable even if it uses TextSearchInfo.NONE
|
// always searchable even if it uses TextSearchInfo.NONE
|
||||||
assertTrue(fieldType.isSearchable());
|
assertTrue(fieldType.isSearchable());
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,14 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.index.mapper;
|
package org.elasticsearch.legacygeo.mapper;
|
||||||
|
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.geo.SpatialStrategy;
|
import org.elasticsearch.common.geo.SpatialStrategy;
|
||||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper.GeoShapeFieldType;
|
import org.elasticsearch.index.mapper.FieldTypeTestCase;
|
||||||
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
|
import org.elasticsearch.index.mapper.MapperBuilderContext;
|
||||||
|
import org.elasticsearch.legacygeo.mapper.LegacyGeoShapeFieldMapper.GeoShapeFieldType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -32,18 +35,18 @@ public class LegacyGeoShapeFieldTypeTests extends FieldTypeTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFetchSourceValue() throws IOException {
|
public void testFetchSourceValue() throws IOException {
|
||||||
|
MappedFieldType mapper = new LegacyGeoShapeFieldMapper.Builder("field", Version.CURRENT, false, true).build(
|
||||||
|
MapperBuilderContext.ROOT
|
||||||
|
).fieldType();
|
||||||
|
|
||||||
MappedFieldType mapper = new LegacyGeoShapeFieldMapper.Builder("field", Version.CURRENT, false, true)
|
Map<String, Object> jsonLineString = org.elasticsearch.core.Map.of(
|
||||||
.build(MapperBuilderContext.ROOT).fieldType();
|
"type",
|
||||||
|
"LineString",
|
||||||
Map<String, Object> jsonLineString = org.elasticsearch.core.Map.of("type", "LineString", "coordinates",
|
"coordinates",
|
||||||
Arrays.asList(Arrays.asList(42.0, 27.1), Arrays.asList(30.0, 50.0)));
|
Arrays.asList(Arrays.asList(42.0, 27.1), Arrays.asList(30.0, 50.0))
|
||||||
Map<String, Object> jsonPoint = org.elasticsearch.core.Map.of(
|
);
|
||||||
"type", "Point",
|
Map<String, Object> jsonPoint = org.elasticsearch.core.Map.of("type", "Point", "coordinates", Arrays.asList(14.0, 15.0));
|
||||||
"coordinates", Arrays.asList(14.0, 15.0));
|
Map<String, Object> jsonMalformed = org.elasticsearch.core.Map.of("type", "LineString", "coordinates", "foo");
|
||||||
Map<String, Object> jsonMalformed = org.elasticsearch.core.Map.of(
|
|
||||||
"type", "LineString",
|
|
||||||
"coordinates", "foo");
|
|
||||||
String wktLineString = "LINESTRING (42.0 27.1, 30.0 50.0)";
|
String wktLineString = "LINESTRING (42.0 27.1, 30.0 50.0)";
|
||||||
String wktPoint = "POINT (14.0 15.0)";
|
String wktPoint = "POINT (14.0 15.0)";
|
||||||
String wktMalformed = "POINT foo";
|
String wktMalformed = "POINT foo";
|
|
@ -6,7 +6,7 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.search.geo;
|
package org.elasticsearch.legacygeo.search;
|
||||||
|
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
|
@ -19,10 +19,11 @@ import org.elasticsearch.geo.GeometryTestUtils;
|
||||||
import org.elasticsearch.geometry.Geometry;
|
import org.elasticsearch.geometry.Geometry;
|
||||||
import org.elasticsearch.geometry.MultiPoint;
|
import org.elasticsearch.geometry.MultiPoint;
|
||||||
import org.elasticsearch.geometry.Point;
|
import org.elasticsearch.geometry.Point;
|
||||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
|
|
||||||
import org.elasticsearch.index.mapper.MapperParsingException;
|
import org.elasticsearch.index.mapper.MapperParsingException;
|
||||||
|
import org.elasticsearch.legacygeo.mapper.LegacyGeoShapeFieldMapper;
|
||||||
|
import org.elasticsearch.legacygeo.test.TestLegacyGeoShapeFieldMapperPlugin;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
import org.elasticsearch.test.TestLegacyGeoShapeFieldMapperPlugin;
|
import org.elasticsearch.search.geo.GeoShapeQueryTestCase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -39,8 +40,7 @@ public class LegacyGeoShapeQueryTests extends GeoShapeQueryTestCase {
|
||||||
|
|
||||||
private static final String[] PREFIX_TREES = new String[] {
|
private static final String[] PREFIX_TREES = new String[] {
|
||||||
LegacyGeoShapeFieldMapper.PrefixTrees.GEOHASH,
|
LegacyGeoShapeFieldMapper.PrefixTrees.GEOHASH,
|
||||||
LegacyGeoShapeFieldMapper.PrefixTrees.QUADTREE
|
LegacyGeoShapeFieldMapper.PrefixTrees.QUADTREE };
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Collection<Class<? extends Plugin>> getPlugins() {
|
protected Collection<Class<? extends Plugin>> getPlugins() {
|
||||||
|
@ -49,8 +49,10 @@ public class LegacyGeoShapeQueryTests extends GeoShapeQueryTestCase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createMapping(String indexName, String type, String fieldName, Settings settings) throws Exception {
|
protected void createMapping(String indexName, String type, String fieldName, Settings settings) throws Exception {
|
||||||
final XContentBuilder xcb = XContentFactory.jsonBuilder().startObject()
|
final XContentBuilder xcb = XContentFactory.jsonBuilder()
|
||||||
.startObject("properties").startObject(fieldName)
|
.startObject()
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject(fieldName)
|
||||||
.field("type", "geo_shape")
|
.field("type", "geo_shape")
|
||||||
.field("tree", randomFrom(PREFIX_TREES))
|
.field("tree", randomFrom(PREFIX_TREES))
|
||||||
.endObject()
|
.endObject()
|
||||||
|
@ -65,59 +67,72 @@ public class LegacyGeoShapeQueryTests extends GeoShapeQueryTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPointsOnlyExplicit() throws Exception {
|
public void testPointsOnlyExplicit() throws Exception {
|
||||||
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
|
String mapping = Strings.toString(
|
||||||
.startObject("properties").startObject(defaultGeoFieldName)
|
XContentFactory.jsonBuilder()
|
||||||
.field("type", "geo_shape")
|
.startObject()
|
||||||
.field("tree", randomBoolean() ? "quadtree" : "geohash")
|
.startObject("properties")
|
||||||
.field("tree_levels", "6")
|
.startObject(defaultGeoFieldName)
|
||||||
.field("distance_error_pct", "0.01")
|
.field("type", "geo_shape")
|
||||||
.field("points_only", true)
|
.field("tree", randomBoolean() ? "quadtree" : "geohash")
|
||||||
.endObject()
|
.field("tree_levels", "6")
|
||||||
.endObject().endObject());
|
.field("distance_error_pct", "0.01")
|
||||||
|
.field("points_only", true)
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
);
|
||||||
|
|
||||||
client().admin().indices().prepareCreate("geo_points_only").addMapping(defaultType, mapping, XContentType.JSON).get();
|
client().admin().indices().prepareCreate("geo_points_only").addMapping(defaultType, mapping, XContentType.JSON).get();
|
||||||
ensureGreen();
|
ensureGreen();
|
||||||
|
|
||||||
// MULTIPOINT
|
// MULTIPOINT
|
||||||
MultiPoint multiPoint = GeometryTestUtils.randomMultiPoint(false);
|
MultiPoint multiPoint = GeometryTestUtils.randomMultiPoint(false);
|
||||||
client().prepareIndex("geo_points_only", defaultType).setId("1")
|
client().prepareIndex("geo_points_only", defaultType)
|
||||||
|
.setId("1")
|
||||||
.setSource(GeoJson.toXContent(multiPoint, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
|
.setSource(GeoJson.toXContent(multiPoint, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
|
||||||
.setRefreshPolicy(IMMEDIATE).get();
|
.setRefreshPolicy(IMMEDIATE)
|
||||||
|
.get();
|
||||||
|
|
||||||
// POINT
|
// POINT
|
||||||
Point point = GeometryTestUtils.randomPoint(false);
|
Point point = GeometryTestUtils.randomPoint(false);
|
||||||
client().prepareIndex("geo_points_only", defaultType).setId("2")
|
client().prepareIndex("geo_points_only", defaultType)
|
||||||
|
.setId("2")
|
||||||
.setSource(GeoJson.toXContent(point, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
|
.setSource(GeoJson.toXContent(point, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
|
||||||
.setRefreshPolicy(IMMEDIATE).get();
|
.setRefreshPolicy(IMMEDIATE)
|
||||||
|
.get();
|
||||||
|
|
||||||
// test that point was inserted
|
// test that point was inserted
|
||||||
SearchResponse response = client().prepareSearch("geo_points_only")
|
SearchResponse response = client().prepareSearch("geo_points_only").setQuery(matchAllQuery()).get();
|
||||||
.setQuery(matchAllQuery())
|
|
||||||
.get();
|
|
||||||
|
|
||||||
assertEquals(2, response.getHits().getTotalHits().value);
|
assertEquals(2, response.getHits().getTotalHits().value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPointsOnly() throws Exception {
|
public void testPointsOnly() throws Exception {
|
||||||
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
|
String mapping = Strings.toString(
|
||||||
.startObject("properties").startObject(defaultGeoFieldName)
|
XContentFactory.jsonBuilder()
|
||||||
.field("type", "geo_shape")
|
.startObject()
|
||||||
.field("tree", randomBoolean() ? "quadtree" : "geohash")
|
.startObject("properties")
|
||||||
.field("tree_levels", "6")
|
.startObject(defaultGeoFieldName)
|
||||||
.field("distance_error_pct", "0.01")
|
.field("type", "geo_shape")
|
||||||
.field("points_only", true)
|
.field("tree", randomBoolean() ? "quadtree" : "geohash")
|
||||||
.endObject()
|
.field("tree_levels", "6")
|
||||||
.endObject().endObject());
|
.field("distance_error_pct", "0.01")
|
||||||
|
.field("points_only", true)
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
);
|
||||||
|
|
||||||
client().admin().indices().prepareCreate("geo_points_only").addMapping(defaultType, mapping, XContentType.JSON).get();
|
client().admin().indices().prepareCreate("geo_points_only").addMapping(defaultType, mapping, XContentType.JSON).get();
|
||||||
ensureGreen();
|
ensureGreen();
|
||||||
|
|
||||||
Geometry geometry = GeometryTestUtils.randomGeometry(false);
|
Geometry geometry = GeometryTestUtils.randomGeometry(false);
|
||||||
try {
|
try {
|
||||||
client().prepareIndex("geo_points_only", defaultType).setId("1")
|
client().prepareIndex("geo_points_only", defaultType)
|
||||||
|
.setId("1")
|
||||||
.setSource(GeoJson.toXContent(geometry, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
|
.setSource(GeoJson.toXContent(geometry, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
|
||||||
.setRefreshPolicy(IMMEDIATE).get();
|
.setRefreshPolicy(IMMEDIATE)
|
||||||
|
.get();
|
||||||
} catch (MapperParsingException e) {
|
} catch (MapperParsingException e) {
|
||||||
// Random geometry generator created something other than a POINT type, verify the correct exception is thrown
|
// Random geometry generator created something other than a POINT type, verify the correct exception is thrown
|
||||||
assertThat(e.getMessage(), containsString("is configured for points only"));
|
assertThat(e.getMessage(), containsString("is configured for points only"));
|
||||||
|
@ -125,37 +140,40 @@ public class LegacyGeoShapeQueryTests extends GeoShapeQueryTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// test that point was inserted
|
// test that point was inserted
|
||||||
SearchResponse response =
|
SearchResponse response = client().prepareSearch("geo_points_only")
|
||||||
client().prepareSearch("geo_points_only").setQuery(geoIntersectionQuery(defaultGeoFieldName, geometry)).get();
|
.setQuery(geoIntersectionQuery(defaultGeoFieldName, geometry))
|
||||||
|
.get();
|
||||||
assertEquals(1, response.getHits().getTotalHits().value);
|
assertEquals(1, response.getHits().getTotalHits().value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFieldAlias() throws IOException {
|
public void testFieldAlias() throws IOException {
|
||||||
String mapping = Strings.toString(XContentFactory.jsonBuilder()
|
String mapping = Strings.toString(
|
||||||
.startObject()
|
XContentFactory.jsonBuilder()
|
||||||
.startObject("properties")
|
.startObject()
|
||||||
.startObject(defaultGeoFieldName)
|
.startObject("properties")
|
||||||
.field("type", "geo_shape")
|
.startObject(defaultGeoFieldName)
|
||||||
.field("tree", randomBoolean() ? "quadtree" : "geohash")
|
.field("type", "geo_shape")
|
||||||
.endObject()
|
.field("tree", randomBoolean() ? "quadtree" : "geohash")
|
||||||
.startObject("alias")
|
.endObject()
|
||||||
.field("type", "alias")
|
.startObject("alias")
|
||||||
.field("path", defaultGeoFieldName)
|
.field("type", "alias")
|
||||||
.endObject()
|
.field("path", defaultGeoFieldName)
|
||||||
.endObject()
|
.endObject()
|
||||||
.endObject());
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
);
|
||||||
|
|
||||||
client().admin().indices().prepareCreate(defaultIndexName).addMapping(defaultType, mapping, XContentType.JSON).get();
|
client().admin().indices().prepareCreate(defaultIndexName).addMapping(defaultType, mapping, XContentType.JSON).get();
|
||||||
ensureGreen();
|
ensureGreen();
|
||||||
|
|
||||||
MultiPoint multiPoint = GeometryTestUtils.randomMultiPoint(false);
|
MultiPoint multiPoint = GeometryTestUtils.randomMultiPoint(false);
|
||||||
client().prepareIndex(defaultIndexName, defaultType).setId("1")
|
client().prepareIndex(defaultIndexName, defaultType)
|
||||||
|
.setId("1")
|
||||||
.setSource(GeoJson.toXContent(multiPoint, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
|
.setSource(GeoJson.toXContent(multiPoint, jsonBuilder().startObject().field(defaultGeoFieldName), null).endObject())
|
||||||
.setRefreshPolicy(IMMEDIATE).get();
|
.setRefreshPolicy(IMMEDIATE)
|
||||||
|
|
||||||
SearchResponse response = client().prepareSearch(defaultIndexName)
|
|
||||||
.setQuery(geoShapeQuery("alias", multiPoint))
|
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
|
SearchResponse response = client().prepareSearch(defaultIndexName).setQuery(geoShapeQuery("alias", multiPoint)).get();
|
||||||
assertEquals(1, response.getHits().getTotalHits().value);
|
assertEquals(1, response.getHits().getTotalHits().value);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.legacygeo.search;
|
||||||
|
|
||||||
|
import org.apache.lucene.spatial.prefix.tree.Cell;
|
||||||
|
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
|
||||||
|
import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
|
||||||
|
import org.elasticsearch.common.geo.GeoUtils;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.locationtech.spatial4j.context.SpatialContext;
|
||||||
|
import org.locationtech.spatial4j.distance.DistanceUtils;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||||
|
|
||||||
|
public class LegacyGeoUtilsTests extends ESTestCase {
|
||||||
|
|
||||||
|
public void testPrefixTreeCellSizes() {
|
||||||
|
assertThat(GeoUtils.EARTH_SEMI_MAJOR_AXIS, equalTo(DistanceUtils.EARTH_EQUATORIAL_RADIUS_KM * 1000));
|
||||||
|
assertThat(GeoUtils.quadTreeCellWidth(0), lessThanOrEqualTo(GeoUtils.EARTH_EQUATOR));
|
||||||
|
|
||||||
|
SpatialContext spatialContext = new SpatialContext(true);
|
||||||
|
|
||||||
|
GeohashPrefixTree geohashPrefixTree = new GeohashPrefixTree(spatialContext, GeohashPrefixTree.getMaxLevelsPossible() / 2);
|
||||||
|
Cell gNode = geohashPrefixTree.getWorldCell();
|
||||||
|
|
||||||
|
for (int i = 0; i < geohashPrefixTree.getMaxLevels(); i++) {
|
||||||
|
double width = GeoUtils.geoHashCellWidth(i);
|
||||||
|
double height = GeoUtils.geoHashCellHeight(i);
|
||||||
|
double size = GeoUtils.geoHashCellSize(i);
|
||||||
|
double degrees = 360.0 * width / GeoUtils.EARTH_EQUATOR;
|
||||||
|
int level = GeoUtils.quadTreeLevelsForPrecision(size);
|
||||||
|
|
||||||
|
assertThat(GeoUtils.quadTreeCellWidth(level), lessThanOrEqualTo(width));
|
||||||
|
assertThat(GeoUtils.quadTreeCellHeight(level), lessThanOrEqualTo(height));
|
||||||
|
assertThat(GeoUtils.geoHashLevelsForPrecision(size), equalTo(geohashPrefixTree.getLevelForDistance(degrees)));
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
"width at level " + i,
|
||||||
|
gNode.getShape().getBoundingBox().getWidth(),
|
||||||
|
equalTo(360.d * width / GeoUtils.EARTH_EQUATOR)
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
"height at level " + i,
|
||||||
|
gNode.getShape().getBoundingBox().getHeight(),
|
||||||
|
equalTo(180.d * height / GeoUtils.EARTH_POLAR_DISTANCE)
|
||||||
|
);
|
||||||
|
|
||||||
|
gNode = gNode.getNextLevelCells(null).next();
|
||||||
|
}
|
||||||
|
|
||||||
|
QuadPrefixTree quadPrefixTree = new QuadPrefixTree(spatialContext);
|
||||||
|
Cell qNode = quadPrefixTree.getWorldCell();
|
||||||
|
for (int i = 0; i < quadPrefixTree.getMaxLevels(); i++) {
|
||||||
|
|
||||||
|
double degrees = 360.0 / (1L << i);
|
||||||
|
double width = GeoUtils.quadTreeCellWidth(i);
|
||||||
|
double height = GeoUtils.quadTreeCellHeight(i);
|
||||||
|
double size = GeoUtils.quadTreeCellSize(i);
|
||||||
|
int level = GeoUtils.quadTreeLevelsForPrecision(size);
|
||||||
|
|
||||||
|
assertThat(GeoUtils.quadTreeCellWidth(level), lessThanOrEqualTo(width));
|
||||||
|
assertThat(GeoUtils.quadTreeCellHeight(level), lessThanOrEqualTo(height));
|
||||||
|
assertThat(GeoUtils.quadTreeLevelsForPrecision(size), equalTo(quadPrefixTree.getLevelForDistance(degrees)));
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
"width at level " + i,
|
||||||
|
qNode.getShape().getBoundingBox().getWidth(),
|
||||||
|
equalTo(360.d * width / GeoUtils.EARTH_EQUATOR)
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
"height at level " + i,
|
||||||
|
qNode.getShape().getBoundingBox().getHeight(),
|
||||||
|
equalTo(180.d * height / GeoUtils.EARTH_POLAR_DISTANCE)
|
||||||
|
);
|
||||||
|
|
||||||
|
qNode = qNode.getNextLevelCells(null).next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,15 +6,15 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.test.hamcrest;
|
package org.elasticsearch.legacygeo.test;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.GeoDistance;
|
import org.elasticsearch.common.geo.GeoDistance;
|
||||||
import org.elasticsearch.common.geo.GeoPoint;
|
import org.elasticsearch.common.geo.GeoPoint;
|
||||||
import org.elasticsearch.common.geo.parsers.ShapeParser;
|
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.geometry.Line;
|
import org.elasticsearch.geometry.Line;
|
||||||
import org.elasticsearch.geometry.MultiLine;
|
import org.elasticsearch.geometry.MultiLine;
|
||||||
|
import org.elasticsearch.legacygeo.parsers.ShapeParser;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
|
@ -40,13 +40,13 @@ import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class ElasticsearchGeoAssertions {
|
public class ElasticsearchGeoAssertions {
|
||||||
|
|
||||||
private static int top(Coordinate...points) {
|
private static int top(Coordinate... points) {
|
||||||
int top = 0;
|
int top = 0;
|
||||||
for (int i = 1; i < points.length; i++) {
|
for (int i = 1; i < points.length; i++) {
|
||||||
if(points[i].y < points[top].y) {
|
if (points[i].y < points[top].y) {
|
||||||
top = i;
|
top = i;
|
||||||
} else if(points[i].y == points[top].y) {
|
} else if (points[i].y == points[top].y) {
|
||||||
if(points[i].x <= points[top].x) {
|
if (points[i].x <= points[top].x) {
|
||||||
top = i;
|
top = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,20 +54,20 @@ public class ElasticsearchGeoAssertions {
|
||||||
return top;
|
return top;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int prev(int top, Coordinate...points) {
|
private static int prev(int top, Coordinate... points) {
|
||||||
for (int i = 1; i < points.length; i++) {
|
for (int i = 1; i < points.length; i++) {
|
||||||
int p = (top + points.length - i) % points.length;
|
int p = (top + points.length - i) % points.length;
|
||||||
if((points[p].x != points[top].x) || (points[p].y != points[top].y)) {
|
if ((points[p].x != points[top].x) || (points[p].y != points[top].y)) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int next(int top, Coordinate...points) {
|
private static int next(int top, Coordinate... points) {
|
||||||
for (int i = 1; i < points.length; i++) {
|
for (int i = 1; i < points.length; i++) {
|
||||||
int n = (top + i) % points.length;
|
int n = (top + i) % points.length;
|
||||||
if((points[n].x != points[top].x) || (points[n].y != points[top].y)) {
|
if ((points[n].x != points[top].x) || (points[n].y != points[top].y)) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,16 +85,16 @@ public class ElasticsearchGeoAssertions {
|
||||||
final int prev = prev(top, points);
|
final int prev = prev(top, points);
|
||||||
final boolean orientation = points[next].x < points[prev].x;
|
final boolean orientation = points[next].x < points[prev].x;
|
||||||
|
|
||||||
if(orientation != direction) {
|
if (orientation != direction) {
|
||||||
List<Coordinate> asList = Arrays.asList(points);
|
List<Coordinate> asList = Arrays.asList(points);
|
||||||
Collections.reverse(asList);
|
Collections.reverse(asList);
|
||||||
return fixedOrderedRing(asList, direction);
|
return fixedOrderedRing(asList, direction);
|
||||||
} else {
|
} else {
|
||||||
if(top>0) {
|
if (top > 0) {
|
||||||
Coordinate[] aligned = new Coordinate[points.length];
|
Coordinate[] aligned = new Coordinate[points.length];
|
||||||
System.arraycopy(points, top, aligned, 0, points.length-top-1);
|
System.arraycopy(points, top, aligned, 0, points.length - top - 1);
|
||||||
System.arraycopy(points, 0, aligned, points.length-top-1, top);
|
System.arraycopy(points, 0, aligned, points.length - top - 1, top);
|
||||||
aligned[aligned.length-1] = aligned[0];
|
aligned[aligned.length - 1] = aligned[0];
|
||||||
return aligned;
|
return aligned;
|
||||||
} else {
|
} else {
|
||||||
return points;
|
return points;
|
||||||
|
@ -108,13 +108,13 @@ public class ElasticsearchGeoAssertions {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isRing(Coordinate[] c) {
|
private static boolean isRing(Coordinate[] c) {
|
||||||
return (c[0].x == c[c.length-1].x) && (c[0].y == c[c.length-1].y);
|
return (c[0].x == c[c.length - 1].x) && (c[0].y == c[c.length - 1].y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertEquals(Coordinate[] c1, Coordinate[] c2) {
|
public static void assertEquals(Coordinate[] c1, Coordinate[] c2) {
|
||||||
Assert.assertEquals(c1.length, c2.length);
|
Assert.assertEquals(c1.length, c2.length);
|
||||||
|
|
||||||
if(isRing(c1) && isRing(c2)) {
|
if (isRing(c1) && isRing(c2)) {
|
||||||
c1 = fixedOrderedRing(c1, true);
|
c1 = fixedOrderedRing(c1, true);
|
||||||
c2 = fixedOrderedRing(c2, true);
|
c2 = fixedOrderedRing(c2, true);
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ public class ElasticsearchGeoAssertions {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertEquals(Geometry s1, Geometry s2) {
|
public static void assertEquals(Geometry s1, Geometry s2) {
|
||||||
if(s1 instanceof LineString && s2 instanceof LineString) {
|
if (s1 instanceof LineString && s2 instanceof LineString) {
|
||||||
assertEquals((LineString) s1, (LineString) s2);
|
assertEquals((LineString) s1, (LineString) s2);
|
||||||
|
|
||||||
} else if (s1 instanceof Polygon && s2 instanceof Polygon) {
|
} else if (s1 instanceof Polygon && s2 instanceof Polygon) {
|
||||||
|
@ -173,8 +173,9 @@ public class ElasticsearchGeoAssertions {
|
||||||
assertEquals((MultiLineString) s1, (MultiLineString) s2);
|
assertEquals((MultiLineString) s1, (MultiLineString) s2);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("equality of shape types not supported [" + s1.getClass().getName() + " and " +
|
throw new RuntimeException(
|
||||||
s2.getClass().getName() + "]");
|
"equality of shape types not supported [" + s1.getClass().getName() + " and " + s2.getClass().getName() + "]"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,9 +191,9 @@ public class ElasticsearchGeoAssertions {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertEquals(Object s1, Object s2) {
|
public static void assertEquals(Object s1, Object s2) {
|
||||||
if(s1 instanceof JtsGeometry && s2 instanceof JtsGeometry) {
|
if (s1 instanceof JtsGeometry && s2 instanceof JtsGeometry) {
|
||||||
assertEquals((JtsGeometry) s1, (JtsGeometry) s2);
|
assertEquals((JtsGeometry) s1, (JtsGeometry) s2);
|
||||||
} else if(s1 instanceof JtsPoint && s2 instanceof JtsPoint) {
|
} else if (s1 instanceof JtsPoint && s2 instanceof JtsPoint) {
|
||||||
JtsPoint p1 = (JtsPoint) s1;
|
JtsPoint p1 = (JtsPoint) s1;
|
||||||
JtsPoint p2 = (JtsPoint) s2;
|
JtsPoint p2 = (JtsPoint) s2;
|
||||||
Assert.assertEquals(p1, p2);
|
Assert.assertEquals(p1, p2);
|
||||||
|
@ -203,76 +204,78 @@ public class ElasticsearchGeoAssertions {
|
||||||
} else if (s1 instanceof RectangleImpl && s2 instanceof RectangleImpl) {
|
} else if (s1 instanceof RectangleImpl && s2 instanceof RectangleImpl) {
|
||||||
Assert.assertEquals(s1, s2);
|
Assert.assertEquals(s1, s2);
|
||||||
} else if (s1 instanceof org.apache.lucene.geo.Line[] && s2 instanceof org.apache.lucene.geo.Line[]) {
|
} else if (s1 instanceof org.apache.lucene.geo.Line[] && s2 instanceof org.apache.lucene.geo.Line[]) {
|
||||||
Assert.assertArrayEquals((org.apache.lucene.geo.Line[])s1, (org.apache.lucene.geo.Line[])s2);
|
Assert.assertArrayEquals((org.apache.lucene.geo.Line[]) s1, (org.apache.lucene.geo.Line[]) s2);
|
||||||
} else if (s1 instanceof org.apache.lucene.geo.Polygon[] && s2 instanceof org.apache.lucene.geo.Polygon[]) {
|
} else if (s1 instanceof org.apache.lucene.geo.Polygon[] && s2 instanceof org.apache.lucene.geo.Polygon[]) {
|
||||||
Assert.assertArrayEquals((org.apache.lucene.geo.Polygon[]) s1, (org.apache.lucene.geo.Polygon[]) s2);
|
Assert.assertArrayEquals((org.apache.lucene.geo.Polygon[]) s1, (org.apache.lucene.geo.Polygon[]) s2);
|
||||||
} else if ((s1 instanceof org.apache.lucene.geo.Line && s2 instanceof org.apache.lucene.geo.Line)
|
} else if ((s1 instanceof org.apache.lucene.geo.Line && s2 instanceof org.apache.lucene.geo.Line)
|
||||||
|| (s1 instanceof org.apache.lucene.geo.Polygon && s2 instanceof org.apache.lucene.geo.Polygon)
|
|| (s1 instanceof org.apache.lucene.geo.Polygon && s2 instanceof org.apache.lucene.geo.Polygon)
|
||||||
|| (s1 instanceof org.apache.lucene.geo.Rectangle && s2 instanceof org.apache.lucene.geo.Rectangle)
|
|| (s1 instanceof org.apache.lucene.geo.Rectangle && s2 instanceof org.apache.lucene.geo.Rectangle)
|
||||||
|| (s1 instanceof GeoPoint && s2 instanceof GeoPoint)) {
|
|| (s1 instanceof GeoPoint && s2 instanceof GeoPoint)) {
|
||||||
Assert.assertEquals(s1, s2);
|
Assert.assertEquals(s1, s2);
|
||||||
} else if (s1 instanceof Object[] && s2 instanceof Object[]) {
|
} else if (s1 instanceof Object[] && s2 instanceof Object[]) {
|
||||||
Assert.assertArrayEquals((Object[]) s1, (Object[]) s2);
|
Assert.assertArrayEquals((Object[]) s1, (Object[]) s2);
|
||||||
} else if (s1 instanceof org.elasticsearch.geometry.Geometry && s2 instanceof org.elasticsearch.geometry.Geometry) {
|
} else if (s1 instanceof org.elasticsearch.geometry.Geometry && s2 instanceof org.elasticsearch.geometry.Geometry) {
|
||||||
Assert.assertEquals(s1, s2);
|
Assert.assertEquals(s1, s2);
|
||||||
} else {
|
} else {
|
||||||
//We want to know the type of the shape because we test shape equality in a special way...
|
// We want to know the type of the shape because we test shape equality in a special way...
|
||||||
//... in particular we test that one ring is equivalent to another ring even if the points are rotated or reversed.
|
// ... in particular we test that one ring is equivalent to another ring even if the points are rotated or reversed.
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"equality of shape types not supported [" + s1.getClass().getName() + " and " + s2.getClass().getName() + "]");
|
"equality of shape types not supported [" + s1.getClass().getName() + " and " + s2.getClass().getName() + "]"
|
||||||
}
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private static Geometry unwrapJTS(Object shape) {
|
private static Geometry unwrapJTS(Object shape) {
|
||||||
assertThat(shape, instanceOf(JtsGeometry.class));
|
assertThat(shape, instanceOf(JtsGeometry.class));
|
||||||
return ((JtsGeometry)shape).getGeom();
|
return ((JtsGeometry) shape).getGeom();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertMultiPolygon(Object shape, boolean useJTS) {
|
public static void assertMultiPolygon(Object shape, boolean useJTS) {
|
||||||
if (useJTS) {
|
if (useJTS) {
|
||||||
assertTrue("expected MultiPolygon but found " + unwrapJTS(shape).getClass().getName(),
|
assertTrue(
|
||||||
unwrapJTS(shape) instanceof MultiPolygon);
|
"expected MultiPolygon but found " + unwrapJTS(shape).getClass().getName(),
|
||||||
|
unwrapJTS(shape) instanceof MultiPolygon
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
assertTrue("expected Polygon[] but found " + shape.getClass().getName(),
|
assertTrue(
|
||||||
shape instanceof org.elasticsearch.geometry.MultiPolygon);
|
"expected Polygon[] but found " + shape.getClass().getName(),
|
||||||
|
shape instanceof org.elasticsearch.geometry.MultiPolygon
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertPolygon(Object shape, boolean useJTS) {
|
public static void assertPolygon(Object shape, boolean useJTS) {
|
||||||
if (useJTS) {
|
if (useJTS) {
|
||||||
assertTrue("expected Polygon but found "
|
assertTrue("expected Polygon but found " + unwrapJTS(shape).getClass().getName(), unwrapJTS(shape) instanceof Polygon);
|
||||||
+ unwrapJTS(shape).getClass().getName(), unwrapJTS(shape) instanceof Polygon);
|
|
||||||
} else {
|
} else {
|
||||||
assertTrue("expected Polygon but found " + shape.getClass().getName(),
|
assertTrue("expected Polygon but found " + shape.getClass().getName(), shape instanceof org.elasticsearch.geometry.Polygon);
|
||||||
shape instanceof org.elasticsearch.geometry.Polygon);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertLineString(Object shape, boolean useJTS) {
|
public static void assertLineString(Object shape, boolean useJTS) {
|
||||||
if (useJTS) {
|
if (useJTS) {
|
||||||
assertTrue("expected LineString but found "
|
assertTrue("expected LineString but found " + unwrapJTS(shape).getClass().getName(), unwrapJTS(shape) instanceof LineString);
|
||||||
+ unwrapJTS(shape).getClass().getName(), unwrapJTS(shape) instanceof LineString);
|
|
||||||
} else {
|
} else {
|
||||||
assertTrue("expected Line but found " + shape.getClass().getName(),
|
assertTrue("expected Line but found " + shape.getClass().getName(), shape instanceof Line);
|
||||||
shape instanceof Line);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertMultiLineString(Object shape, boolean useJTS) {
|
public static void assertMultiLineString(Object shape, boolean useJTS) {
|
||||||
if (useJTS) {
|
if (useJTS) {
|
||||||
assertTrue("expected MultiLineString but found "
|
assertTrue(
|
||||||
+ unwrapJTS(shape).getClass().getName(), unwrapJTS(shape) instanceof MultiLineString);
|
"expected MultiLineString but found " + unwrapJTS(shape).getClass().getName(),
|
||||||
|
unwrapJTS(shape) instanceof MultiLineString
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
assertTrue("expected Line[] but found " + shape.getClass().getName(),
|
assertTrue("expected Line[] but found " + shape.getClass().getName(), shape instanceof MultiLine);
|
||||||
shape instanceof MultiLine);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertDistance(String geohash1, String geohash2, Matcher<Double> match) {
|
public static void assertDistance(String geohash1, String geohash2, Matcher<Double> match) {
|
||||||
GeoPoint p1 = new GeoPoint(geohash1);
|
GeoPoint p1 = new GeoPoint(geohash1);
|
||||||
GeoPoint p2 = new GeoPoint(geohash2);
|
GeoPoint p2 = new GeoPoint(geohash2);
|
||||||
assertDistance(p1.lat(), p1.lon(), p2.lat(),p2.lon(), match);
|
assertDistance(p1.lat(), p1.lon(), p2.lat(), p2.lon(), match);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertDistance(double lat1, double lon1, double lat2, double lon2, Matcher<Double> match) {
|
public static void assertDistance(double lat1, double lon1, double lat2, double lon2, Matcher<Double> match) {
|
||||||
|
@ -288,8 +291,10 @@ public class ElasticsearchGeoAssertions {
|
||||||
ShapeParser.parse(parser).buildS4J();
|
ShapeParser.parse(parser).buildS4J();
|
||||||
Assert.fail("process completed successfully when " + expectedException.getName() + " expected");
|
Assert.fail("process completed successfully when " + expectedException.getName() + " expected");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertTrue("expected " + expectedException.getName() + " but found " + e.getClass().getName(),
|
assertTrue(
|
||||||
e.getClass().equals(expectedException));
|
"expected " + expectedException.getName() + " but found " + e.getClass().getName(),
|
||||||
|
e.getClass().equals(expectedException)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||||
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
|
* Side Public License, v 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.legacygeo.test;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.geo.GeoPoint;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Random geo generation utilities for randomized {@code geo_point} type testing
|
||||||
|
* does not depend on jts or spatial4j. Use {@link org.elasticsearch.legacygeo.test.RandomShapeGenerator}
|
||||||
|
* to create random OGC compliant shapes.
|
||||||
|
*/
|
||||||
|
public class RandomGeoGenerator {
|
||||||
|
|
||||||
|
public static void randomPoint(Random r, double[] pt) {
|
||||||
|
final double[] min = { -180, -90 };
|
||||||
|
final double[] max = { 180, 90 };
|
||||||
|
randomPointIn(r, min[0], min[1], max[0], max[1], pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void randomPointIn(
|
||||||
|
Random r,
|
||||||
|
final double minLon,
|
||||||
|
final double minLat,
|
||||||
|
final double maxLon,
|
||||||
|
final double maxLat,
|
||||||
|
double[] pt
|
||||||
|
) {
|
||||||
|
assert pt != null && pt.length == 2;
|
||||||
|
|
||||||
|
// normalize min and max
|
||||||
|
double[] min = { normalizeLongitude(minLon), normalizeLatitude(minLat) };
|
||||||
|
double[] max = { normalizeLongitude(maxLon), normalizeLatitude(maxLat) };
|
||||||
|
final double[] tMin = new double[2];
|
||||||
|
final double[] tMax = new double[2];
|
||||||
|
tMin[0] = Math.min(min[0], max[0]);
|
||||||
|
tMax[0] = Math.max(min[0], max[0]);
|
||||||
|
tMin[1] = Math.min(min[1], max[1]);
|
||||||
|
tMax[1] = Math.max(min[1], max[1]);
|
||||||
|
|
||||||
|
pt[0] = tMin[0] + r.nextDouble() * (tMax[0] - tMin[0]);
|
||||||
|
pt[1] = tMin[1] + r.nextDouble() * (tMax[1] - tMin[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GeoPoint randomPoint(Random r) {
|
||||||
|
return randomPointIn(r, -180, -90, 180, 90);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GeoPoint randomPointIn(Random r, final double minLon, final double minLat, final double maxLon, final double maxLat) {
|
||||||
|
double[] pt = new double[2];
|
||||||
|
randomPointIn(r, minLon, minLat, maxLon, maxLat, pt);
|
||||||
|
return new GeoPoint(pt[1], pt[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Puts latitude in range of -90 to 90. */
|
||||||
|
private static double normalizeLatitude(double latitude) {
|
||||||
|
if (latitude >= -90 && latitude <= 90) {
|
||||||
|
return latitude; // common case, and avoids slight double precision shifting
|
||||||
|
}
|
||||||
|
double off = Math.abs((latitude + 90) % 360);
|
||||||
|
return (off <= 180 ? off : 360 - off) - 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Puts longitude in range of -180 to +180. */
|
||||||
|
private static double normalizeLongitude(double longitude) {
|
||||||
|
if (longitude >= -180 && longitude <= 180) {
|
||||||
|
return longitude; // common case, and avoids slight double precision shifting
|
||||||
|
}
|
||||||
|
double off = (longitude + 180) % 360;
|
||||||
|
if (off < 0) {
|
||||||
|
return 180 + off;
|
||||||
|
} else if (off == 0 && longitude > 0) {
|
||||||
|
return 180;
|
||||||
|
} else {
|
||||||
|
return -180 + off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,22 +6,23 @@
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.test.geo;
|
package org.elasticsearch.legacygeo.test;
|
||||||
|
|
||||||
import com.carrotsearch.randomizedtesting.generators.RandomNumbers;
|
import com.carrotsearch.randomizedtesting.generators.RandomNumbers;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchException;
|
||||||
|
import org.elasticsearch.legacygeo.builders.CoordinatesBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.GeometryCollectionBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.LineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiLineStringBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.MultiPointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PointBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.PolygonBuilder;
|
||||||
|
import org.elasticsearch.legacygeo.builders.ShapeBuilder;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.locationtech.jts.algorithm.ConvexHull;
|
import org.locationtech.jts.algorithm.ConvexHull;
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.jts.geom.Geometry;
|
import org.locationtech.jts.geom.Geometry;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
|
||||||
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.GeometryCollectionBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiLineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiPointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PolygonBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.locationtech.spatial4j.context.jts.JtsSpatialContext;
|
import org.locationtech.spatial4j.context.jts.JtsSpatialContext;
|
||||||
import org.locationtech.spatial4j.distance.DistanceUtils;
|
import org.locationtech.spatial4j.distance.DistanceUtils;
|
||||||
import org.locationtech.spatial4j.exception.InvalidShapeException;
|
import org.locationtech.spatial4j.exception.InvalidShapeException;
|
||||||
|
@ -44,7 +45,12 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
protected static boolean ST_VALIDATE = true;
|
protected static boolean ST_VALIDATE = true;
|
||||||
|
|
||||||
public enum ShapeType {
|
public enum ShapeType {
|
||||||
POINT, MULTIPOINT, LINESTRING, MULTILINESTRING, POLYGON;
|
POINT,
|
||||||
|
MULTIPOINT,
|
||||||
|
LINESTRING,
|
||||||
|
MULTILINESTRING,
|
||||||
|
POLYGON;
|
||||||
|
|
||||||
private static final ShapeType[] types = values();
|
private static final ShapeType[] types = values();
|
||||||
|
|
||||||
public static ShapeType randomType(Random r) {
|
public static ShapeType randomType(Random r) {
|
||||||
|
@ -84,8 +90,7 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
return createGeometryCollection(r, nearPoint, null, 0);
|
return createGeometryCollection(r, nearPoint, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GeometryCollectionBuilder createGeometryCollectionNear(Random r, Point nearPoint, int size) throws
|
public static GeometryCollectionBuilder createGeometryCollectionNear(Random r, Point nearPoint, int size) throws InvalidShapeException {
|
||||||
InvalidShapeException {
|
|
||||||
return createGeometryCollection(r, nearPoint, null, size);
|
return createGeometryCollection(r, nearPoint, null, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,13 +98,13 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
return createGeometryCollection(r, null, within, 0);
|
return createGeometryCollection(r, null, within, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GeometryCollectionBuilder createGeometryCollectionWithin(Random r, Rectangle within, int size) throws
|
public static GeometryCollectionBuilder createGeometryCollectionWithin(Random r, Rectangle within, int size)
|
||||||
InvalidShapeException {
|
throws InvalidShapeException {
|
||||||
return createGeometryCollection(r, null, within, size);
|
return createGeometryCollection(r, null, within, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static GeometryCollectionBuilder createGeometryCollection(Random r, Point nearPoint, Rectangle bounds, int numGeometries)
|
protected static GeometryCollectionBuilder createGeometryCollection(Random r, Point nearPoint, Rectangle bounds, int numGeometries)
|
||||||
throws InvalidShapeException {
|
throws InvalidShapeException {
|
||||||
if (numGeometries <= 0) {
|
if (numGeometries <= 0) {
|
||||||
// cap geometry collection at 4 shapes (to save test time)
|
// cap geometry collection at 4 shapes (to save test time)
|
||||||
numGeometries = RandomNumbers.randomIntBetween(r, 2, 4);
|
numGeometries = RandomNumbers.randomIntBetween(r, 2, 4);
|
||||||
|
@ -114,7 +119,7 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
GeometryCollectionBuilder gcb = new GeometryCollectionBuilder();
|
GeometryCollectionBuilder gcb = new GeometryCollectionBuilder();
|
||||||
for (int i=0; i<numGeometries;) {
|
for (int i = 0; i < numGeometries;) {
|
||||||
ShapeBuilder<?, ?, ?> builder = createShapeWithin(r, bounds);
|
ShapeBuilder<?, ?, ?> builder = createShapeWithin(r, bounds);
|
||||||
// due to world wrapping, and the possibility for ambiguous polygons, the random shape generation could bail with
|
// due to world wrapping, and the possibility for ambiguous polygons, the random shape generation could bail with
|
||||||
// a null shape. We catch that situation here, and only increment the counter when a valid shape is returned.
|
// a null shape. We catch that situation here, and only increment the counter when a valid shape is returned.
|
||||||
|
@ -130,7 +135,7 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
private static ShapeBuilder<?, ?, ?> createShape(Random r, Point nearPoint, Rectangle within, ShapeType st)
|
private static ShapeBuilder<?, ?, ?> createShape(Random r, Point nearPoint, Rectangle within, ShapeType st)
|
||||||
throws InvalidShapeException {
|
throws InvalidShapeException {
|
||||||
ShapeBuilder<?, ?, ?> shape;
|
ShapeBuilder<?, ?, ?> shape;
|
||||||
short i=0;
|
short i = 0;
|
||||||
do {
|
do {
|
||||||
shape = createShape(r, nearPoint, within, st, ST_VALIDATE);
|
shape = createShape(r, nearPoint, within, st, ST_VALIDATE);
|
||||||
if (shape != null) {
|
if (shape != null) {
|
||||||
|
@ -150,8 +155,8 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
* @param st Create a random shape of the provided type
|
* @param st Create a random shape of the provided type
|
||||||
* @return the ShapeBuilder for a random shape
|
* @return the ShapeBuilder for a random shape
|
||||||
*/
|
*/
|
||||||
private static ShapeBuilder<?, ?, ?> createShape(Random r, Point nearPoint, Rectangle within, ShapeType st, boolean validate) throws
|
private static ShapeBuilder<?, ?, ?> createShape(Random r, Point nearPoint, Rectangle within, ShapeType st, boolean validate)
|
||||||
InvalidShapeException {
|
throws InvalidShapeException {
|
||||||
|
|
||||||
if (st == null) {
|
if (st == null) {
|
||||||
st = ShapeType.randomType(r);
|
st = ShapeType.randomType(r);
|
||||||
|
@ -176,7 +181,7 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
// (n^2-n)/2 and computing the relation intersection matrix will become NP-Hard
|
// (n^2-n)/2 and computing the relation intersection matrix will become NP-Hard
|
||||||
int numPoints = RandomNumbers.randomIntBetween(r, 3, 10);
|
int numPoints = RandomNumbers.randomIntBetween(r, 3, 10);
|
||||||
CoordinatesBuilder coordinatesBuilder = new CoordinatesBuilder();
|
CoordinatesBuilder coordinatesBuilder = new CoordinatesBuilder();
|
||||||
for (int i=0; i<numPoints; ++i) {
|
for (int i = 0; i < numPoints; ++i) {
|
||||||
p = xRandomPointIn(r, within);
|
p = xRandomPointIn(r, within);
|
||||||
coordinatesBuilder.coordinate(p.getX(), p.getY());
|
coordinatesBuilder.coordinate(p.getX(), p.getY());
|
||||||
}
|
}
|
||||||
|
@ -186,14 +191,14 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
return pcb;
|
return pcb;
|
||||||
case MULTILINESTRING:
|
case MULTILINESTRING:
|
||||||
MultiLineStringBuilder mlsb = new MultiLineStringBuilder();
|
MultiLineStringBuilder mlsb = new MultiLineStringBuilder();
|
||||||
for (int i=0; i<RandomNumbers.randomIntBetween(r, 1, 10); ++i) {
|
for (int i = 0; i < RandomNumbers.randomIntBetween(r, 1, 10); ++i) {
|
||||||
mlsb.linestring((LineStringBuilder) createShape(r, nearPoint, within, ShapeType.LINESTRING, false));
|
mlsb.linestring((LineStringBuilder) createShape(r, nearPoint, within, ShapeType.LINESTRING, false));
|
||||||
}
|
}
|
||||||
return mlsb;
|
return mlsb;
|
||||||
case POLYGON:
|
case POLYGON:
|
||||||
numPoints = RandomNumbers.randomIntBetween(r, 5, 25);
|
numPoints = RandomNumbers.randomIntBetween(r, 5, 25);
|
||||||
Coordinate[] coordinates = new Coordinate[numPoints];
|
Coordinate[] coordinates = new Coordinate[numPoints];
|
||||||
for (int i=0; i<numPoints; ++i) {
|
for (int i = 0; i < numPoints; ++i) {
|
||||||
p = (Point) createShape(r, nearPoint, within, ShapeType.POINT, false).buildS4J();
|
p = (Point) createShape(r, nearPoint, within, ShapeType.POINT, false).buildS4J();
|
||||||
coordinates[i] = new Coordinate(p.getX(), p.getY());
|
coordinates[i] = new Coordinate(p.getX(), p.getY());
|
||||||
}
|
}
|
||||||
|
@ -236,15 +241,14 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
|
|
||||||
protected static Point xRandomPointIn(Random rand, Rectangle r) {
|
protected static Point xRandomPointIn(Random rand, Rectangle r) {
|
||||||
double[] pt = new double[2];
|
double[] pt = new double[2];
|
||||||
randomPointIn(rand, r.getMinX(), r.getMinY(), r.getMaxX(), r.getMaxY(), pt);
|
RandomGeoGenerator.randomPointIn(rand, r.getMinX(), r.getMinY(), r.getMaxX(), r.getMaxY(), pt);
|
||||||
Point p = ctx.makePoint(pt[0], pt[1]);
|
Point p = ctx.makePoint(pt[0], pt[1]);
|
||||||
Assert.assertEquals(CONTAINS, r.relate(p));
|
Assert.assertEquals(CONTAINS, r.relate(p));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Rectangle xRandomRectangle(Random r, Point nearP, Rectangle bounds, boolean small) {
|
private static Rectangle xRandomRectangle(Random r, Point nearP, Rectangle bounds, boolean small) {
|
||||||
if (nearP == null)
|
if (nearP == null) nearP = xRandomPointIn(r, bounds);
|
||||||
nearP = xRandomPointIn(r, bounds);
|
|
||||||
|
|
||||||
if (small) {
|
if (small) {
|
||||||
// between 3 and 6 degrees
|
// between 3 and 6 degrees
|
||||||
|
@ -271,10 +275,11 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
Range yRange = xRandomRange(r, rarely(r) ? 0 : nearP.getY(), Range.yRange(bounds, ctx));
|
Range yRange = xRandomRange(r, rarely(r) ? 0 : nearP.getY(), Range.yRange(bounds, ctx));
|
||||||
|
|
||||||
return xMakeNormRect(
|
return xMakeNormRect(
|
||||||
xDivisible(xRange.getMin()*10e3)/10e3,
|
xDivisible(xRange.getMin() * 10e3) / 10e3,
|
||||||
xDivisible(xRange.getMax()*10e3)/10e3,
|
xDivisible(xRange.getMax() * 10e3) / 10e3,
|
||||||
xDivisible(yRange.getMin()*10e3)/10e3,
|
xDivisible(yRange.getMin() * 10e3) / 10e3,
|
||||||
xDivisible(yRange.getMax()*10e3)/10e3);
|
xDivisible(yRange.getMax() * 10e3) / 10e3
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** creates a small random rectangle by default to keep shape test performance at bay */
|
/** creates a small random rectangle by default to keep shape test performance at bay */
|
||||||
|
@ -292,7 +297,7 @@ public class RandomShapeGenerator extends RandomGeoGenerator {
|
||||||
|
|
||||||
private static Range xRandomRange(Random r, double near, Range bounds) {
|
private static Range xRandomRange(Random r, double near, Range bounds) {
|
||||||
double mid = near + r.nextGaussian() * bounds.getWidth() / 6;
|
double mid = near + r.nextGaussian() * bounds.getWidth() / 6;
|
||||||
double width = Math.abs(r.nextGaussian()) * bounds.getWidth() / 6;//1/3rd
|
double width = Math.abs(r.nextGaussian()) * bounds.getWidth() / 6;// 1/3rd
|
||||||
return new Range(mid - width / 2, mid + width / 2);
|
return new Range(mid - width / 2, mid + width / 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,25 +5,22 @@
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||||
* Side Public License, v 1.
|
* Side Public License, v 1.
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.test;
|
package org.elasticsearch.legacygeo.test;
|
||||||
|
|
||||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
|
|
||||||
import org.elasticsearch.index.mapper.Mapper;
|
import org.elasticsearch.index.mapper.Mapper;
|
||||||
|
import org.elasticsearch.legacygeo.LegacyGeoPlugin;
|
||||||
|
import org.elasticsearch.legacygeo.mapper.LegacyGeoShapeFieldMapper;
|
||||||
import org.elasticsearch.plugins.MapperPlugin;
|
import org.elasticsearch.plugins.MapperPlugin;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some tests depend on the {@link LegacyGeoShapeFieldMapper}.
|
* Test plugin to test functionality of this mapper.
|
||||||
* This mapper is registered in the spatial-extras module, but used in some integration
|
|
||||||
* tests in server code. The goal is to migrate all of the spatial/geo pieces to the spatial-extras
|
|
||||||
* module such that no tests in server depend on this test plugin
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class TestLegacyGeoShapeFieldMapperPlugin extends Plugin implements MapperPlugin {
|
public class TestLegacyGeoShapeFieldMapperPlugin extends LegacyGeoPlugin implements MapperPlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Mapper.TypeParser> getMappers() {
|
public Map<String, Mapper.TypeParser> getMappers() {
|
|
@ -84,7 +84,6 @@ dependencies {
|
||||||
api "org.apache.lucene:lucene-queries:${versions.lucene}"
|
api "org.apache.lucene:lucene-queries:${versions.lucene}"
|
||||||
api "org.apache.lucene:lucene-queryparser:${versions.lucene}"
|
api "org.apache.lucene:lucene-queryparser:${versions.lucene}"
|
||||||
api "org.apache.lucene:lucene-sandbox:${versions.lucene}"
|
api "org.apache.lucene:lucene-sandbox:${versions.lucene}"
|
||||||
api "org.apache.lucene:lucene-spatial-extras:${versions.lucene}"
|
|
||||||
api "org.apache.lucene:lucene-spatial3d:${versions.lucene}"
|
api "org.apache.lucene:lucene-spatial3d:${versions.lucene}"
|
||||||
api "org.apache.lucene:lucene-suggest:${versions.lucene}"
|
api "org.apache.lucene:lucene-suggest:${versions.lucene}"
|
||||||
|
|
||||||
|
@ -103,10 +102,6 @@ dependencies {
|
||||||
// precentil ranks aggregation
|
// precentil ranks aggregation
|
||||||
api 'org.hdrhistogram:HdrHistogram:2.1.9'
|
api 'org.hdrhistogram:HdrHistogram:2.1.9'
|
||||||
|
|
||||||
// lucene spatial
|
|
||||||
api "org.locationtech.spatial4j:spatial4j:${versions.spatial4j}", optional
|
|
||||||
api "org.locationtech.jts:jts-core:${versions.jts}", optional
|
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
api "org.apache.logging.log4j:log4j-api:${versions.log4j}"
|
api "org.apache.logging.log4j:log4j-api:${versions.log4j}"
|
||||||
api "org.apache.logging.log4j:log4j-core:${versions.log4j}", optional
|
api "org.apache.logging.log4j:log4j-core:${versions.log4j}", optional
|
||||||
|
@ -202,7 +197,6 @@ tasks.named("thirdPartyAudit").configure {
|
||||||
'com.fasterxml.jackson.dataformat.xml.JacksonXmlModule',
|
'com.fasterxml.jackson.dataformat.xml.JacksonXmlModule',
|
||||||
'com.fasterxml.jackson.dataformat.xml.XmlMapper',
|
'com.fasterxml.jackson.dataformat.xml.XmlMapper',
|
||||||
'com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter',
|
'com.fasterxml.jackson.dataformat.xml.util.DefaultXmlPrettyPrinter',
|
||||||
'com.fasterxml.jackson.databind.node.ObjectNode',
|
|
||||||
'org.fusesource.jansi.Ansi',
|
'org.fusesource.jansi.Ansi',
|
||||||
'org.fusesource.jansi.AnsiRenderer$Code',
|
'org.fusesource.jansi.AnsiRenderer$Code',
|
||||||
'com.lmax.disruptor.BlockingWaitStrategy',
|
'com.lmax.disruptor.BlockingWaitStrategy',
|
||||||
|
@ -270,20 +264,6 @@ tasks.named("thirdPartyAudit").configure {
|
||||||
'org.zeromq.ZMQ$Context',
|
'org.zeromq.ZMQ$Context',
|
||||||
'org.zeromq.ZMQ$Socket',
|
'org.zeromq.ZMQ$Socket',
|
||||||
'org.zeromq.ZMQ',
|
'org.zeromq.ZMQ',
|
||||||
|
|
||||||
// from org.locationtech.spatial4j.io.GeoJSONReader (spatial4j)
|
|
||||||
'org.noggit.JSONParser',
|
|
||||||
|
|
||||||
// from lucene-spatial
|
|
||||||
'com.fasterxml.jackson.databind.JsonSerializer',
|
|
||||||
'com.fasterxml.jackson.databind.JsonDeserializer',
|
|
||||||
'com.fasterxml.jackson.databind.node.ArrayNode',
|
|
||||||
'com.google.common.geometry.S2Cell',
|
|
||||||
'com.google.common.geometry.S2CellId',
|
|
||||||
'com.google.common.geometry.S2Projections',
|
|
||||||
'com.google.common.geometry.S2Point',
|
|
||||||
'com.google.common.geometry.S2$Metric',
|
|
||||||
'com.google.common.geometry.S2LatLng'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (BuildParams.runtimeJavaVersion > JavaVersion.VERSION_1_8) {
|
if (BuildParams.runtimeJavaVersion > JavaVersion.VERSION_1_8) {
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
package org.elasticsearch.common.geo;
|
package org.elasticsearch.common.geo;
|
||||||
|
|
||||||
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
|
|
||||||
import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
|
|
||||||
import org.apache.lucene.util.SloppyMath;
|
import org.apache.lucene.util.SloppyMath;
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.unit.DistanceUnit;
|
import org.elasticsearch.common.unit.DistanceUnit;
|
||||||
|
@ -66,6 +64,9 @@ public class GeoUtils {
|
||||||
/** rounding error for quantized latitude and longitude values */
|
/** rounding error for quantized latitude and longitude values */
|
||||||
public static final double TOLERANCE = 1E-6;
|
public static final double TOLERANCE = 1E-6;
|
||||||
|
|
||||||
|
private static final int QUAD_MAX_LEVELS_POSSIBLE = 50;
|
||||||
|
private static final int GEOHASH_MAX_LEVELS_POSSIBLE = 24;
|
||||||
|
|
||||||
/** Returns true if latitude is actually a valid latitude value.*/
|
/** Returns true if latitude is actually a valid latitude value.*/
|
||||||
public static boolean isValidLatitude(double latitude) {
|
public static boolean isValidLatitude(double latitude) {
|
||||||
if (Double.isNaN(latitude) || Double.isInfinite(latitude) || latitude < GeoUtils.MIN_LAT || latitude > GeoUtils.MAX_LAT) {
|
if (Double.isNaN(latitude) || Double.isInfinite(latitude) || latitude < GeoUtils.MIN_LAT || latitude > GeoUtils.MAX_LAT) {
|
||||||
|
@ -158,7 +159,7 @@ public class GeoUtils {
|
||||||
public static int quadTreeLevelsForPrecision(double meters) {
|
public static int quadTreeLevelsForPrecision(double meters) {
|
||||||
assert meters >= 0;
|
assert meters >= 0;
|
||||||
if(meters == 0) {
|
if(meters == 0) {
|
||||||
return QuadPrefixTree.MAX_LEVELS_POSSIBLE;
|
return QUAD_MAX_LEVELS_POSSIBLE;
|
||||||
} else {
|
} else {
|
||||||
final double ratio = 1+(EARTH_POLAR_DISTANCE / EARTH_EQUATOR); // cell ratio
|
final double ratio = 1+(EARTH_POLAR_DISTANCE / EARTH_EQUATOR); // cell ratio
|
||||||
final double width = Math.sqrt((meters*meters)/(ratio*ratio)); // convert to cell width
|
final double width = Math.sqrt((meters*meters)/(ratio*ratio)); // convert to cell width
|
||||||
|
@ -188,7 +189,7 @@ public class GeoUtils {
|
||||||
assert meters >= 0;
|
assert meters >= 0;
|
||||||
|
|
||||||
if(meters == 0) {
|
if(meters == 0) {
|
||||||
return GeohashPrefixTree.getMaxLevelsPossible();
|
return GEOHASH_MAX_LEVELS_POSSIBLE;
|
||||||
} else {
|
} else {
|
||||||
final double ratio = 1+(EARTH_POLAR_DISTANCE / EARTH_EQUATOR); // cell ratio
|
final double ratio = 1+(EARTH_POLAR_DISTANCE / EARTH_EQUATOR); // cell ratio
|
||||||
final double width = Math.sqrt((meters*meters)/(ratio*ratio)); // convert to cell width
|
final double width = Math.sqrt((meters*meters)/(ratio*ratio)); // convert to cell width
|
||||||
|
|
|
@ -16,7 +16,7 @@ import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for {@link GeoShapeFieldMapper} and {@link LegacyGeoShapeFieldMapper}
|
* Base class for {@link GeoShapeFieldMapper}
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractShapeGeometryFieldMapper<T> extends AbstractGeometryFieldMapper<T> {
|
public abstract class AbstractShapeGeometryFieldMapper<T> extends AbstractGeometryFieldMapper<T> {
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,10 @@ import org.elasticsearch.index.query.SearchExecutionContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,6 +56,10 @@ public class GeoShapeFieldMapper extends AbstractShapeGeometryFieldMapper<Geomet
|
||||||
|
|
||||||
private static final DeprecationLogger DEPRECATION_LOGGER = DeprecationLogger.getLogger(GeoShapeFieldMapper.class);
|
private static final DeprecationLogger DEPRECATION_LOGGER = DeprecationLogger.getLogger(GeoShapeFieldMapper.class);
|
||||||
|
|
||||||
|
public static final Set<String> DEPRECATED_PARAMETERS = new HashSet<>(
|
||||||
|
Arrays.asList("strategy", "tree", "tree_levels", "precision", "distance_error_pct", "points_only")
|
||||||
|
);
|
||||||
|
|
||||||
public static final String CONTENT_TYPE = "geo_shape";
|
public static final String CONTENT_TYPE = "geo_shape";
|
||||||
|
|
||||||
private static Builder builder(FieldMapper in) {
|
private static Builder builder(FieldMapper in) {
|
||||||
|
|
|
@ -12,7 +12,6 @@ import org.apache.lucene.search.join.ScoreMode;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.geo.GeoPoint;
|
import org.elasticsearch.common.geo.GeoPoint;
|
||||||
import org.elasticsearch.common.geo.ShapeRelation;
|
import org.elasticsearch.common.geo.ShapeRelation;
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.elasticsearch.geometry.Geometry;
|
import org.elasticsearch.geometry.Geometry;
|
||||||
import org.elasticsearch.index.query.DistanceFeatureQueryBuilder.Origin;
|
import org.elasticsearch.index.query.DistanceFeatureQueryBuilder.Origin;
|
||||||
import org.elasticsearch.index.query.MoreLikeThisQueryBuilder.Item;
|
import org.elasticsearch.index.query.MoreLikeThisQueryBuilder.Item;
|
||||||
|
@ -676,14 +675,6 @@ public final class QueryBuilders {
|
||||||
return new GeoShapeQueryBuilder(name, shape);
|
return new GeoShapeQueryBuilder(name, shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link #geoShapeQuery(String, Geometry)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static GeoShapeQueryBuilder geoShapeQuery(String name, ShapeBuilder<?, ?, ?> shape) throws IOException {
|
|
||||||
return new GeoShapeQueryBuilder(name, shape.buildGeometry());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GeoShapeQueryBuilder geoShapeQuery(String name, String indexedShapeId) {
|
public static GeoShapeQueryBuilder geoShapeQuery(String name, String indexedShapeId) {
|
||||||
return new GeoShapeQueryBuilder(name, indexedShapeId);
|
return new GeoShapeQueryBuilder(name, indexedShapeId);
|
||||||
}
|
}
|
||||||
|
@ -708,16 +699,6 @@ public final class QueryBuilders {
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link #geoIntersectionQuery(String, Geometry)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static GeoShapeQueryBuilder geoIntersectionQuery(String name, ShapeBuilder<?, ?, ?> shape) throws IOException {
|
|
||||||
GeoShapeQueryBuilder builder = geoShapeQuery(name, shape);
|
|
||||||
builder.relation(ShapeRelation.INTERSECTS);
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GeoShapeQueryBuilder geoIntersectionQuery(String name, String indexedShapeId) {
|
public static GeoShapeQueryBuilder geoIntersectionQuery(String name, String indexedShapeId) {
|
||||||
GeoShapeQueryBuilder builder = geoShapeQuery(name, indexedShapeId);
|
GeoShapeQueryBuilder builder = geoShapeQuery(name, indexedShapeId);
|
||||||
builder.relation(ShapeRelation.INTERSECTS);
|
builder.relation(ShapeRelation.INTERSECTS);
|
||||||
|
@ -746,16 +727,6 @@ public final class QueryBuilders {
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link #geoWithinQuery(String, Geometry)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static GeoShapeQueryBuilder geoWithinQuery(String name, ShapeBuilder<?, ?, ?> shape) throws IOException {
|
|
||||||
GeoShapeQueryBuilder builder = geoShapeQuery(name, shape);
|
|
||||||
builder.relation(ShapeRelation.WITHIN);
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GeoShapeQueryBuilder geoWithinQuery(String name, String indexedShapeId) {
|
public static GeoShapeQueryBuilder geoWithinQuery(String name, String indexedShapeId) {
|
||||||
GeoShapeQueryBuilder builder = geoShapeQuery(name, indexedShapeId);
|
GeoShapeQueryBuilder builder = geoShapeQuery(name, indexedShapeId);
|
||||||
builder.relation(ShapeRelation.WITHIN);
|
builder.relation(ShapeRelation.WITHIN);
|
||||||
|
@ -784,16 +755,6 @@ public final class QueryBuilders {
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link #geoDisjointQuery(String, Geometry)} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static GeoShapeQueryBuilder geoDisjointQuery(String name, ShapeBuilder<?, ?, ?> shape) throws IOException {
|
|
||||||
GeoShapeQueryBuilder builder = geoShapeQuery(name, shape);
|
|
||||||
builder.relation(ShapeRelation.DISJOINT);
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GeoShapeQueryBuilder geoDisjointQuery(String name, String indexedShapeId) {
|
public static GeoShapeQueryBuilder geoDisjointQuery(String name, String indexedShapeId) {
|
||||||
GeoShapeQueryBuilder builder = geoShapeQuery(name, indexedShapeId);
|
GeoShapeQueryBuilder builder = geoShapeQuery(name, indexedShapeId);
|
||||||
builder.relation(ShapeRelation.DISJOINT);
|
builder.relation(ShapeRelation.DISJOINT);
|
||||||
|
|
|
@ -12,8 +12,6 @@ import org.apache.lucene.search.BooleanQuery;
|
||||||
import org.elasticsearch.common.CheckedBiConsumer;
|
import org.elasticsearch.common.CheckedBiConsumer;
|
||||||
import org.elasticsearch.common.NamedRegistry;
|
import org.elasticsearch.common.NamedRegistry;
|
||||||
import org.elasticsearch.common.xcontent.ParseField;
|
import org.elasticsearch.common.xcontent.ParseField;
|
||||||
import org.elasticsearch.common.geo.GeoShapeType;
|
|
||||||
import org.elasticsearch.common.geo.ShapesAvailability;
|
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry;
|
import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
@ -293,7 +291,7 @@ import static org.elasticsearch.index.query.CommonTermsQueryBuilder.COMMON_TERMS
|
||||||
*/
|
*/
|
||||||
public class SearchModule {
|
public class SearchModule {
|
||||||
public static final Setting<Integer> INDICES_MAX_CLAUSE_COUNT_SETTING = Setting.intSetting("indices.query.bool.max_clause_count",
|
public static final Setting<Integer> INDICES_MAX_CLAUSE_COUNT_SETTING = Setting.intSetting("indices.query.bool.max_clause_count",
|
||||||
1024, 1, Integer.MAX_VALUE, Setting.Property.NodeScope);
|
1024, 1, Integer.MAX_VALUE, Setting.Property.NodeScope);
|
||||||
|
|
||||||
public static final Setting<Integer> INDICES_MAX_NESTED_DEPTH_SETTING = Setting.intSetting("indices.query.bool.max_nested_depth",
|
public static final Setting<Integer> INDICES_MAX_NESTED_DEPTH_SETTING = Setting.intSetting("indices.query.bool.max_nested_depth",
|
||||||
20, 1, Integer.MAX_VALUE, Setting.Property.NodeScope);
|
20, 1, Integer.MAX_VALUE, Setting.Property.NodeScope);
|
||||||
|
@ -301,7 +299,7 @@ public class SearchModule {
|
||||||
private final boolean transportClient;
|
private final boolean transportClient;
|
||||||
private final Map<String, Highlighter> highlighters;
|
private final Map<String, Highlighter> highlighters;
|
||||||
private final ParseFieldRegistry<MovAvgModel.AbstractModelParser> movingAverageModelParserRegistry = new ParseFieldRegistry<>(
|
private final ParseFieldRegistry<MovAvgModel.AbstractModelParser> movingAverageModelParserRegistry = new ParseFieldRegistry<>(
|
||||||
"moving_avg_model");
|
"moving_avg_model");
|
||||||
|
|
||||||
private final List<FetchSubPhase> fetchSubPhases = new ArrayList<>();
|
private final List<FetchSubPhase> fetchSubPhases = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -336,7 +334,6 @@ public class SearchModule {
|
||||||
registerPipelineAggregations(plugins);
|
registerPipelineAggregations(plugins);
|
||||||
registerFetchSubPhases(plugins);
|
registerFetchSubPhases(plugins);
|
||||||
registerSearchExts(plugins);
|
registerSearchExts(plugins);
|
||||||
registerShapes();
|
|
||||||
registerIntervalsSourceProviders();
|
registerIntervalsSourceProviders();
|
||||||
requestCacheKeyDifferentiator = registerRequestCacheKeyDifferentiator(plugins);
|
requestCacheKeyDifferentiator = registerRequestCacheKeyDifferentiator(plugins);
|
||||||
namedWriteables.addAll(SortValue.namedWriteables());
|
namedWriteables.addAll(SortValue.namedWriteables());
|
||||||
|
@ -385,137 +382,137 @@ public class SearchModule {
|
||||||
.addResultReader(InternalSum::new)
|
.addResultReader(InternalSum::new)
|
||||||
.setAggregatorRegistrar(SumAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(SumAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(MinAggregationBuilder.NAME, MinAggregationBuilder::new, MinAggregationBuilder.PARSER)
|
registerAggregation(new AggregationSpec(MinAggregationBuilder.NAME, MinAggregationBuilder::new, MinAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalMin::new)
|
.addResultReader(InternalMin::new)
|
||||||
.setAggregatorRegistrar(MinAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(MinAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(MaxAggregationBuilder.NAME, MaxAggregationBuilder::new, MaxAggregationBuilder.PARSER)
|
registerAggregation(new AggregationSpec(MaxAggregationBuilder.NAME, MaxAggregationBuilder::new, MaxAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalMax::new)
|
.addResultReader(InternalMax::new)
|
||||||
.setAggregatorRegistrar(MaxAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(MaxAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(StatsAggregationBuilder.NAME, StatsAggregationBuilder::new, StatsAggregationBuilder.PARSER)
|
registerAggregation(new AggregationSpec(StatsAggregationBuilder.NAME, StatsAggregationBuilder::new, StatsAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalStats::new)
|
.addResultReader(InternalStats::new)
|
||||||
.setAggregatorRegistrar(StatsAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(StatsAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(ExtendedStatsAggregationBuilder.NAME, ExtendedStatsAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(ExtendedStatsAggregationBuilder.NAME, ExtendedStatsAggregationBuilder::new,
|
||||||
ExtendedStatsAggregationBuilder.PARSER)
|
ExtendedStatsAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalExtendedStats::new)
|
.addResultReader(InternalExtendedStats::new)
|
||||||
.setAggregatorRegistrar(ExtendedStatsAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(ExtendedStatsAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(ValueCountAggregationBuilder.NAME, ValueCountAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(ValueCountAggregationBuilder.NAME, ValueCountAggregationBuilder::new,
|
||||||
ValueCountAggregationBuilder.PARSER)
|
ValueCountAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalValueCount::new)
|
.addResultReader(InternalValueCount::new)
|
||||||
.setAggregatorRegistrar(ValueCountAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(ValueCountAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(PercentilesAggregationBuilder.NAME, PercentilesAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(PercentilesAggregationBuilder.NAME, PercentilesAggregationBuilder::new,
|
||||||
PercentilesAggregationBuilder::parse)
|
PercentilesAggregationBuilder::parse)
|
||||||
.addResultReader(InternalTDigestPercentiles.NAME, InternalTDigestPercentiles::new)
|
.addResultReader(InternalTDigestPercentiles.NAME, InternalTDigestPercentiles::new)
|
||||||
.addResultReader(InternalHDRPercentiles.NAME, InternalHDRPercentiles::new)
|
.addResultReader(InternalHDRPercentiles.NAME, InternalHDRPercentiles::new)
|
||||||
.setAggregatorRegistrar(PercentilesAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(PercentilesAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(PercentileRanksAggregationBuilder.NAME, PercentileRanksAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(PercentileRanksAggregationBuilder.NAME, PercentileRanksAggregationBuilder::new,
|
||||||
PercentileRanksAggregationBuilder::parse)
|
PercentileRanksAggregationBuilder::parse)
|
||||||
.addResultReader(InternalTDigestPercentileRanks.NAME, InternalTDigestPercentileRanks::new)
|
.addResultReader(InternalTDigestPercentileRanks.NAME, InternalTDigestPercentileRanks::new)
|
||||||
.addResultReader(InternalHDRPercentileRanks.NAME, InternalHDRPercentileRanks::new)
|
.addResultReader(InternalHDRPercentileRanks.NAME, InternalHDRPercentileRanks::new)
|
||||||
.setAggregatorRegistrar(PercentileRanksAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(PercentileRanksAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(MedianAbsoluteDeviationAggregationBuilder.NAME,
|
registerAggregation(new AggregationSpec(MedianAbsoluteDeviationAggregationBuilder.NAME,
|
||||||
MedianAbsoluteDeviationAggregationBuilder::new, MedianAbsoluteDeviationAggregationBuilder.PARSER)
|
MedianAbsoluteDeviationAggregationBuilder::new, MedianAbsoluteDeviationAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalMedianAbsoluteDeviation::new)
|
.addResultReader(InternalMedianAbsoluteDeviation::new)
|
||||||
.setAggregatorRegistrar(MedianAbsoluteDeviationAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(MedianAbsoluteDeviationAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(CardinalityAggregationBuilder.NAME, CardinalityAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(CardinalityAggregationBuilder.NAME, CardinalityAggregationBuilder::new,
|
||||||
CardinalityAggregationBuilder.PARSER).addResultReader(InternalCardinality::new)
|
CardinalityAggregationBuilder.PARSER).addResultReader(InternalCardinality::new)
|
||||||
.setAggregatorRegistrar(CardinalityAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(CardinalityAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(GlobalAggregationBuilder.NAME, GlobalAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(GlobalAggregationBuilder.NAME, GlobalAggregationBuilder::new,
|
||||||
GlobalAggregationBuilder::parse).addResultReader(InternalGlobal::new), builder);
|
GlobalAggregationBuilder::parse).addResultReader(InternalGlobal::new), builder);
|
||||||
registerAggregation(new AggregationSpec(MissingAggregationBuilder.NAME, MissingAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(MissingAggregationBuilder.NAME, MissingAggregationBuilder::new,
|
||||||
MissingAggregationBuilder.PARSER)
|
MissingAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalMissing::new)
|
.addResultReader(InternalMissing::new)
|
||||||
.setAggregatorRegistrar(MissingAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(MissingAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(FilterAggregationBuilder.NAME, FilterAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(FilterAggregationBuilder.NAME, FilterAggregationBuilder::new,
|
||||||
FilterAggregationBuilder::parse).addResultReader(InternalFilter::new), builder);
|
FilterAggregationBuilder::parse).addResultReader(InternalFilter::new), builder);
|
||||||
registerAggregation(new AggregationSpec(FiltersAggregationBuilder.NAME, FiltersAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(FiltersAggregationBuilder.NAME, FiltersAggregationBuilder::new,
|
||||||
FiltersAggregationBuilder::parse).addResultReader(InternalFilters::new), builder);
|
FiltersAggregationBuilder::parse).addResultReader(InternalFilters::new), builder);
|
||||||
registerAggregation(new AggregationSpec(AdjacencyMatrixAggregationBuilder.NAME, AdjacencyMatrixAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(AdjacencyMatrixAggregationBuilder.NAME, AdjacencyMatrixAggregationBuilder::new,
|
||||||
AdjacencyMatrixAggregationBuilder::parse).addResultReader(InternalAdjacencyMatrix::new), builder);
|
AdjacencyMatrixAggregationBuilder::parse).addResultReader(InternalAdjacencyMatrix::new), builder);
|
||||||
registerAggregation(new AggregationSpec(SamplerAggregationBuilder.NAME, SamplerAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(SamplerAggregationBuilder.NAME, SamplerAggregationBuilder::new,
|
||||||
SamplerAggregationBuilder::parse)
|
SamplerAggregationBuilder::parse)
|
||||||
.addResultReader(InternalSampler.NAME, InternalSampler::new)
|
.addResultReader(InternalSampler.NAME, InternalSampler::new)
|
||||||
.addResultReader(UnmappedSampler.NAME, UnmappedSampler::new),
|
.addResultReader(UnmappedSampler.NAME, UnmappedSampler::new),
|
||||||
builder);
|
builder);
|
||||||
registerAggregation(new AggregationSpec(DiversifiedAggregationBuilder.NAME, DiversifiedAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(DiversifiedAggregationBuilder.NAME, DiversifiedAggregationBuilder::new,
|
||||||
DiversifiedAggregationBuilder.PARSER).setAggregatorRegistrar(DiversifiedAggregationBuilder::registerAggregators)
|
DiversifiedAggregationBuilder.PARSER).setAggregatorRegistrar(DiversifiedAggregationBuilder::registerAggregators)
|
||||||
/* Reuses result readers from SamplerAggregator*/, builder);
|
/* Reuses result readers from SamplerAggregator*/, builder);
|
||||||
registerAggregation(new AggregationSpec(TermsAggregationBuilder.NAME, TermsAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(TermsAggregationBuilder.NAME, TermsAggregationBuilder::new,
|
||||||
TermsAggregationBuilder.PARSER)
|
TermsAggregationBuilder.PARSER)
|
||||||
.addResultReader(StringTerms.NAME, StringTerms::new)
|
.addResultReader(StringTerms.NAME, StringTerms::new)
|
||||||
.addResultReader(UnmappedTerms.NAME, UnmappedTerms::new)
|
.addResultReader(UnmappedTerms.NAME, UnmappedTerms::new)
|
||||||
.addResultReader(LongTerms.NAME, LongTerms::new)
|
.addResultReader(LongTerms.NAME, LongTerms::new)
|
||||||
.addResultReader(DoubleTerms.NAME, DoubleTerms::new)
|
.addResultReader(DoubleTerms.NAME, DoubleTerms::new)
|
||||||
.setAggregatorRegistrar(TermsAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(TermsAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(RareTermsAggregationBuilder.NAME, RareTermsAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(RareTermsAggregationBuilder.NAME, RareTermsAggregationBuilder::new,
|
||||||
RareTermsAggregationBuilder.PARSER)
|
RareTermsAggregationBuilder.PARSER)
|
||||||
.addResultReader(StringRareTerms.NAME, StringRareTerms::new)
|
.addResultReader(StringRareTerms.NAME, StringRareTerms::new)
|
||||||
.addResultReader(UnmappedRareTerms.NAME, UnmappedRareTerms::new)
|
.addResultReader(UnmappedRareTerms.NAME, UnmappedRareTerms::new)
|
||||||
.addResultReader(LongRareTerms.NAME, LongRareTerms::new)
|
.addResultReader(LongRareTerms.NAME, LongRareTerms::new)
|
||||||
.setAggregatorRegistrar(RareTermsAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(RareTermsAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(SignificantTermsAggregationBuilder.NAME, SignificantTermsAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(SignificantTermsAggregationBuilder.NAME, SignificantTermsAggregationBuilder::new,
|
||||||
SignificantTermsAggregationBuilder::parse)
|
SignificantTermsAggregationBuilder::parse)
|
||||||
.addResultReader(SignificantStringTerms.NAME, SignificantStringTerms::new)
|
.addResultReader(SignificantStringTerms.NAME, SignificantStringTerms::new)
|
||||||
.addResultReader(SignificantLongTerms.NAME, SignificantLongTerms::new)
|
.addResultReader(SignificantLongTerms.NAME, SignificantLongTerms::new)
|
||||||
.addResultReader(UnmappedSignificantTerms.NAME, UnmappedSignificantTerms::new)
|
.addResultReader(UnmappedSignificantTerms.NAME, UnmappedSignificantTerms::new)
|
||||||
.setAggregatorRegistrar(SignificantTermsAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(SignificantTermsAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(SignificantTextAggregationBuilder.NAME, SignificantTextAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(SignificantTextAggregationBuilder.NAME, SignificantTextAggregationBuilder::new,
|
||||||
SignificantTextAggregationBuilder::parse), builder);
|
SignificantTextAggregationBuilder::parse), builder);
|
||||||
registerAggregation(new AggregationSpec(RangeAggregationBuilder.NAME, RangeAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(RangeAggregationBuilder.NAME, RangeAggregationBuilder::new,
|
||||||
RangeAggregationBuilder.PARSER)
|
RangeAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalRange::new)
|
.addResultReader(InternalRange::new)
|
||||||
.setAggregatorRegistrar(RangeAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(RangeAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(DateRangeAggregationBuilder.NAME, DateRangeAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(DateRangeAggregationBuilder.NAME, DateRangeAggregationBuilder::new,
|
||||||
DateRangeAggregationBuilder.PARSER)
|
DateRangeAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalDateRange::new)
|
.addResultReader(InternalDateRange::new)
|
||||||
.setAggregatorRegistrar(DateRangeAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(DateRangeAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(IpRangeAggregationBuilder.NAME, IpRangeAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(IpRangeAggregationBuilder.NAME, IpRangeAggregationBuilder::new,
|
||||||
IpRangeAggregationBuilder.PARSER)
|
IpRangeAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalBinaryRange::new)
|
.addResultReader(InternalBinaryRange::new)
|
||||||
.setAggregatorRegistrar(IpRangeAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(IpRangeAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(HistogramAggregationBuilder.NAME, HistogramAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(HistogramAggregationBuilder.NAME, HistogramAggregationBuilder::new,
|
||||||
HistogramAggregationBuilder.PARSER)
|
HistogramAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalHistogram::new)
|
.addResultReader(InternalHistogram::new)
|
||||||
.setAggregatorRegistrar(HistogramAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(HistogramAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(DateHistogramAggregationBuilder.NAME, DateHistogramAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(DateHistogramAggregationBuilder.NAME, DateHistogramAggregationBuilder::new,
|
||||||
DateHistogramAggregationBuilder.PARSER)
|
DateHistogramAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalDateHistogram::new)
|
.addResultReader(InternalDateHistogram::new)
|
||||||
.setAggregatorRegistrar(DateHistogramAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(DateHistogramAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(AutoDateHistogramAggregationBuilder.NAME, AutoDateHistogramAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(AutoDateHistogramAggregationBuilder.NAME, AutoDateHistogramAggregationBuilder::new,
|
||||||
AutoDateHistogramAggregationBuilder.PARSER)
|
AutoDateHistogramAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalAutoDateHistogram::new)
|
.addResultReader(InternalAutoDateHistogram::new)
|
||||||
.setAggregatorRegistrar(AutoDateHistogramAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(AutoDateHistogramAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(VariableWidthHistogramAggregationBuilder.NAME,
|
registerAggregation(new AggregationSpec(VariableWidthHistogramAggregationBuilder.NAME,
|
||||||
VariableWidthHistogramAggregationBuilder::new,
|
VariableWidthHistogramAggregationBuilder::new,
|
||||||
VariableWidthHistogramAggregationBuilder.PARSER)
|
VariableWidthHistogramAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalVariableWidthHistogram::new)
|
.addResultReader(InternalVariableWidthHistogram::new)
|
||||||
.setAggregatorRegistrar(VariableWidthHistogramAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(VariableWidthHistogramAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(GeoDistanceAggregationBuilder.NAME, GeoDistanceAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(GeoDistanceAggregationBuilder.NAME, GeoDistanceAggregationBuilder::new,
|
||||||
GeoDistanceAggregationBuilder::parse)
|
GeoDistanceAggregationBuilder::parse)
|
||||||
.addResultReader(InternalGeoDistance::new)
|
.addResultReader(InternalGeoDistance::new)
|
||||||
.setAggregatorRegistrar(GeoDistanceAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(GeoDistanceAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(GeoHashGridAggregationBuilder.NAME, GeoHashGridAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(GeoHashGridAggregationBuilder.NAME, GeoHashGridAggregationBuilder::new,
|
||||||
GeoHashGridAggregationBuilder.PARSER)
|
GeoHashGridAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalGeoHashGrid::new)
|
.addResultReader(InternalGeoHashGrid::new)
|
||||||
.setAggregatorRegistrar(GeoHashGridAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(GeoHashGridAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(GeoTileGridAggregationBuilder.NAME, GeoTileGridAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(GeoTileGridAggregationBuilder.NAME, GeoTileGridAggregationBuilder::new,
|
||||||
GeoTileGridAggregationBuilder.PARSER)
|
GeoTileGridAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalGeoTileGrid::new)
|
.addResultReader(InternalGeoTileGrid::new)
|
||||||
.setAggregatorRegistrar(GeoTileGridAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(GeoTileGridAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(NestedAggregationBuilder.NAME, NestedAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(NestedAggregationBuilder.NAME, NestedAggregationBuilder::new,
|
||||||
NestedAggregationBuilder::parse).addResultReader(InternalNested::new), builder);
|
NestedAggregationBuilder::parse).addResultReader(InternalNested::new), builder);
|
||||||
registerAggregation(new AggregationSpec(ReverseNestedAggregationBuilder.NAME, ReverseNestedAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(ReverseNestedAggregationBuilder.NAME, ReverseNestedAggregationBuilder::new,
|
||||||
ReverseNestedAggregationBuilder::parse).addResultReader(InternalReverseNested::new), builder);
|
ReverseNestedAggregationBuilder::parse).addResultReader(InternalReverseNested::new), builder);
|
||||||
registerAggregation(new AggregationSpec(TopHitsAggregationBuilder.NAME, TopHitsAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(TopHitsAggregationBuilder.NAME, TopHitsAggregationBuilder::new,
|
||||||
TopHitsAggregationBuilder::parse).addResultReader(InternalTopHits::new), builder);
|
TopHitsAggregationBuilder::parse).addResultReader(InternalTopHits::new), builder);
|
||||||
registerAggregation(new AggregationSpec(GeoBoundsAggregationBuilder.NAME, GeoBoundsAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(GeoBoundsAggregationBuilder.NAME, GeoBoundsAggregationBuilder::new,
|
||||||
GeoBoundsAggregationBuilder.PARSER)
|
GeoBoundsAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalGeoBounds::new)
|
.addResultReader(InternalGeoBounds::new)
|
||||||
.setAggregatorRegistrar(GeoBoundsAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(GeoBoundsAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(GeoCentroidAggregationBuilder.NAME, GeoCentroidAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(GeoCentroidAggregationBuilder.NAME, GeoCentroidAggregationBuilder::new,
|
||||||
GeoCentroidAggregationBuilder.PARSER)
|
GeoCentroidAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalGeoCentroid::new)
|
.addResultReader(InternalGeoCentroid::new)
|
||||||
.setAggregatorRegistrar(GeoCentroidAggregationBuilder::registerAggregators), builder);
|
.setAggregatorRegistrar(GeoCentroidAggregationBuilder::registerAggregators), builder);
|
||||||
registerAggregation(new AggregationSpec(ScriptedMetricAggregationBuilder.NAME, ScriptedMetricAggregationBuilder::new,
|
registerAggregation(new AggregationSpec(ScriptedMetricAggregationBuilder.NAME, ScriptedMetricAggregationBuilder::new,
|
||||||
ScriptedMetricAggregationBuilder.PARSER).addResultReader(InternalScriptedMetric::new), builder);
|
ScriptedMetricAggregationBuilder.PARSER).addResultReader(InternalScriptedMetric::new), builder);
|
||||||
registerAggregation(
|
registerAggregation(
|
||||||
new AggregationSpec(CompositeAggregationBuilder.NAME, CompositeAggregationBuilder::new, CompositeAggregationBuilder.PARSER)
|
new AggregationSpec(CompositeAggregationBuilder.NAME, CompositeAggregationBuilder::new, CompositeAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalComposite::new)
|
.addResultReader(InternalComposite::new)
|
||||||
|
@ -539,7 +536,7 @@ public class SearchModule {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
namedWriteables.add(
|
namedWriteables.add(
|
||||||
new NamedWriteableRegistry.Entry(AggregationBuilder.class, spec.getName().getPreferredName(), spec.getReader()));
|
new NamedWriteableRegistry.Entry(AggregationBuilder.class, spec.getName().getPreferredName(), spec.getReader()));
|
||||||
for (Map.Entry<String, Writeable.Reader<? extends InternalAggregation>> t : spec.getResultReaders().entrySet()) {
|
for (Map.Entry<String, Writeable.Reader<? extends InternalAggregation>> t : spec.getResultReaders().entrySet()) {
|
||||||
String writeableName = t.getKey();
|
String writeableName = t.getKey();
|
||||||
Writeable.Reader<? extends InternalAggregation> internalReader = t.getValue();
|
Writeable.Reader<? extends InternalAggregation> internalReader = t.getValue();
|
||||||
|
@ -557,92 +554,92 @@ public class SearchModule {
|
||||||
|
|
||||||
private void registerPipelineAggregations(List<SearchPlugin> plugins) {
|
private void registerPipelineAggregations(List<SearchPlugin> plugins) {
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
DerivativePipelineAggregationBuilder.NAME,
|
DerivativePipelineAggregationBuilder.NAME,
|
||||||
DerivativePipelineAggregationBuilder::new,
|
DerivativePipelineAggregationBuilder::new,
|
||||||
DerivativePipelineAggregator::new,
|
DerivativePipelineAggregator::new,
|
||||||
DerivativePipelineAggregationBuilder::parse)
|
DerivativePipelineAggregationBuilder::parse)
|
||||||
.addResultReader(InternalDerivative::new));
|
.addResultReader(InternalDerivative::new));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
MaxBucketPipelineAggregationBuilder.NAME,
|
MaxBucketPipelineAggregationBuilder.NAME,
|
||||||
MaxBucketPipelineAggregationBuilder::new,
|
MaxBucketPipelineAggregationBuilder::new,
|
||||||
MaxBucketPipelineAggregator::new,
|
MaxBucketPipelineAggregator::new,
|
||||||
MaxBucketPipelineAggregationBuilder.PARSER)
|
MaxBucketPipelineAggregationBuilder.PARSER)
|
||||||
// This bucket is used by many pipeline aggreations.
|
// This bucket is used by many pipeline aggreations.
|
||||||
.addResultReader(InternalBucketMetricValue.NAME, InternalBucketMetricValue::new));
|
.addResultReader(InternalBucketMetricValue.NAME, InternalBucketMetricValue::new));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
MinBucketPipelineAggregationBuilder.NAME,
|
MinBucketPipelineAggregationBuilder.NAME,
|
||||||
MinBucketPipelineAggregationBuilder::new,
|
MinBucketPipelineAggregationBuilder::new,
|
||||||
MinBucketPipelineAggregator::new,
|
MinBucketPipelineAggregator::new,
|
||||||
MinBucketPipelineAggregationBuilder.PARSER)
|
MinBucketPipelineAggregationBuilder.PARSER)
|
||||||
/* Uses InternalBucketMetricValue */);
|
/* Uses InternalBucketMetricValue */);
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
AvgBucketPipelineAggregationBuilder.NAME,
|
AvgBucketPipelineAggregationBuilder.NAME,
|
||||||
AvgBucketPipelineAggregationBuilder::new,
|
AvgBucketPipelineAggregationBuilder::new,
|
||||||
AvgBucketPipelineAggregator::new,
|
AvgBucketPipelineAggregator::new,
|
||||||
AvgBucketPipelineAggregationBuilder.PARSER)
|
AvgBucketPipelineAggregationBuilder.PARSER)
|
||||||
// This bucket is used by many pipeline aggreations.
|
// This bucket is used by many pipeline aggreations.
|
||||||
.addResultReader(InternalSimpleValue.NAME, InternalSimpleValue::new));
|
.addResultReader(InternalSimpleValue.NAME, InternalSimpleValue::new));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
SumBucketPipelineAggregationBuilder.NAME,
|
SumBucketPipelineAggregationBuilder.NAME,
|
||||||
SumBucketPipelineAggregationBuilder::new,
|
SumBucketPipelineAggregationBuilder::new,
|
||||||
SumBucketPipelineAggregator::new,
|
SumBucketPipelineAggregator::new,
|
||||||
SumBucketPipelineAggregationBuilder.PARSER)
|
SumBucketPipelineAggregationBuilder.PARSER)
|
||||||
/* Uses InternalSimpleValue */);
|
/* Uses InternalSimpleValue */);
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
StatsBucketPipelineAggregationBuilder.NAME,
|
StatsBucketPipelineAggregationBuilder.NAME,
|
||||||
StatsBucketPipelineAggregationBuilder::new,
|
StatsBucketPipelineAggregationBuilder::new,
|
||||||
StatsBucketPipelineAggregator::new,
|
StatsBucketPipelineAggregator::new,
|
||||||
StatsBucketPipelineAggregationBuilder.PARSER)
|
StatsBucketPipelineAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalStatsBucket::new));
|
.addResultReader(InternalStatsBucket::new));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
ExtendedStatsBucketPipelineAggregationBuilder.NAME,
|
ExtendedStatsBucketPipelineAggregationBuilder.NAME,
|
||||||
ExtendedStatsBucketPipelineAggregationBuilder::new,
|
ExtendedStatsBucketPipelineAggregationBuilder::new,
|
||||||
ExtendedStatsBucketPipelineAggregator::new,
|
ExtendedStatsBucketPipelineAggregator::new,
|
||||||
new ExtendedStatsBucketParser())
|
new ExtendedStatsBucketParser())
|
||||||
.addResultReader(InternalExtendedStatsBucket::new));
|
.addResultReader(InternalExtendedStatsBucket::new));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
PercentilesBucketPipelineAggregationBuilder.NAME,
|
PercentilesBucketPipelineAggregationBuilder.NAME,
|
||||||
PercentilesBucketPipelineAggregationBuilder::new,
|
PercentilesBucketPipelineAggregationBuilder::new,
|
||||||
PercentilesBucketPipelineAggregator::new,
|
PercentilesBucketPipelineAggregator::new,
|
||||||
PercentilesBucketPipelineAggregationBuilder.PARSER)
|
PercentilesBucketPipelineAggregationBuilder.PARSER)
|
||||||
.addResultReader(InternalPercentilesBucket::new));
|
.addResultReader(InternalPercentilesBucket::new));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
MovAvgPipelineAggregationBuilder.NAME,
|
MovAvgPipelineAggregationBuilder.NAME,
|
||||||
MovAvgPipelineAggregationBuilder::new,
|
MovAvgPipelineAggregationBuilder::new,
|
||||||
MovAvgPipelineAggregator::new,
|
MovAvgPipelineAggregator::new,
|
||||||
(XContentParser parser, String name) ->
|
(XContentParser parser, String name) ->
|
||||||
MovAvgPipelineAggregationBuilder.parse(movingAverageModelParserRegistry, name, parser)
|
MovAvgPipelineAggregationBuilder.parse(movingAverageModelParserRegistry, name, parser)
|
||||||
)/* Uses InternalHistogram for buckets */);
|
)/* Uses InternalHistogram for buckets */);
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
CumulativeSumPipelineAggregationBuilder.NAME,
|
CumulativeSumPipelineAggregationBuilder.NAME,
|
||||||
CumulativeSumPipelineAggregationBuilder::new,
|
CumulativeSumPipelineAggregationBuilder::new,
|
||||||
CumulativeSumPipelineAggregator::new,
|
CumulativeSumPipelineAggregator::new,
|
||||||
CumulativeSumPipelineAggregationBuilder.PARSER));
|
CumulativeSumPipelineAggregationBuilder.PARSER));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
BucketScriptPipelineAggregationBuilder.NAME,
|
BucketScriptPipelineAggregationBuilder.NAME,
|
||||||
BucketScriptPipelineAggregationBuilder::new,
|
BucketScriptPipelineAggregationBuilder::new,
|
||||||
BucketScriptPipelineAggregator::new,
|
BucketScriptPipelineAggregator::new,
|
||||||
BucketScriptPipelineAggregationBuilder.PARSER));
|
BucketScriptPipelineAggregationBuilder.PARSER));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
BucketSelectorPipelineAggregationBuilder.NAME,
|
BucketSelectorPipelineAggregationBuilder.NAME,
|
||||||
BucketSelectorPipelineAggregationBuilder::new,
|
BucketSelectorPipelineAggregationBuilder::new,
|
||||||
BucketSelectorPipelineAggregator::new,
|
BucketSelectorPipelineAggregator::new,
|
||||||
BucketSelectorPipelineAggregationBuilder::parse));
|
BucketSelectorPipelineAggregationBuilder::parse));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
BucketSortPipelineAggregationBuilder.NAME,
|
BucketSortPipelineAggregationBuilder.NAME,
|
||||||
BucketSortPipelineAggregationBuilder::new,
|
BucketSortPipelineAggregationBuilder::new,
|
||||||
BucketSortPipelineAggregator::new,
|
BucketSortPipelineAggregator::new,
|
||||||
BucketSortPipelineAggregationBuilder::parse));
|
BucketSortPipelineAggregationBuilder::parse));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
SerialDiffPipelineAggregationBuilder.NAME,
|
SerialDiffPipelineAggregationBuilder.NAME,
|
||||||
SerialDiffPipelineAggregationBuilder::new,
|
SerialDiffPipelineAggregationBuilder::new,
|
||||||
SerialDiffPipelineAggregator::new,
|
SerialDiffPipelineAggregator::new,
|
||||||
SerialDiffPipelineAggregationBuilder::parse));
|
SerialDiffPipelineAggregationBuilder::parse));
|
||||||
registerPipelineAggregation(new PipelineAggregationSpec(
|
registerPipelineAggregation(new PipelineAggregationSpec(
|
||||||
MovFnPipelineAggregationBuilder.NAME,
|
MovFnPipelineAggregationBuilder.NAME,
|
||||||
MovFnPipelineAggregationBuilder::new,
|
MovFnPipelineAggregationBuilder::new,
|
||||||
MovFnPipelineAggregator::new,
|
MovFnPipelineAggregator::new,
|
||||||
MovFnPipelineAggregationBuilder.PARSER));
|
MovFnPipelineAggregationBuilder.PARSER));
|
||||||
|
|
||||||
registerFromPlugin(plugins, SearchPlugin::getPipelineAggregations, this::registerPipelineAggregation);
|
registerFromPlugin(plugins, SearchPlugin::getPipelineAggregations, this::registerPipelineAggregation);
|
||||||
}
|
}
|
||||||
|
@ -650,23 +647,17 @@ public class SearchModule {
|
||||||
private void registerPipelineAggregation(PipelineAggregationSpec spec) {
|
private void registerPipelineAggregation(PipelineAggregationSpec spec) {
|
||||||
if (false == transportClient) {
|
if (false == transportClient) {
|
||||||
namedXContents.add(new NamedXContentRegistry.Entry(BaseAggregationBuilder.class, spec.getName(),
|
namedXContents.add(new NamedXContentRegistry.Entry(BaseAggregationBuilder.class, spec.getName(),
|
||||||
(p, c) -> spec.getParser().parse(p, (String) c)));
|
(p, c) -> spec.getParser().parse(p, (String) c)));
|
||||||
}
|
}
|
||||||
namedWriteables.add(
|
namedWriteables.add(
|
||||||
new NamedWriteableRegistry.Entry(PipelineAggregationBuilder.class, spec.getName().getPreferredName(), spec.getReader()));
|
new NamedWriteableRegistry.Entry(PipelineAggregationBuilder.class, spec.getName().getPreferredName(), spec.getReader()));
|
||||||
if (spec.getAggregatorReader() != null) {
|
if (spec.getAggregatorReader() != null) {
|
||||||
namedWriteables.add(new NamedWriteableRegistry.Entry(
|
namedWriteables.add(new NamedWriteableRegistry.Entry(
|
||||||
PipelineAggregator.class, spec.getName().getPreferredName(), spec.getAggregatorReader()));
|
PipelineAggregator.class, spec.getName().getPreferredName(), spec.getAggregatorReader()));
|
||||||
}
|
}
|
||||||
for (Map.Entry<String, Writeable.Reader<? extends InternalAggregation>> resultReader : spec.getResultReaders().entrySet()) {
|
for (Map.Entry<String, Writeable.Reader<? extends InternalAggregation>> resultReader : spec.getResultReaders().entrySet()) {
|
||||||
namedWriteables
|
namedWriteables
|
||||||
.add(new NamedWriteableRegistry.Entry(InternalAggregation.class, resultReader.getKey(), resultReader.getValue()));
|
.add(new NamedWriteableRegistry.Entry(InternalAggregation.class, resultReader.getKey(), resultReader.getValue()));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerShapes() {
|
|
||||||
if (ShapesAvailability.JTS_AVAILABLE && ShapesAvailability.SPATIAL4J_AVAILABLE) {
|
|
||||||
namedWriteables.addAll(GeoShapeType.getShapeWriteables());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,9 +711,9 @@ public class SearchModule {
|
||||||
|
|
||||||
private void registerSuggester(SuggesterSpec<?> suggester) {
|
private void registerSuggester(SuggesterSpec<?> suggester) {
|
||||||
namedWriteables.add(new NamedWriteableRegistry.Entry(
|
namedWriteables.add(new NamedWriteableRegistry.Entry(
|
||||||
SuggestionBuilder.class, suggester.getName().getPreferredName(), suggester.getReader()));
|
SuggestionBuilder.class, suggester.getName().getPreferredName(), suggester.getReader()));
|
||||||
namedXContents.add(new NamedXContentRegistry.Entry(SuggestionBuilder.class, suggester.getName(),
|
namedXContents.add(new NamedXContentRegistry.Entry(SuggestionBuilder.class, suggester.getName(),
|
||||||
suggester.getParser()));
|
suggester.getParser()));
|
||||||
|
|
||||||
namedWriteables.add(new NamedWriteableRegistry.Entry(
|
namedWriteables.add(new NamedWriteableRegistry.Entry(
|
||||||
Suggest.Suggestion.class, suggester.getName().getPreferredName(), suggester.getSuggestionReader()
|
Suggest.Suggestion.class, suggester.getName().getPreferredName(), suggester.getSuggestionReader()
|
||||||
|
@ -744,18 +735,18 @@ public class SearchModule {
|
||||||
namedWriteables.add(new NamedWriteableRegistry.Entry(
|
namedWriteables.add(new NamedWriteableRegistry.Entry(
|
||||||
ScriptScoreFunctionBuilder.class, ScriptScoreFunctionBuilder.NAME, ScriptScoreFunctionBuilder::new));
|
ScriptScoreFunctionBuilder.class, ScriptScoreFunctionBuilder.NAME, ScriptScoreFunctionBuilder::new));
|
||||||
registerScoreFunction(new ScoreFunctionSpec<>(ScriptScoreFunctionBuilder.NAME, ScriptScoreFunctionBuilder::new,
|
registerScoreFunction(new ScoreFunctionSpec<>(ScriptScoreFunctionBuilder.NAME, ScriptScoreFunctionBuilder::new,
|
||||||
ScriptScoreFunctionBuilder::fromXContent));
|
ScriptScoreFunctionBuilder::fromXContent));
|
||||||
|
|
||||||
registerScoreFunction(
|
registerScoreFunction(
|
||||||
new ScoreFunctionSpec<>(GaussDecayFunctionBuilder.NAME, GaussDecayFunctionBuilder::new, GaussDecayFunctionBuilder.PARSER));
|
new ScoreFunctionSpec<>(GaussDecayFunctionBuilder.NAME, GaussDecayFunctionBuilder::new, GaussDecayFunctionBuilder.PARSER));
|
||||||
registerScoreFunction(new ScoreFunctionSpec<>(LinearDecayFunctionBuilder.NAME, LinearDecayFunctionBuilder::new,
|
registerScoreFunction(new ScoreFunctionSpec<>(LinearDecayFunctionBuilder.NAME, LinearDecayFunctionBuilder::new,
|
||||||
LinearDecayFunctionBuilder.PARSER));
|
LinearDecayFunctionBuilder.PARSER));
|
||||||
registerScoreFunction(new ScoreFunctionSpec<>(ExponentialDecayFunctionBuilder.NAME, ExponentialDecayFunctionBuilder::new,
|
registerScoreFunction(new ScoreFunctionSpec<>(ExponentialDecayFunctionBuilder.NAME, ExponentialDecayFunctionBuilder::new,
|
||||||
ExponentialDecayFunctionBuilder.PARSER));
|
ExponentialDecayFunctionBuilder.PARSER));
|
||||||
registerScoreFunction(new ScoreFunctionSpec<>(RandomScoreFunctionBuilder.NAME, RandomScoreFunctionBuilder::new,
|
registerScoreFunction(new ScoreFunctionSpec<>(RandomScoreFunctionBuilder.NAME, RandomScoreFunctionBuilder::new,
|
||||||
RandomScoreFunctionBuilder::fromXContent));
|
RandomScoreFunctionBuilder::fromXContent));
|
||||||
registerScoreFunction(new ScoreFunctionSpec<>(FieldValueFactorFunctionBuilder.NAME, FieldValueFactorFunctionBuilder::new,
|
registerScoreFunction(new ScoreFunctionSpec<>(FieldValueFactorFunctionBuilder.NAME, FieldValueFactorFunctionBuilder::new,
|
||||||
FieldValueFactorFunctionBuilder::fromXContent));
|
FieldValueFactorFunctionBuilder::fromXContent));
|
||||||
|
|
||||||
//weight doesn't have its own parser, so every function supports it out of the box.
|
//weight doesn't have its own parser, so every function supports it out of the box.
|
||||||
//Can be a single function too when not associated to any other function, which is why it needs to be registered manually here.
|
//Can be a single function too when not associated to any other function, which is why it needs to be registered manually here.
|
||||||
|
@ -766,11 +757,11 @@ public class SearchModule {
|
||||||
|
|
||||||
private void registerScoreFunction(ScoreFunctionSpec<?> scoreFunction) {
|
private void registerScoreFunction(ScoreFunctionSpec<?> scoreFunction) {
|
||||||
namedWriteables.add(new NamedWriteableRegistry.Entry(
|
namedWriteables.add(new NamedWriteableRegistry.Entry(
|
||||||
ScoreFunctionBuilder.class, scoreFunction.getName().getPreferredName(), scoreFunction.getReader()));
|
ScoreFunctionBuilder.class, scoreFunction.getName().getPreferredName(), scoreFunction.getReader()));
|
||||||
// TODO remove funky contexts
|
// TODO remove funky contexts
|
||||||
namedXContents.add(new NamedXContentRegistry.Entry(
|
namedXContents.add(new NamedXContentRegistry.Entry(
|
||||||
ScoreFunctionBuilder.class, scoreFunction.getName(),
|
ScoreFunctionBuilder.class, scoreFunction.getName(),
|
||||||
(XContentParser p, Object c) -> scoreFunction.getParser().fromXContent(p)));
|
(XContentParser p, Object c) -> scoreFunction.getParser().fromXContent(p)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerValueFormats() {
|
private void registerValueFormats() {
|
||||||
|
@ -824,7 +815,7 @@ public class SearchModule {
|
||||||
private void registerMovingAverageModel(SearchExtensionSpec<MovAvgModel, MovAvgModel.AbstractModelParser> movAvgModel) {
|
private void registerMovingAverageModel(SearchExtensionSpec<MovAvgModel, MovAvgModel.AbstractModelParser> movAvgModel) {
|
||||||
movingAverageModelParserRegistry.register(movAvgModel.getParser(), movAvgModel.getName());
|
movingAverageModelParserRegistry.register(movAvgModel.getParser(), movAvgModel.getName());
|
||||||
namedWriteables.add(
|
namedWriteables.add(
|
||||||
new NamedWriteableRegistry.Entry(MovAvgModel.class, movAvgModel.getName().getPreferredName(), movAvgModel.getReader()));
|
new NamedWriteableRegistry.Entry(MovAvgModel.class, movAvgModel.getName().getPreferredName(), movAvgModel.getReader()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerFetchSubPhases(List<SearchPlugin> plugins) {
|
private void registerFetchSubPhases(List<SearchPlugin> plugins) {
|
||||||
|
@ -864,7 +855,7 @@ public class SearchModule {
|
||||||
registerQuery(new QuerySpec<>(MatchQueryBuilder.NAME, MatchQueryBuilder::new, MatchQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(MatchQueryBuilder.NAME, MatchQueryBuilder::new, MatchQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(MatchPhraseQueryBuilder.NAME, MatchPhraseQueryBuilder::new, MatchPhraseQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(MatchPhraseQueryBuilder.NAME, MatchPhraseQueryBuilder::new, MatchPhraseQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(MatchPhrasePrefixQueryBuilder.NAME, MatchPhrasePrefixQueryBuilder::new,
|
registerQuery(new QuerySpec<>(MatchPhrasePrefixQueryBuilder.NAME, MatchPhrasePrefixQueryBuilder::new,
|
||||||
MatchPhrasePrefixQueryBuilder::fromXContent));
|
MatchPhrasePrefixQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(MultiMatchQueryBuilder.NAME, MultiMatchQueryBuilder::new, MultiMatchQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(MultiMatchQueryBuilder.NAME, MultiMatchQueryBuilder::new, MultiMatchQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(CombinedFieldsQueryBuilder.NAME, CombinedFieldsQueryBuilder::new,
|
registerQuery(new QuerySpec<>(CombinedFieldsQueryBuilder.NAME, CombinedFieldsQueryBuilder::new,
|
||||||
CombinedFieldsQueryBuilder::fromXContent));
|
CombinedFieldsQueryBuilder::fromXContent));
|
||||||
|
@ -885,35 +876,35 @@ public class SearchModule {
|
||||||
registerQuery(new QuerySpec<>(PrefixQueryBuilder.NAME, PrefixQueryBuilder::new, PrefixQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(PrefixQueryBuilder.NAME, PrefixQueryBuilder::new, PrefixQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(WildcardQueryBuilder.NAME, WildcardQueryBuilder::new, WildcardQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(WildcardQueryBuilder.NAME, WildcardQueryBuilder::new, WildcardQueryBuilder::fromXContent));
|
||||||
registerQuery(
|
registerQuery(
|
||||||
new QuerySpec<>(ConstantScoreQueryBuilder.NAME, ConstantScoreQueryBuilder::new, ConstantScoreQueryBuilder::fromXContent));
|
new QuerySpec<>(ConstantScoreQueryBuilder.NAME, ConstantScoreQueryBuilder::new, ConstantScoreQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(SpanTermQueryBuilder.NAME, SpanTermQueryBuilder::new, SpanTermQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(SpanTermQueryBuilder.NAME, SpanTermQueryBuilder::new, SpanTermQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(SpanNotQueryBuilder.NAME, SpanNotQueryBuilder::new, SpanNotQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(SpanNotQueryBuilder.NAME, SpanNotQueryBuilder::new, SpanNotQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(SpanWithinQueryBuilder.NAME, SpanWithinQueryBuilder::new, SpanWithinQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(SpanWithinQueryBuilder.NAME, SpanWithinQueryBuilder::new, SpanWithinQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(SpanContainingQueryBuilder.NAME, SpanContainingQueryBuilder::new,
|
registerQuery(new QuerySpec<>(SpanContainingQueryBuilder.NAME, SpanContainingQueryBuilder::new,
|
||||||
SpanContainingQueryBuilder::fromXContent));
|
SpanContainingQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(FieldMaskingSpanQueryBuilder.NAME, FieldMaskingSpanQueryBuilder::new,
|
registerQuery(new QuerySpec<>(FieldMaskingSpanQueryBuilder.NAME, FieldMaskingSpanQueryBuilder::new,
|
||||||
FieldMaskingSpanQueryBuilder::fromXContent));
|
FieldMaskingSpanQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(SpanFirstQueryBuilder.NAME, SpanFirstQueryBuilder::new, SpanFirstQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(SpanFirstQueryBuilder.NAME, SpanFirstQueryBuilder::new, SpanFirstQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(SpanNearQueryBuilder.NAME, SpanNearQueryBuilder::new, SpanNearQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(SpanNearQueryBuilder.NAME, SpanNearQueryBuilder::new, SpanNearQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(SpanGapQueryBuilder.NAME, SpanGapQueryBuilder::new, SpanGapQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(SpanGapQueryBuilder.NAME, SpanGapQueryBuilder::new, SpanGapQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(SpanOrQueryBuilder.NAME, SpanOrQueryBuilder::new, SpanOrQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(SpanOrQueryBuilder.NAME, SpanOrQueryBuilder::new, SpanOrQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(MoreLikeThisQueryBuilder.NAME, MoreLikeThisQueryBuilder::new,
|
registerQuery(new QuerySpec<>(MoreLikeThisQueryBuilder.NAME, MoreLikeThisQueryBuilder::new,
|
||||||
MoreLikeThisQueryBuilder::fromXContent));
|
MoreLikeThisQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(WrapperQueryBuilder.NAME, WrapperQueryBuilder::new, WrapperQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(WrapperQueryBuilder.NAME, WrapperQueryBuilder::new, WrapperQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(new ParseField(CommonTermsQueryBuilder.NAME).withAllDeprecated(COMMON_TERMS_QUERY_DEPRECATION_MSG),
|
registerQuery(new QuerySpec<>(new ParseField(CommonTermsQueryBuilder.NAME).withAllDeprecated(COMMON_TERMS_QUERY_DEPRECATION_MSG),
|
||||||
CommonTermsQueryBuilder::new, CommonTermsQueryBuilder::fromXContent));
|
CommonTermsQueryBuilder::new, CommonTermsQueryBuilder::fromXContent));
|
||||||
registerQuery(
|
registerQuery(
|
||||||
new QuerySpec<>(SpanMultiTermQueryBuilder.NAME, SpanMultiTermQueryBuilder::new, SpanMultiTermQueryBuilder::fromXContent));
|
new QuerySpec<>(SpanMultiTermQueryBuilder.NAME, SpanMultiTermQueryBuilder::new, SpanMultiTermQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(FunctionScoreQueryBuilder.NAME, FunctionScoreQueryBuilder::new,
|
registerQuery(new QuerySpec<>(FunctionScoreQueryBuilder.NAME, FunctionScoreQueryBuilder::new,
|
||||||
FunctionScoreQueryBuilder::fromXContent));
|
FunctionScoreQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(ScriptScoreQueryBuilder.NAME, ScriptScoreQueryBuilder::new, ScriptScoreQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(ScriptScoreQueryBuilder.NAME, ScriptScoreQueryBuilder::new, ScriptScoreQueryBuilder::fromXContent));
|
||||||
registerQuery(
|
registerQuery(
|
||||||
new QuerySpec<>(SimpleQueryStringBuilder.NAME, SimpleQueryStringBuilder::new, SimpleQueryStringBuilder::fromXContent));
|
new QuerySpec<>(SimpleQueryStringBuilder.NAME, SimpleQueryStringBuilder::new, SimpleQueryStringBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(TypeQueryBuilder.NAME, TypeQueryBuilder::new, TypeQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(TypeQueryBuilder.NAME, TypeQueryBuilder::new, TypeQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(ScriptQueryBuilder.NAME, ScriptQueryBuilder::new, ScriptQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(ScriptQueryBuilder.NAME, ScriptQueryBuilder::new, ScriptQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(GeoDistanceQueryBuilder.NAME, GeoDistanceQueryBuilder::new, GeoDistanceQueryBuilder::fromXContent));
|
registerQuery(new QuerySpec<>(GeoDistanceQueryBuilder.NAME, GeoDistanceQueryBuilder::new, GeoDistanceQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(GeoBoundingBoxQueryBuilder.NAME, GeoBoundingBoxQueryBuilder::new,
|
registerQuery(new QuerySpec<>(GeoBoundingBoxQueryBuilder.NAME, GeoBoundingBoxQueryBuilder::new,
|
||||||
GeoBoundingBoxQueryBuilder::fromXContent));
|
GeoBoundingBoxQueryBuilder::fromXContent));
|
||||||
registerQuery(new QuerySpec<>(
|
registerQuery(new QuerySpec<>(
|
||||||
(new ParseField(GeoPolygonQueryBuilder.NAME).withAllDeprecated(GeoPolygonQueryBuilder.GEO_POLYGON_DEPRECATION_MSG)),
|
(new ParseField(GeoPolygonQueryBuilder.NAME).withAllDeprecated(GeoPolygonQueryBuilder.GEO_POLYGON_DEPRECATION_MSG)),
|
||||||
GeoPolygonQueryBuilder::new, GeoPolygonQueryBuilder::fromXContent));
|
GeoPolygonQueryBuilder::new, GeoPolygonQueryBuilder::fromXContent));
|
||||||
|
@ -925,10 +916,8 @@ public class SearchModule {
|
||||||
DistanceFeatureQueryBuilder::fromXContent));
|
DistanceFeatureQueryBuilder::fromXContent));
|
||||||
registerQuery(
|
registerQuery(
|
||||||
new QuerySpec<>(MatchBoolPrefixQueryBuilder.NAME, MatchBoolPrefixQueryBuilder::new, MatchBoolPrefixQueryBuilder::fromXContent));
|
new QuerySpec<>(MatchBoolPrefixQueryBuilder.NAME, MatchBoolPrefixQueryBuilder::new, MatchBoolPrefixQueryBuilder::fromXContent));
|
||||||
|
registerQuery(new QuerySpec<>(GeoShapeQueryBuilder.NAME, GeoShapeQueryBuilder::new, GeoShapeQueryBuilder::fromXContent));
|
||||||
|
|
||||||
if (ShapesAvailability.JTS_AVAILABLE && ShapesAvailability.SPATIAL4J_AVAILABLE) {
|
|
||||||
registerQuery(new QuerySpec<>(GeoShapeQueryBuilder.NAME, GeoShapeQueryBuilder::new, GeoShapeQueryBuilder::fromXContent));
|
|
||||||
}
|
|
||||||
|
|
||||||
registerFromPlugin(plugins, SearchPlugin::getQueries, this::registerQuery);
|
registerFromPlugin(plugins, SearchPlugin::getQueries, this::registerQuery);
|
||||||
}
|
}
|
||||||
|
@ -955,24 +944,24 @@ public class SearchModule {
|
||||||
|
|
||||||
public static List<NamedWriteableRegistry.Entry> getIntervalsSourceProviderNamedWritables() {
|
public static List<NamedWriteableRegistry.Entry> getIntervalsSourceProviderNamedWritables() {
|
||||||
return unmodifiableList(Arrays.asList(
|
return unmodifiableList(Arrays.asList(
|
||||||
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Match.NAME,
|
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Match.NAME,
|
||||||
IntervalsSourceProvider.Match::new),
|
IntervalsSourceProvider.Match::new),
|
||||||
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Combine.NAME,
|
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Combine.NAME,
|
||||||
IntervalsSourceProvider.Combine::new),
|
IntervalsSourceProvider.Combine::new),
|
||||||
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Disjunction.NAME,
|
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Disjunction.NAME,
|
||||||
IntervalsSourceProvider.Disjunction::new),
|
IntervalsSourceProvider.Disjunction::new),
|
||||||
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Prefix.NAME,
|
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Prefix.NAME,
|
||||||
IntervalsSourceProvider.Prefix::new),
|
IntervalsSourceProvider.Prefix::new),
|
||||||
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Wildcard.NAME,
|
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Wildcard.NAME,
|
||||||
IntervalsSourceProvider.Wildcard::new),
|
IntervalsSourceProvider.Wildcard::new),
|
||||||
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Fuzzy.NAME,
|
new NamedWriteableRegistry.Entry(IntervalsSourceProvider.class, IntervalsSourceProvider.Fuzzy.NAME,
|
||||||
IntervalsSourceProvider.Fuzzy::new)));
|
IntervalsSourceProvider.Fuzzy::new)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerQuery(QuerySpec<?> spec) {
|
private void registerQuery(QuerySpec<?> spec) {
|
||||||
namedWriteables.add(new NamedWriteableRegistry.Entry(QueryBuilder.class, spec.getName().getPreferredName(), spec.getReader()));
|
namedWriteables.add(new NamedWriteableRegistry.Entry(QueryBuilder.class, spec.getName().getPreferredName(), spec.getReader()));
|
||||||
namedXContents.add(new NamedXContentRegistry.Entry(QueryBuilder.class, spec.getName(),
|
namedXContents.add(new NamedXContentRegistry.Entry(QueryBuilder.class, spec.getName(),
|
||||||
(p, c) -> spec.getParser().fromXContent(p)));
|
(p, c) -> spec.getParser().fromXContent(p)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerBoolQuery(ParseField name, Writeable.Reader<QueryBuilder> reader) {
|
private void registerBoolQuery(ParseField name, Writeable.Reader<QueryBuilder> reader) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.elasticsearch.geometry.Point;
|
||||||
import org.elasticsearch.geometry.Polygon;
|
import org.elasticsearch.geometry.Polygon;
|
||||||
import org.elasticsearch.geometry.Rectangle;
|
import org.elasticsearch.geometry.Rectangle;
|
||||||
import org.elasticsearch.geometry.utils.GeographyValidator;
|
import org.elasticsearch.geometry.utils.GeographyValidator;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
|
@ -36,9 +37,8 @@ import java.util.Collections;
|
||||||
/**
|
/**
|
||||||
* Tests for {@code GeoJSONShapeParser}
|
* Tests for {@code GeoJSONShapeParser}
|
||||||
*/
|
*/
|
||||||
public class GeoJsonParserTests extends BaseGeoParsingTestCase {
|
public class GeoJsonParserTests extends ESTestCase {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void testParsePoint() throws IOException {
|
public void testParsePoint() throws IOException {
|
||||||
XContentBuilder pointGeoJson = XContentFactory.jsonBuilder()
|
XContentBuilder pointGeoJson = XContentFactory.jsonBuilder()
|
||||||
.startObject()
|
.startObject()
|
||||||
|
@ -49,7 +49,6 @@ public class GeoJsonParserTests extends BaseGeoParsingTestCase {
|
||||||
assertGeometryEquals(expected, pointGeoJson);
|
assertGeometryEquals(expected, pointGeoJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void testParseLineString() throws IOException {
|
public void testParseLineString() throws IOException {
|
||||||
XContentBuilder lineGeoJson = XContentFactory.jsonBuilder()
|
XContentBuilder lineGeoJson = XContentFactory.jsonBuilder()
|
||||||
.startObject()
|
.startObject()
|
||||||
|
@ -67,7 +66,6 @@ public class GeoJsonParserTests extends BaseGeoParsingTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void testParseMultiLineString() throws IOException {
|
public void testParseMultiLineString() throws IOException {
|
||||||
XContentBuilder multilinesGeoJson = XContentFactory.jsonBuilder()
|
XContentBuilder multilinesGeoJson = XContentFactory.jsonBuilder()
|
||||||
.startObject()
|
.startObject()
|
||||||
|
@ -138,7 +136,6 @@ public class GeoJsonParserTests extends BaseGeoParsingTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void testParseEnvelope() throws IOException {
|
public void testParseEnvelope() throws IOException {
|
||||||
// test #1: envelope with expected coordinate order (TopLeft, BottomRight)
|
// test #1: envelope with expected coordinate order (TopLeft, BottomRight)
|
||||||
XContentBuilder multilinesGeoJson = XContentFactory.jsonBuilder().startObject().field("type", randomBoolean() ? "envelope" : "bbox")
|
XContentBuilder multilinesGeoJson = XContentFactory.jsonBuilder().startObject().field("type", randomBoolean() ? "envelope" : "bbox")
|
||||||
|
@ -189,7 +186,6 @@ public class GeoJsonParserTests extends BaseGeoParsingTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void testParsePolygon() throws IOException {
|
public void testParsePolygon() throws IOException {
|
||||||
XContentBuilder polygonGeoJson = XContentFactory.jsonBuilder()
|
XContentBuilder polygonGeoJson = XContentFactory.jsonBuilder()
|
||||||
.startObject()
|
.startObject()
|
||||||
|
@ -516,7 +512,6 @@ public class GeoJsonParserTests extends BaseGeoParsingTestCase {
|
||||||
assertGeometryEquals(p, polygonGeoJson);
|
assertGeometryEquals(p, polygonGeoJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void testParseMultiPoint() throws IOException {
|
public void testParseMultiPoint() throws IOException {
|
||||||
XContentBuilder multiPointGeoJson = XContentFactory.jsonBuilder()
|
XContentBuilder multiPointGeoJson = XContentFactory.jsonBuilder()
|
||||||
.startObject()
|
.startObject()
|
||||||
|
@ -532,7 +527,6 @@ public class GeoJsonParserTests extends BaseGeoParsingTestCase {
|
||||||
new Point(101, 1))), multiPointGeoJson);
|
new Point(101, 1))), multiPointGeoJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void testParseMultiPolygon() throws IOException {
|
public void testParseMultiPolygon() throws IOException {
|
||||||
// two polygons; one without hole, one with hole
|
// two polygons; one without hole, one with hole
|
||||||
XContentBuilder multiPolygonGeoJson = XContentFactory.jsonBuilder()
|
XContentBuilder multiPolygonGeoJson = XContentFactory.jsonBuilder()
|
||||||
|
@ -580,7 +574,6 @@ public class GeoJsonParserTests extends BaseGeoParsingTestCase {
|
||||||
assertGeometryEquals(polygons, multiPolygonGeoJson);
|
assertGeometryEquals(polygons, multiPolygonGeoJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void testParseGeometryCollection() throws IOException {
|
public void testParseGeometryCollection() throws IOException {
|
||||||
XContentBuilder geometryCollectionGeoJson = XContentFactory.jsonBuilder()
|
XContentBuilder geometryCollectionGeoJson = XContentFactory.jsonBuilder()
|
||||||
.startObject()
|
.startObject()
|
||||||
|
@ -641,7 +634,7 @@ public class GeoJsonParserTests extends BaseGeoParsingTestCase {
|
||||||
.endObject();
|
.endObject();
|
||||||
|
|
||||||
Point expectedPt = new Point(100, 0);
|
Point expectedPt = new Point(100, 0);
|
||||||
assertGeometryEquals(expectedPt, pointGeoJson, false);
|
assertGeometryEquals(expectedPt, pointGeoJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testParseOrientationOption() throws IOException {
|
public void testParseOrientationOption() throws IOException {
|
||||||
|
@ -763,4 +756,11 @@ public class GeoJsonParserTests extends BaseGeoParsingTestCase {
|
||||||
assertNull(parser.nextToken()); // no more elements afterwards
|
assertNull(parser.nextToken()); // no more elements afterwards
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertGeometryEquals(org.elasticsearch.geometry.Geometry expected, XContentBuilder geoJson) throws IOException {
|
||||||
|
try (XContentParser parser = createParser(geoJson)) {
|
||||||
|
parser.nextToken();
|
||||||
|
assertEquals(expected, GeoJson.fromXContent(GeographyValidator.instance(false), false, true, parser));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,18 +8,12 @@
|
||||||
|
|
||||||
package org.elasticsearch.common.geo;
|
package org.elasticsearch.common.geo;
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput;
|
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.geometry.Geometry;
|
import org.elasticsearch.geometry.Geometry;
|
||||||
import org.elasticsearch.geometry.GeometryCollection;
|
|
||||||
import org.elasticsearch.geometry.ShapeType;
|
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
import static org.elasticsearch.geo.GeometryTestUtils.randomGeometry;
|
import static org.elasticsearch.geo.GeometryTestUtils.randomGeometry;
|
||||||
import static org.elasticsearch.index.query.LegacyGeoShapeQueryProcessor.geometryToShapeBuilder;
|
|
||||||
|
|
||||||
public class GeometryIOTests extends ESTestCase {
|
public class GeometryIOTests extends ESTestCase {
|
||||||
|
|
||||||
|
@ -27,69 +21,16 @@ public class GeometryIOTests extends ESTestCase {
|
||||||
for (int i = 0; i < randomIntBetween(1, 20); i++) {
|
for (int i = 0; i < randomIntBetween(1, 20); i++) {
|
||||||
boolean hasAlt = randomBoolean();
|
boolean hasAlt = randomBoolean();
|
||||||
Geometry geometry = randomGeometry(hasAlt);
|
Geometry geometry = randomGeometry(hasAlt);
|
||||||
if (shapeSupported(geometry) && randomBoolean()) {
|
// Test Geometry -> Geometry
|
||||||
// Shape builder conversion doesn't support altitude
|
try (BytesStreamOutput out = new BytesStreamOutput()) {
|
||||||
ShapeBuilder<?, ?, ?> shapeBuilder = geometryToShapeBuilder(geometry);
|
GeometryIO.writeGeometry(out, geometry);
|
||||||
if (randomBoolean()) {
|
;
|
||||||
Geometry actual = shapeBuilder.buildGeometry();
|
try (StreamInput in = out.bytes().streamInput()) {
|
||||||
|
Geometry actual = GeometryIO.readGeometry(in);
|
||||||
assertEquals(geometry, actual);
|
assertEquals(geometry, actual);
|
||||||
}
|
assertEquals(0, in.available());
|
||||||
if (randomBoolean()) {
|
|
||||||
// Test ShapeBuilder -> Geometry Serialization
|
|
||||||
try (BytesStreamOutput out = new BytesStreamOutput()) {
|
|
||||||
out.writeNamedWriteable(shapeBuilder);
|
|
||||||
try (StreamInput in = out.bytes().streamInput()) {
|
|
||||||
Geometry actual = GeometryIO.readGeometry(in);
|
|
||||||
assertEquals(geometry, actual);
|
|
||||||
assertEquals(0, in.available());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Test Geometry -> ShapeBuilder Serialization
|
|
||||||
try (BytesStreamOutput out = new BytesStreamOutput()) {
|
|
||||||
GeometryIO.writeGeometry(out, geometry);
|
|
||||||
try (StreamInput in = out.bytes().streamInput()) {
|
|
||||||
try (StreamInput nin = new NamedWriteableAwareStreamInput(in, this.writableRegistry())) {
|
|
||||||
ShapeBuilder<?, ?, ?> actual = nin.readNamedWriteable(ShapeBuilder.class);
|
|
||||||
assertEquals(shapeBuilder, actual);
|
|
||||||
assertEquals(0, in.available());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Test Geometry -> Geometry
|
|
||||||
try (BytesStreamOutput out = new BytesStreamOutput()) {
|
|
||||||
GeometryIO.writeGeometry(out, geometry);
|
|
||||||
;
|
|
||||||
try (StreamInput in = out.bytes().streamInput()) {
|
|
||||||
Geometry actual = GeometryIO.readGeometry(in);
|
|
||||||
assertEquals(geometry, actual);
|
|
||||||
assertEquals(0, in.available());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shapeSupported(Geometry geometry) {
|
|
||||||
if (geometry.hasZ()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (geometry.type() == ShapeType.GEOMETRYCOLLECTION) {
|
|
||||||
GeometryCollection<?> collection = (GeometryCollection<?>) geometry;
|
|
||||||
for (Geometry g : collection) {
|
|
||||||
if (shapeSupported(g) == false) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected NamedWriteableRegistry writableRegistry() {
|
|
||||||
return new NamedWriteableRegistry(GeoShapeType.getShapeWriteables());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,842 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.elasticsearch.common.geo;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.geo.builders.CircleBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.CoordinatesBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.EnvelopeBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.LineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.MultiLineStringBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PointBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.PolygonBuilder;
|
|
||||||
import org.elasticsearch.common.geo.builders.ShapeBuilder;
|
|
||||||
import org.elasticsearch.geometry.LinearRing;
|
|
||||||
import org.elasticsearch.index.mapper.GeoShapeIndexer;
|
|
||||||
import org.elasticsearch.test.ESTestCase;
|
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
|
||||||
import org.locationtech.jts.geom.LineString;
|
|
||||||
import org.locationtech.jts.geom.Polygon;
|
|
||||||
import org.locationtech.spatial4j.exception.InvalidShapeException;
|
|
||||||
import org.locationtech.spatial4j.shape.Circle;
|
|
||||||
import org.locationtech.spatial4j.shape.Point;
|
|
||||||
import org.locationtech.spatial4j.shape.Rectangle;
|
|
||||||
import org.locationtech.spatial4j.shape.impl.PointImpl;
|
|
||||||
|
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchGeoAssertions.assertMultiLineString;
|
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchGeoAssertions.assertMultiPolygon;
|
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchGeoAssertions.assertPolygon;
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
import static org.hamcrest.Matchers.not;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link ShapeBuilder}
|
|
||||||
*/
|
|
||||||
public class ShapeBuilderTests extends ESTestCase {
|
|
||||||
|
|
||||||
public void testNewPoint() {
|
|
||||||
PointBuilder pb = new PointBuilder().coordinate(-100, 45);
|
|
||||||
Point point = pb.buildS4J();
|
|
||||||
assertEquals(-100D, point.getX(), 0.0d);
|
|
||||||
assertEquals(45D, point.getY(), 0.0d);
|
|
||||||
org.elasticsearch.geometry.Point geoPoint = pb.buildGeometry();
|
|
||||||
assertEquals(-100D, geoPoint.getX(), 0.0d);
|
|
||||||
assertEquals(45D, geoPoint.getY(), 0.0d);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testNewRectangle() {
|
|
||||||
EnvelopeBuilder eb = new EnvelopeBuilder(new Coordinate(-45, 30), new Coordinate(45, -30));
|
|
||||||
Rectangle rectangle = eb.buildS4J();
|
|
||||||
assertEquals(-45D, rectangle.getMinX(), 0.0d);
|
|
||||||
assertEquals(-30D, rectangle.getMinY(), 0.0d);
|
|
||||||
assertEquals(45D, rectangle.getMaxX(), 0.0d);
|
|
||||||
assertEquals(30D, rectangle.getMaxY(), 0.0d);
|
|
||||||
|
|
||||||
org.elasticsearch.geometry.Rectangle luceneRectangle = eb.buildGeometry();
|
|
||||||
assertEquals(-45D, luceneRectangle.getMinX(), 0.0d);
|
|
||||||
assertEquals(-30D, luceneRectangle.getMinY(), 0.0d);
|
|
||||||
assertEquals(45D, luceneRectangle.getMaxX(), 0.0d);
|
|
||||||
assertEquals(30D, luceneRectangle.getMaxY(), 0.0d);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testNewPolygon() {
|
|
||||||
PolygonBuilder pb = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-45, 30)
|
|
||||||
.coordinate(45, 30)
|
|
||||||
.coordinate(45, -30)
|
|
||||||
.coordinate(-45, -30)
|
|
||||||
.coordinate(-45, 30));
|
|
||||||
|
|
||||||
Polygon poly = pb.toPolygonS4J();
|
|
||||||
LineString exterior = poly.getExteriorRing();
|
|
||||||
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
|
||||||
assertEquals(exterior.getCoordinateN(1), new Coordinate(45, 30));
|
|
||||||
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
|
|
||||||
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
|
|
||||||
|
|
||||||
LinearRing polygon = pb.toPolygonGeometry().getPolygon();
|
|
||||||
assertEquals(polygon.getY(0), 30, 0d);
|
|
||||||
assertEquals(polygon.getX(0), -45, 0d);
|
|
||||||
assertEquals(polygon.getY(1), 30, 0d);
|
|
||||||
assertEquals(polygon.getX(1), 45, 0d);
|
|
||||||
assertEquals(polygon.getY(2), -30, 0d);
|
|
||||||
assertEquals(polygon.getX(2), 45, 0d);
|
|
||||||
assertEquals(polygon.getY(3), -30, 0d);
|
|
||||||
assertEquals(polygon.getX(3), -45, 0d);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testNewPolygon_coordinate() {
|
|
||||||
PolygonBuilder pb = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(new Coordinate(-45, 30))
|
|
||||||
.coordinate(new Coordinate(45, 30))
|
|
||||||
.coordinate(new Coordinate(45, -30))
|
|
||||||
.coordinate(new Coordinate(-45, -30))
|
|
||||||
.coordinate(new Coordinate(-45, 30)));
|
|
||||||
|
|
||||||
Polygon poly = pb.toPolygonS4J();
|
|
||||||
LineString exterior = poly.getExteriorRing();
|
|
||||||
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
|
||||||
assertEquals(exterior.getCoordinateN(1), new Coordinate(45, 30));
|
|
||||||
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
|
|
||||||
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
|
|
||||||
|
|
||||||
LinearRing polygon = pb.toPolygonGeometry().getPolygon();
|
|
||||||
assertEquals(polygon.getY(0), 30, 0d);
|
|
||||||
assertEquals(polygon.getX(0), -45, 0d);
|
|
||||||
assertEquals(polygon.getY(1), 30, 0d);
|
|
||||||
assertEquals(polygon.getX(1), 45, 0d);
|
|
||||||
assertEquals(polygon.getY(2), -30, 0d);
|
|
||||||
assertEquals(polygon.getX(2), 45, 0d);
|
|
||||||
assertEquals(polygon.getY(3), -30, 0d);
|
|
||||||
assertEquals(polygon.getX(3), -45, 0d);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testNewPolygon_coordinates() {
|
|
||||||
PolygonBuilder pb = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinates(new Coordinate(-45, 30), new Coordinate(45, 30),
|
|
||||||
new Coordinate(45, -30), new Coordinate(-45, -30), new Coordinate(-45, 30))
|
|
||||||
);
|
|
||||||
|
|
||||||
Polygon poly = pb.toPolygonS4J();
|
|
||||||
LineString exterior = poly.getExteriorRing();
|
|
||||||
assertEquals(exterior.getCoordinateN(0), new Coordinate(-45, 30));
|
|
||||||
assertEquals(exterior.getCoordinateN(1), new Coordinate(45, 30));
|
|
||||||
assertEquals(exterior.getCoordinateN(2), new Coordinate(45, -30));
|
|
||||||
assertEquals(exterior.getCoordinateN(3), new Coordinate(-45, -30));
|
|
||||||
|
|
||||||
LinearRing polygon = pb.toPolygonGeometry().getPolygon();
|
|
||||||
assertEquals(polygon.getY(0), 30, 0d);
|
|
||||||
assertEquals(polygon.getX(0), -45, 0d);
|
|
||||||
assertEquals(polygon.getY(1), 30, 0d);
|
|
||||||
assertEquals(polygon.getX(1), 45, 0d);
|
|
||||||
assertEquals(polygon.getY(2), -30, 0d);
|
|
||||||
assertEquals(polygon.getX(2), 45, 0d);
|
|
||||||
assertEquals(polygon.getY(3), -30, 0d);
|
|
||||||
assertEquals(polygon.getX(3), -45, 0d);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testLineStringBuilder() {
|
|
||||||
// Building a simple LineString
|
|
||||||
LineStringBuilder lsb = new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-130.0, 55.0)
|
|
||||||
.coordinate(-130.0, -40.0)
|
|
||||||
.coordinate(-15.0, -40.0)
|
|
||||||
.coordinate(-20.0, 50.0)
|
|
||||||
.coordinate(-45.0, 50.0)
|
|
||||||
.coordinate(-45.0, -15.0)
|
|
||||||
.coordinate(-110.0, -15.0)
|
|
||||||
.coordinate(-110.0, 55.0));
|
|
||||||
|
|
||||||
lsb.buildS4J();
|
|
||||||
buildGeometry(lsb);
|
|
||||||
|
|
||||||
// Building a linestring that needs to be wrapped
|
|
||||||
lsb = new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(100.0, 50.0)
|
|
||||||
.coordinate(110.0, -40.0)
|
|
||||||
.coordinate(240.0, -40.0)
|
|
||||||
.coordinate(230.0, 60.0)
|
|
||||||
.coordinate(200.0, 60.0)
|
|
||||||
.coordinate(200.0, -30.0)
|
|
||||||
.coordinate(130.0, -30.0)
|
|
||||||
.coordinate(130.0, 60.0));
|
|
||||||
|
|
||||||
lsb.buildS4J();
|
|
||||||
buildGeometry(lsb);
|
|
||||||
|
|
||||||
// Building a lineString on the dateline
|
|
||||||
lsb = new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-180.0, 80.0)
|
|
||||||
.coordinate(-180.0, 40.0)
|
|
||||||
.coordinate(-180.0, -40.0)
|
|
||||||
.coordinate(-180.0, -80.0));
|
|
||||||
|
|
||||||
lsb.buildS4J();
|
|
||||||
buildGeometry(lsb);
|
|
||||||
|
|
||||||
// Building a lineString on the dateline
|
|
||||||
lsb = new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(180.0, 80.0)
|
|
||||||
.coordinate(180.0, 40.0)
|
|
||||||
.coordinate(180.0, -40.0)
|
|
||||||
.coordinate(180.0, -80.0));
|
|
||||||
|
|
||||||
lsb.buildS4J();
|
|
||||||
buildGeometry(lsb);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testMultiLineString() {
|
|
||||||
MultiLineStringBuilder mlsb = new MultiLineStringBuilder()
|
|
||||||
.linestring(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-100.0, 50.0)
|
|
||||||
.coordinate(50.0, 50.0)
|
|
||||||
.coordinate(50.0, 20.0)
|
|
||||||
.coordinate(-100.0, 20.0)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.linestring(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-100.0, 20.0)
|
|
||||||
.coordinate(50.0, 20.0)
|
|
||||||
.coordinate(50.0, 0.0)
|
|
||||||
.coordinate(-100.0, 0.0)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
mlsb.buildS4J();
|
|
||||||
buildGeometry(mlsb);
|
|
||||||
|
|
||||||
// LineString that needs to be wrapped
|
|
||||||
new MultiLineStringBuilder()
|
|
||||||
.linestring(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(150.0, 60.0)
|
|
||||||
.coordinate(200.0, 60.0)
|
|
||||||
.coordinate(200.0, 40.0)
|
|
||||||
.coordinate(150.0, 40.0)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.linestring(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(150.0, 20.0)
|
|
||||||
.coordinate(200.0, 20.0)
|
|
||||||
.coordinate(200.0, 0.0)
|
|
||||||
.coordinate(150.0, 0.0)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
mlsb.buildS4J();
|
|
||||||
buildGeometry(mlsb);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPolygonSelfIntersection() {
|
|
||||||
PolygonBuilder newPolygon = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-40.0, 50.0)
|
|
||||||
.coordinate(40.0, 50.0)
|
|
||||||
.coordinate(-40.0, -50.0)
|
|
||||||
.coordinate(40.0, -50.0).close());
|
|
||||||
Exception e = expectThrows(InvalidShapeException.class, () -> newPolygon.buildS4J());
|
|
||||||
assertThat(e.getMessage(), containsString("Cannot determine orientation: signed area equal to 0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** note: only supported by S4J at the moment */
|
|
||||||
public void testGeoCircle() {
|
|
||||||
double earthCircumference = 40075016.69;
|
|
||||||
Circle circle = new CircleBuilder().center(0, 0).radius("100m").buildS4J();
|
|
||||||
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
|
|
||||||
assertEquals(new PointImpl(0, 0, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
|
||||||
circle = new CircleBuilder().center(+180, 0).radius("100m").buildS4J();
|
|
||||||
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
|
|
||||||
assertEquals(new PointImpl(180, 0, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
|
||||||
circle = new CircleBuilder().center(-180, 0).radius("100m").buildS4J();
|
|
||||||
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
|
|
||||||
assertEquals(new PointImpl(-180, 0, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
|
||||||
circle = new CircleBuilder().center(0, 90).radius("100m").buildS4J();
|
|
||||||
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
|
|
||||||
assertEquals(new PointImpl(0, 90, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
|
||||||
circle = new CircleBuilder().center(0, -90).radius("100m").buildS4J();
|
|
||||||
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
|
|
||||||
assertEquals(new PointImpl(0, -90, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
|
||||||
double randomLat = (randomDouble() * 180) - 90;
|
|
||||||
double randomLon = (randomDouble() * 360) - 180;
|
|
||||||
double randomRadius = randomIntBetween(1, (int) earthCircumference / 4);
|
|
||||||
circle = new CircleBuilder().center(randomLon, randomLat).radius(randomRadius + "m").buildS4J();
|
|
||||||
assertEquals((360 * randomRadius) / earthCircumference, circle.getRadius(), 0.00000001);
|
|
||||||
assertEquals(new PointImpl(randomLon, randomLat, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPolygonWrapping() {
|
|
||||||
PolygonBuilder pb = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-150.0, 65.0)
|
|
||||||
.coordinate(-250.0, 65.0)
|
|
||||||
.coordinate(-250.0, -65.0)
|
|
||||||
.coordinate(-150.0, -65.0)
|
|
||||||
.close());
|
|
||||||
|
|
||||||
assertMultiPolygon(pb.buildS4J(), true);
|
|
||||||
assertMultiPolygon(buildGeometry(pb), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testLineStringWrapping() {
|
|
||||||
LineStringBuilder lsb = new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-150.0, 65.0)
|
|
||||||
.coordinate(-250.0, 65.0)
|
|
||||||
.coordinate(-250.0, -65.0)
|
|
||||||
.coordinate(-150.0, -65.0)
|
|
||||||
.close());
|
|
||||||
|
|
||||||
assertMultiLineString(lsb.buildS4J(), true);
|
|
||||||
assertMultiLineString(buildGeometry(lsb), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDatelineOGC() {
|
|
||||||
// tests that the following shape (defined in counterclockwise OGC order)
|
|
||||||
// https://gist.github.com/anonymous/7f1bb6d7e9cd72f5977c crosses the dateline
|
|
||||||
// expected results: 3 polygons, 1 with a hole
|
|
||||||
|
|
||||||
// a giant c shape
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(174,0)
|
|
||||||
.coordinate(-176,0)
|
|
||||||
.coordinate(-176,3)
|
|
||||||
.coordinate(177,3)
|
|
||||||
.coordinate(177,5)
|
|
||||||
.coordinate(-176,5)
|
|
||||||
.coordinate(-176,8)
|
|
||||||
.coordinate(174,8)
|
|
||||||
.coordinate(174,0)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 3/4 of an embedded 'c', crossing dateline once
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(175, 1)
|
|
||||||
.coordinate(175, 7)
|
|
||||||
.coordinate(-178, 7)
|
|
||||||
.coordinate(-178, 6)
|
|
||||||
.coordinate(176, 6)
|
|
||||||
.coordinate(176, 2)
|
|
||||||
.coordinate(179, 2)
|
|
||||||
.coordinate(179,1)
|
|
||||||
.coordinate(175, 1)
|
|
||||||
));
|
|
||||||
|
|
||||||
// embedded hole right of the dateline
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-179, 1)
|
|
||||||
.coordinate(-179, 2)
|
|
||||||
.coordinate(-177, 2)
|
|
||||||
.coordinate(-177,1)
|
|
||||||
.coordinate(-179,1)
|
|
||||||
));
|
|
||||||
|
|
||||||
assertMultiPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertMultiPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testDateline() {
|
|
||||||
// tests that the following shape (defined in clockwise non-OGC order)
|
|
||||||
// https://gist.github.com/anonymous/7f1bb6d7e9cd72f5977c crosses the dateline
|
|
||||||
// expected results: 3 polygons, 1 with a hole
|
|
||||||
|
|
||||||
// a giant c shape
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-186,0)
|
|
||||||
.coordinate(-176,0)
|
|
||||||
.coordinate(-176,3)
|
|
||||||
.coordinate(-183,3)
|
|
||||||
.coordinate(-183,5)
|
|
||||||
.coordinate(-176,5)
|
|
||||||
.coordinate(-176,8)
|
|
||||||
.coordinate(-186,8)
|
|
||||||
.coordinate(-186,0)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 3/4 of an embedded 'c', crossing dateline once
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-185,1)
|
|
||||||
.coordinate(-181,1)
|
|
||||||
.coordinate(-181,2)
|
|
||||||
.coordinate(-184,2)
|
|
||||||
.coordinate(-184,6)
|
|
||||||
.coordinate(-178,6)
|
|
||||||
.coordinate(-178,7)
|
|
||||||
.coordinate(-185,7)
|
|
||||||
.coordinate(-185,1)
|
|
||||||
));
|
|
||||||
|
|
||||||
// embedded hole right of the dateline
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-179,1)
|
|
||||||
.coordinate(-177,1)
|
|
||||||
.coordinate(-177,2)
|
|
||||||
.coordinate(-179,2)
|
|
||||||
.coordinate(-179,1)
|
|
||||||
));
|
|
||||||
|
|
||||||
assertMultiPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertMultiPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testComplexShapeWithHole() {
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-85.0018514,37.1311314)
|
|
||||||
.coordinate(-85.0016645,37.1315293)
|
|
||||||
.coordinate(-85.0016246,37.1317069)
|
|
||||||
.coordinate(-85.0016526,37.1318183)
|
|
||||||
.coordinate(-85.0017119,37.1319196)
|
|
||||||
.coordinate(-85.0019371,37.1321182)
|
|
||||||
.coordinate(-85.0019972,37.1322115)
|
|
||||||
.coordinate(-85.0019942,37.1323234)
|
|
||||||
.coordinate(-85.0019543,37.1324336)
|
|
||||||
.coordinate(-85.001906,37.1324985)
|
|
||||||
.coordinate(-85.001834,37.1325497)
|
|
||||||
.coordinate(-85.0016965,37.1325907)
|
|
||||||
.coordinate(-85.0016011,37.1325873)
|
|
||||||
.coordinate(-85.0014816,37.1325353)
|
|
||||||
.coordinate(-85.0011755,37.1323509)
|
|
||||||
.coordinate(-85.000955,37.1322802)
|
|
||||||
.coordinate(-85.0006241,37.1322529)
|
|
||||||
.coordinate(-85.0000002,37.1322307)
|
|
||||||
.coordinate(-84.9994,37.1323001)
|
|
||||||
.coordinate(-84.999109,37.1322864)
|
|
||||||
.coordinate(-84.998934,37.1322415)
|
|
||||||
.coordinate(-84.9988639,37.1321888)
|
|
||||||
.coordinate(-84.9987841,37.1320944)
|
|
||||||
.coordinate(-84.9987208,37.131954)
|
|
||||||
.coordinate(-84.998736,37.1316611)
|
|
||||||
.coordinate(-84.9988091,37.131334)
|
|
||||||
.coordinate(-84.9989283,37.1311337)
|
|
||||||
.coordinate(-84.9991943,37.1309198)
|
|
||||||
.coordinate(-84.9993573,37.1308459)
|
|
||||||
.coordinate(-84.9995888,37.1307924)
|
|
||||||
.coordinate(-84.9998746,37.130806)
|
|
||||||
.coordinate(-85.0000002,37.1308358)
|
|
||||||
.coordinate(-85.0004984,37.1310658)
|
|
||||||
.coordinate(-85.0008008,37.1311625)
|
|
||||||
.coordinate(-85.0009461,37.1311684)
|
|
||||||
.coordinate(-85.0011373,37.1311515)
|
|
||||||
.coordinate(-85.0016455,37.1310491)
|
|
||||||
.coordinate(-85.0018514,37.1311314)
|
|
||||||
);
|
|
||||||
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-85.0000002,37.1317672)
|
|
||||||
.coordinate(-85.0001983,37.1317538)
|
|
||||||
.coordinate(-85.0003378,37.1317582)
|
|
||||||
.coordinate(-85.0004697,37.131792)
|
|
||||||
.coordinate(-85.0008048,37.1319439)
|
|
||||||
.coordinate(-85.0009342,37.1319838)
|
|
||||||
.coordinate(-85.0010184,37.1319463)
|
|
||||||
.coordinate(-85.0010618,37.13184)
|
|
||||||
.coordinate(-85.0010057,37.1315102)
|
|
||||||
.coordinate(-85.000977,37.1314403)
|
|
||||||
.coordinate(-85.0009182,37.1313793)
|
|
||||||
.coordinate(-85.0005366,37.1312209)
|
|
||||||
.coordinate(-85.000224,37.1311466)
|
|
||||||
.coordinate(-85.000087,37.1311356)
|
|
||||||
.coordinate(-85.0000002,37.1311433)
|
|
||||||
.coordinate(-84.9995021,37.1312336)
|
|
||||||
.coordinate(-84.9993308,37.1312859)
|
|
||||||
.coordinate(-84.9992567,37.1313252)
|
|
||||||
.coordinate(-84.9991868,37.1314277)
|
|
||||||
.coordinate(-84.9991593,37.1315381)
|
|
||||||
.coordinate(-84.9991841,37.1316527)
|
|
||||||
.coordinate(-84.9992329,37.1317117)
|
|
||||||
.coordinate(-84.9993527,37.1317788)
|
|
||||||
.coordinate(-84.9994931,37.1318061)
|
|
||||||
.coordinate(-84.9996815,37.1317979)
|
|
||||||
.coordinate(-85.0000002,37.1317672)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assertPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testShapeWithHoleAtEdgeEndPoints() {
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-4, 2)
|
|
||||||
.coordinate(4, 2)
|
|
||||||
.coordinate(6, 0)
|
|
||||||
.coordinate(4, -2)
|
|
||||||
.coordinate(-4, -2)
|
|
||||||
.coordinate(-6, 0)
|
|
||||||
.coordinate(-4, 2)
|
|
||||||
);
|
|
||||||
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(4, 1)
|
|
||||||
.coordinate(4, -1)
|
|
||||||
.coordinate(-4, -1)
|
|
||||||
.coordinate(-4, 1)
|
|
||||||
.coordinate(4, 1)
|
|
||||||
));
|
|
||||||
assertPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testShapeWithPointOnDateline() {
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(180, 0)
|
|
||||||
.coordinate(176, 4)
|
|
||||||
.coordinate(176, -4)
|
|
||||||
.coordinate(180, 0)
|
|
||||||
);
|
|
||||||
assertPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testShapeWithEdgeAlongDateline() {
|
|
||||||
// test case 1: test the positive side of the dateline
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(180, 0)
|
|
||||||
.coordinate(176, 4)
|
|
||||||
.coordinate(180, -4)
|
|
||||||
.coordinate(180, 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
assertPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertPolygon(buildGeometry(builder.close()), false);
|
|
||||||
|
|
||||||
// test case 2: test the negative side of the dateline
|
|
||||||
builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-176, 4)
|
|
||||||
.coordinate(-180, 0)
|
|
||||||
.coordinate(-180, -4)
|
|
||||||
.coordinate(-176, 4)
|
|
||||||
);
|
|
||||||
|
|
||||||
assertPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testShapeWithBoundaryHoles() {
|
|
||||||
// test case 1: test the positive side of the dateline
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
.coordinate(176, 15)
|
|
||||||
.coordinate(172, 0)
|
|
||||||
.coordinate(176, -15)
|
|
||||||
.coordinate(-177, -10)
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
);
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(176, 10)
|
|
||||||
.coordinate(180, 5)
|
|
||||||
.coordinate(180, -5)
|
|
||||||
.coordinate(176, -10)
|
|
||||||
.coordinate(176, 10)
|
|
||||||
));
|
|
||||||
|
|
||||||
assertMultiPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertMultiPolygon(buildGeometry(builder.close()), false);
|
|
||||||
|
|
||||||
// test case 2: test the negative side of the dateline
|
|
||||||
builder = new PolygonBuilder(
|
|
||||||
new CoordinatesBuilder()
|
|
||||||
.coordinate(-176, 15)
|
|
||||||
.coordinate(179, 10)
|
|
||||||
.coordinate(179, -10)
|
|
||||||
.coordinate(-176, -15)
|
|
||||||
.coordinate(-172, 0)
|
|
||||||
.close()
|
|
||||||
);
|
|
||||||
builder.hole(new LineStringBuilder(
|
|
||||||
new CoordinatesBuilder()
|
|
||||||
.coordinate(-176, 10)
|
|
||||||
.coordinate(-176, -10)
|
|
||||||
.coordinate(-180, -5)
|
|
||||||
.coordinate(-180, 5)
|
|
||||||
.coordinate(-176, 10)
|
|
||||||
.close()
|
|
||||||
));
|
|
||||||
|
|
||||||
assertMultiPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertMultiPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testShapeWithHoleTouchingAtDateline() throws Exception {
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-180, 90)
|
|
||||||
.coordinate(-180, -90)
|
|
||||||
.coordinate(180, -90)
|
|
||||||
.coordinate(180, 90)
|
|
||||||
.coordinate(-180, 90)
|
|
||||||
);
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(180.0, -16.14)
|
|
||||||
.coordinate(178.53, -16.64)
|
|
||||||
.coordinate(178.49, -16.82)
|
|
||||||
.coordinate(178.73, -17.02)
|
|
||||||
.coordinate(178.86, -16.86)
|
|
||||||
.coordinate(180.0, -16.14)
|
|
||||||
));
|
|
||||||
|
|
||||||
assertPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testShapeWithTangentialHole() {
|
|
||||||
// test a shape with one tangential (shared) vertex (should pass)
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(179, 10)
|
|
||||||
.coordinate(168, 15)
|
|
||||||
.coordinate(164, 0)
|
|
||||||
.coordinate(166, -15)
|
|
||||||
.coordinate(179, -10)
|
|
||||||
.coordinate(179, 10)
|
|
||||||
);
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
.coordinate(-178, -10)
|
|
||||||
.coordinate(-180, -5)
|
|
||||||
.coordinate(-180, 5)
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
));
|
|
||||||
|
|
||||||
assertMultiPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertMultiPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testShapeWithInvalidTangentialHole() {
|
|
||||||
// test a shape with one invalid tangential (shared) vertex (should throw exception)
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(179, 10)
|
|
||||||
.coordinate(168, 15)
|
|
||||||
.coordinate(164, 0)
|
|
||||||
.coordinate(166, -15)
|
|
||||||
.coordinate(179, -10)
|
|
||||||
.coordinate(179, 10)
|
|
||||||
);
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(164, 0)
|
|
||||||
.coordinate(175, 10)
|
|
||||||
.coordinate(175, 5)
|
|
||||||
.coordinate(179, -10)
|
|
||||||
.coordinate(164, 0)
|
|
||||||
));
|
|
||||||
Exception e;
|
|
||||||
|
|
||||||
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildS4J());
|
|
||||||
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
|
|
||||||
e = expectThrows(IllegalArgumentException.class, () -> buildGeometry(builder.close()));
|
|
||||||
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testBoundaryShapeWithTangentialHole() {
|
|
||||||
// test a shape with one tangential (shared) vertex for each hole (should pass)
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
.coordinate(176, 15)
|
|
||||||
.coordinate(172, 0)
|
|
||||||
.coordinate(176, -15)
|
|
||||||
.coordinate(-177, -10)
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
);
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
.coordinate(-178, -10)
|
|
||||||
.coordinate(-180, -5)
|
|
||||||
.coordinate(-180, 5)
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
));
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(172, 0)
|
|
||||||
.coordinate(176, 10)
|
|
||||||
.coordinate(176, -5)
|
|
||||||
.coordinate(172, 0)
|
|
||||||
));
|
|
||||||
assertMultiPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertMultiPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testBoundaryShapeWithInvalidTangentialHole() {
|
|
||||||
// test shape with two tangential (shared) vertices (should throw exception)
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
.coordinate(176, 15)
|
|
||||||
.coordinate(172, 0)
|
|
||||||
.coordinate(176, -15)
|
|
||||||
.coordinate(-177, -10)
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
);
|
|
||||||
builder.hole(new LineStringBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
.coordinate(172, 0)
|
|
||||||
.coordinate(180, -5)
|
|
||||||
.coordinate(176, -10)
|
|
||||||
.coordinate(-177, 10)
|
|
||||||
));
|
|
||||||
Exception e;
|
|
||||||
e = expectThrows(InvalidShapeException.class, () -> builder.close().buildS4J());
|
|
||||||
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
|
|
||||||
e = expectThrows(IllegalArgumentException.class, () -> buildGeometry(builder.close()));
|
|
||||||
assertThat(e.getMessage(), containsString("interior cannot share more than one point with the exterior"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test an enveloping polygon around the max mercator bounds
|
|
||||||
*/
|
|
||||||
public void testBoundaryShape() {
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(-180, 90)
|
|
||||||
.coordinate(180, 90)
|
|
||||||
.coordinate(180, -90)
|
|
||||||
.coordinate(-180, 90)
|
|
||||||
);
|
|
||||||
|
|
||||||
assertPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testShapeWithAlternateOrientation() {
|
|
||||||
// cw: should produce a multi polygon spanning hemispheres
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(180, 0)
|
|
||||||
.coordinate(176, 4)
|
|
||||||
.coordinate(-176, 4)
|
|
||||||
.coordinate(180, 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
assertPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertPolygon(buildGeometry(builder.close()), false);
|
|
||||||
|
|
||||||
// cw: geo core will convert to ccw across the dateline
|
|
||||||
builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(180, 0)
|
|
||||||
.coordinate(-176, 4)
|
|
||||||
.coordinate(176, 4)
|
|
||||||
.coordinate(180, 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
assertMultiPolygon(builder.close().buildS4J(), true);
|
|
||||||
assertMultiPolygon(buildGeometry(builder.close()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testShapeWithConsecutiveDuplicatePoints() {
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(180, 0)
|
|
||||||
.coordinate(176, 4)
|
|
||||||
.coordinate(176, 4)
|
|
||||||
.coordinate(-176, 4)
|
|
||||||
.coordinate(180, 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
// duplicated points are removed
|
|
||||||
PolygonBuilder expected = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(180, 0)
|
|
||||||
.coordinate(176, 4)
|
|
||||||
.coordinate(-176, 4)
|
|
||||||
.coordinate(180, 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEquals(buildGeometry(expected.close()), buildGeometry(builder.close()));
|
|
||||||
assertEquals(expected.close().buildS4J(), builder.close().buildS4J());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testShapeWithCoplanarVerticalPoints() throws Exception {
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(180, -36)
|
|
||||||
.coordinate(180, 90)
|
|
||||||
.coordinate(-180, 90)
|
|
||||||
.coordinate(-180, 79)
|
|
||||||
.coordinate(16, 58)
|
|
||||||
.coordinate(8, 13)
|
|
||||||
.coordinate(-180, 74)
|
|
||||||
.coordinate(-180, -85)
|
|
||||||
.coordinate(-180, -90)
|
|
||||||
.coordinate(180, -90)
|
|
||||||
.coordinate(180, -85)
|
|
||||||
.coordinate(26, 6)
|
|
||||||
.coordinate(33, 62)
|
|
||||||
.coordinate(180, -36)
|
|
||||||
);
|
|
||||||
|
|
||||||
//coplanar points on vertical edge are removed.
|
|
||||||
PolygonBuilder expected = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(180, -36)
|
|
||||||
.coordinate(180, 90)
|
|
||||||
.coordinate(-180, 90)
|
|
||||||
.coordinate(-180, 79)
|
|
||||||
.coordinate(16, 58)
|
|
||||||
.coordinate(8, 13)
|
|
||||||
.coordinate(-180, 74)
|
|
||||||
.coordinate(-180, -90)
|
|
||||||
.coordinate(180, -90)
|
|
||||||
.coordinate(180, -85)
|
|
||||||
.coordinate(26, 6)
|
|
||||||
.coordinate(33, 62)
|
|
||||||
.coordinate(180, -36)
|
|
||||||
);
|
|
||||||
|
|
||||||
assertEquals(buildGeometry(expected.close()), buildGeometry(builder.close()));
|
|
||||||
assertEquals(expected.close().buildS4J(), builder.close().buildS4J());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPolygon3D() {
|
|
||||||
String expected = "{\n" +
|
|
||||||
" \"type\" : \"polygon\",\n" +
|
|
||||||
" \"orientation\" : \"right\",\n" +
|
|
||||||
" \"coordinates\" : [\n" +
|
|
||||||
" [\n" +
|
|
||||||
" [\n" +
|
|
||||||
" -45.0,\n" +
|
|
||||||
" 30.0,\n" +
|
|
||||||
" 100.0\n" +
|
|
||||||
" ],\n" +
|
|
||||||
" [\n" +
|
|
||||||
" 45.0,\n" +
|
|
||||||
" 30.0,\n" +
|
|
||||||
" 75.0\n" +
|
|
||||||
" ],\n" +
|
|
||||||
" [\n" +
|
|
||||||
" 45.0,\n" +
|
|
||||||
" -30.0,\n" +
|
|
||||||
" 77.0\n" +
|
|
||||||
" ],\n" +
|
|
||||||
" [\n" +
|
|
||||||
" -45.0,\n" +
|
|
||||||
" -30.0,\n" +
|
|
||||||
" 101.0\n" +
|
|
||||||
" ],\n" +
|
|
||||||
" [\n" +
|
|
||||||
" -45.0,\n" +
|
|
||||||
" 30.0,\n" +
|
|
||||||
" 110.0\n" +
|
|
||||||
" ]\n" +
|
|
||||||
" ]\n" +
|
|
||||||
" ]\n" +
|
|
||||||
"}";
|
|
||||||
|
|
||||||
PolygonBuilder pb = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(new Coordinate(-45, 30, 100))
|
|
||||||
.coordinate(new Coordinate(45, 30, 75))
|
|
||||||
.coordinate(new Coordinate(45, -30, 77))
|
|
||||||
.coordinate(new Coordinate(-45, -30, 101))
|
|
||||||
.coordinate(new Coordinate(-45, 30, 110)));
|
|
||||||
|
|
||||||
assertEquals(expected, pb.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testInvalidSelfCrossingPolygon() {
|
|
||||||
PolygonBuilder builder = new PolygonBuilder(new CoordinatesBuilder()
|
|
||||||
.coordinate(0, 0)
|
|
||||||
.coordinate(0, 2)
|
|
||||||
.coordinate(1, 1.9)
|
|
||||||
.coordinate(0.5, 1.8)
|
|
||||||
.coordinate(1.5, 1.8)
|
|
||||||
.coordinate(1, 1.9)
|
|
||||||
.coordinate(2, 2)
|
|
||||||
.coordinate(2, 0)
|
|
||||||
.coordinate(0, 0)
|
|
||||||
);
|
|
||||||
Exception e = expectThrows(InvalidShapeException.class, () -> builder.close().buildS4J());
|
|
||||||
assertThat(e.getMessage(), containsString("Self-intersection at or near point ["));
|
|
||||||
assertThat(e.getMessage(), not(containsString("NaN")));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object buildGeometry(ShapeBuilder<?, ?, ?> builder) {
|
|
||||||
return new GeoShapeIndexer(true, "name").prepareForIndexing(builder.buildGeometry());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.elasticsearch.common.geo.builders;
|
|
||||||
|
|
||||||
import org.elasticsearch.test.geo.RandomShapeGenerator;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class GeometryCollectionBuilderTests extends AbstractShapeBuilderTestCase<GeometryCollectionBuilder> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GeometryCollectionBuilder createTestShapeBuilder() {
|
|
||||||
GeometryCollectionBuilder geometryCollection = new GeometryCollectionBuilder();
|
|
||||||
int shapes = randomIntBetween(0, 8);
|
|
||||||
for (int i = 0; i < shapes; i++) {
|
|
||||||
switch (randomIntBetween(0, 7)) {
|
|
||||||
case 0:
|
|
||||||
geometryCollection.shape(PointBuilderTests.createRandomShape());
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
geometryCollection.shape(CircleBuilderTests.createRandomShape());
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
geometryCollection.shape(EnvelopeBuilderTests.createRandomShape());
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
geometryCollection.shape(LineStringBuilderTests.createRandomShape());
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
geometryCollection.shape(MultiLineStringBuilderTests.createRandomShape());
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
geometryCollection.shape(MultiPolygonBuilderTests.createRandomShape());
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
geometryCollection.shape(MultiPointBuilderTests.createRandomShape());
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
geometryCollection.shape(PolygonBuilderTests.createRandomShape());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return geometryCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GeometryCollectionBuilder createMutation(GeometryCollectionBuilder original) throws IOException {
|
|
||||||
return mutate(original);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GeometryCollectionBuilder mutate(GeometryCollectionBuilder original) throws IOException {
|
|
||||||
GeometryCollectionBuilder mutation = copyShape(original);
|
|
||||||
if (mutation.shapes.size() > 0) {
|
|
||||||
int shapePosition = randomIntBetween(0, mutation.shapes.size() - 1);
|
|
||||||
ShapeBuilder<?, ?, ?> shapeToChange = mutation.shapes.get(shapePosition);
|
|
||||||
switch (shapeToChange.type()) {
|
|
||||||
case POINT:
|
|
||||||
shapeToChange = PointBuilderTests.mutate((PointBuilder) shapeToChange);
|
|
||||||
break;
|
|
||||||
case CIRCLE:
|
|
||||||
shapeToChange = CircleBuilderTests.mutate((CircleBuilder) shapeToChange);
|
|
||||||
break;
|
|
||||||
case ENVELOPE:
|
|
||||||
shapeToChange = EnvelopeBuilderTests.mutate((EnvelopeBuilder) shapeToChange);
|
|
||||||
break;
|
|
||||||
case LINESTRING:
|
|
||||||
shapeToChange = LineStringBuilderTests.mutate((LineStringBuilder) shapeToChange);
|
|
||||||
break;
|
|
||||||
case MULTILINESTRING:
|
|
||||||
shapeToChange = MultiLineStringBuilderTests.mutate((MultiLineStringBuilder) shapeToChange);
|
|
||||||
break;
|
|
||||||
case MULTIPOLYGON:
|
|
||||||
shapeToChange = MultiPolygonBuilderTests.mutate((MultiPolygonBuilder) shapeToChange);
|
|
||||||
break;
|
|
||||||
case MULTIPOINT:
|
|
||||||
shapeToChange = MultiPointBuilderTests.mutate((MultiPointBuilder) shapeToChange);
|
|
||||||
break;
|
|
||||||
case POLYGON:
|
|
||||||
shapeToChange = PolygonBuilderTests.mutate((PolygonBuilder) shapeToChange);
|
|
||||||
break;
|
|
||||||
case GEOMETRYCOLLECTION:
|
|
||||||
throw new UnsupportedOperationException("GeometryCollection should not be nested inside each other");
|
|
||||||
}
|
|
||||||
mutation.shapes.set(shapePosition, shapeToChange);
|
|
||||||
} else {
|
|
||||||
mutation.shape(RandomShapeGenerator.createShape(random()));
|
|
||||||
}
|
|
||||||
return mutation;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License
|
|
||||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
|
||||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
|
||||||
* Side Public License, v 1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.elasticsearch.index.query;
|
|
||||||
|
|
||||||
import org.elasticsearch.Version;
|
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
|
||||||
import org.elasticsearch.common.geo.ShapeRelation;
|
|
||||||
import org.elasticsearch.common.geo.SpatialStrategy;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.geo.GeometryTestUtils;
|
|
||||||
import org.elasticsearch.geometry.Geometry;
|
|
||||||
import org.elasticsearch.geometry.ShapeType;
|
|
||||||
import org.elasticsearch.plugins.Plugin;
|
|
||||||
import org.elasticsearch.test.TestLegacyGeoShapeFieldMapperPlugin;
|
|
||||||
import org.elasticsearch.test.VersionUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
public class LegacyGeoShapeFieldQueryTests extends GeoShapeQueryBuilderTests {
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Override
|
|
||||||
protected Collection<Class<? extends Plugin>> getPlugins() {
|
|
||||||
return Collections.singletonList(TestLegacyGeoShapeFieldMapperPlugin.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String fieldName() {
|
|
||||||
return GEO_SHAPE_FIELD_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings createTestIndexSettings() {
|
|
||||||
// force the legacy shape impl
|
|
||||||
Version version = VersionUtils.randomVersionBetween(random(), Version.V_6_0_0, Version.V_6_5_0);
|
|
||||||
return Settings.builder()
|
|
||||||
.put(super.createTestIndexSettings())
|
|
||||||
.put(IndexMetadata.SETTING_VERSION_CREATED, version)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GeoShapeQueryBuilder doCreateTestQueryBuilder(boolean indexedShape) {
|
|
||||||
Geometry geometry = GeometryTestUtils.randomGeometry(false);
|
|
||||||
GeoShapeQueryBuilder builder;
|
|
||||||
clearShapeFields();
|
|
||||||
if (indexedShape == false) {
|
|
||||||
builder = new GeoShapeQueryBuilder(fieldName(), geometry);
|
|
||||||
} else {
|
|
||||||
indexedShapeToReturn = geometry;
|
|
||||||
indexedShapeId = randomAlphaOfLengthBetween(3, 20);
|
|
||||||
builder = new GeoShapeQueryBuilder(fieldName(), indexedShapeId);
|
|
||||||
if (randomBoolean()) {
|
|
||||||
indexedShapeIndex = randomAlphaOfLengthBetween(3, 20);
|
|
||||||
builder.indexedShapeIndex(indexedShapeIndex);
|
|
||||||
}
|
|
||||||
if (randomBoolean()) {
|
|
||||||
indexedShapePath = randomAlphaOfLengthBetween(3, 20);
|
|
||||||
builder.indexedShapePath(indexedShapePath);
|
|
||||||
}
|
|
||||||
if (randomBoolean()) {
|
|
||||||
indexedShapeRouting = randomAlphaOfLengthBetween(3, 20);
|
|
||||||
builder.indexedShapeRouting(indexedShapeRouting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (randomBoolean()) {
|
|
||||||
SpatialStrategy strategy = randomFrom(SpatialStrategy.values());
|
|
||||||
// ShapeType.MULTILINESTRING + SpatialStrategy.TERM can lead to large queries and will slow down tests, so
|
|
||||||
// we try to avoid that combination
|
|
||||||
while (geometry.type() == ShapeType.MULTILINESTRING && strategy == SpatialStrategy.TERM) {
|
|
||||||
strategy = randomFrom(SpatialStrategy.values());
|
|
||||||
}
|
|
||||||
builder.strategy(strategy);
|
|
||||||
if (strategy != SpatialStrategy.TERM) {
|
|
||||||
builder.relation(randomFrom(ShapeRelation.values()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (randomBoolean()) {
|
|
||||||
builder.ignoreUnmapped(randomBoolean());
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testInvalidRelation() throws IOException {
|
|
||||||
Geometry shape = GeometryTestUtils.randomGeometry(false);
|
|
||||||
GeoShapeQueryBuilder builder = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, shape);
|
|
||||||
builder.strategy(SpatialStrategy.TERM);
|
|
||||||
expectThrows(IllegalArgumentException.class, () -> builder.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.WITHIN)));
|
|
||||||
GeoShapeQueryBuilder builder2 = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, shape);
|
|
||||||
builder2.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.WITHIN));
|
|
||||||
expectThrows(IllegalArgumentException.class, () -> builder2.strategy(SpatialStrategy.TERM));
|
|
||||||
GeoShapeQueryBuilder builder3 = new GeoShapeQueryBuilder(GEO_SHAPE_FIELD_NAME, shape);
|
|
||||||
builder3.strategy(SpatialStrategy.TERM);
|
|
||||||
expectThrows(IllegalArgumentException.class, () -> builder3.relation(randomFrom(ShapeRelation.DISJOINT, ShapeRelation.WITHIN)));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,9 +8,6 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.search.geo;
|
package org.elasticsearch.index.search.geo;
|
||||||
|
|
||||||
import org.apache.lucene.spatial.prefix.tree.Cell;
|
|
||||||
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
|
|
||||||
import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
|
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.geo.GeoPoint;
|
import org.elasticsearch.common.geo.GeoPoint;
|
||||||
import org.elasticsearch.common.geo.GeoUtils;
|
import org.elasticsearch.common.geo.GeoUtils;
|
||||||
|
@ -19,8 +16,6 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser.Token;
|
import org.elasticsearch.common.xcontent.XContentParser.Token;
|
||||||
import org.elasticsearch.geometry.utils.Geohash;
|
import org.elasticsearch.geometry.utils.Geohash;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.locationtech.spatial4j.context.SpatialContext;
|
|
||||||
import org.locationtech.spatial4j.distance.DistanceUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -617,56 +612,7 @@ public class GeoUtilsTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPrefixTreeCellSizes() {
|
|
||||||
assertThat(GeoUtils.EARTH_SEMI_MAJOR_AXIS, equalTo(DistanceUtils.EARTH_EQUATORIAL_RADIUS_KM * 1000));
|
|
||||||
assertThat(GeoUtils.quadTreeCellWidth(0), lessThanOrEqualTo(GeoUtils.EARTH_EQUATOR));
|
|
||||||
|
|
||||||
SpatialContext spatialContext = new SpatialContext(true);
|
|
||||||
|
|
||||||
GeohashPrefixTree geohashPrefixTree = new GeohashPrefixTree(spatialContext, GeohashPrefixTree.getMaxLevelsPossible() / 2);
|
|
||||||
Cell gNode = geohashPrefixTree.getWorldCell();
|
|
||||||
|
|
||||||
for (int i = 0; i < geohashPrefixTree.getMaxLevels(); i++) {
|
|
||||||
double width = GeoUtils.geoHashCellWidth(i);
|
|
||||||
double height = GeoUtils.geoHashCellHeight(i);
|
|
||||||
double size = GeoUtils.geoHashCellSize(i);
|
|
||||||
double degrees = 360.0 * width / GeoUtils.EARTH_EQUATOR;
|
|
||||||
int level = GeoUtils.quadTreeLevelsForPrecision(size);
|
|
||||||
|
|
||||||
assertThat(GeoUtils.quadTreeCellWidth(level), lessThanOrEqualTo(width));
|
|
||||||
assertThat(GeoUtils.quadTreeCellHeight(level), lessThanOrEqualTo(height));
|
|
||||||
assertThat(GeoUtils.geoHashLevelsForPrecision(size), equalTo(geohashPrefixTree.getLevelForDistance(degrees)));
|
|
||||||
|
|
||||||
assertThat("width at level " + i,
|
|
||||||
gNode.getShape().getBoundingBox().getWidth(), equalTo(360.d * width / GeoUtils.EARTH_EQUATOR));
|
|
||||||
assertThat("height at level " + i, gNode.getShape().getBoundingBox().getHeight(), equalTo(180.d * height
|
|
||||||
/ GeoUtils.EARTH_POLAR_DISTANCE));
|
|
||||||
|
|
||||||
gNode = gNode.getNextLevelCells(null).next();
|
|
||||||
}
|
|
||||||
|
|
||||||
QuadPrefixTree quadPrefixTree = new QuadPrefixTree(spatialContext);
|
|
||||||
Cell qNode = quadPrefixTree.getWorldCell();
|
|
||||||
for (int i = 0; i < quadPrefixTree.getMaxLevels(); i++) {
|
|
||||||
|
|
||||||
double degrees = 360.0 / (1L << i);
|
|
||||||
double width = GeoUtils.quadTreeCellWidth(i);
|
|
||||||
double height = GeoUtils.quadTreeCellHeight(i);
|
|
||||||
double size = GeoUtils.quadTreeCellSize(i);
|
|
||||||
int level = GeoUtils.quadTreeLevelsForPrecision(size);
|
|
||||||
|
|
||||||
assertThat(GeoUtils.quadTreeCellWidth(level), lessThanOrEqualTo(width));
|
|
||||||
assertThat(GeoUtils.quadTreeCellHeight(level), lessThanOrEqualTo(height));
|
|
||||||
assertThat(GeoUtils.quadTreeLevelsForPrecision(size), equalTo(quadPrefixTree.getLevelForDistance(degrees)));
|
|
||||||
|
|
||||||
assertThat("width at level " + i,
|
|
||||||
qNode.getShape().getBoundingBox().getWidth(), equalTo(360.d * width / GeoUtils.EARTH_EQUATOR));
|
|
||||||
assertThat("height at level " + i, qNode.getShape().getBoundingBox().getHeight(), equalTo(180.d * height
|
|
||||||
/ GeoUtils.EARTH_POLAR_DISTANCE));
|
|
||||||
|
|
||||||
qNode = qNode.getNextLevelCells(null).next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testParseGeoPointGeohashPositions() throws IOException {
|
public void testParseGeoPointGeohashPositions() throws IOException {
|
||||||
assertNormalizedPoint(parseGeohash("drt5",
|
assertNormalizedPoint(parseGeohash("drt5",
|
||||||
|
|
|
@ -14,8 +14,7 @@ import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Random geo generation utilities for randomized {@code geo_point} type testing
|
* Random geo generation utilities for randomized {@code geo_point} type testing
|
||||||
* does not depend on jts or spatial4j. Use {@link org.elasticsearch.test.geo.RandomShapeGenerator}
|
* does not depend on jts or spatial4j.
|
||||||
* to create random OGC compliant shapes.
|
|
||||||
*/
|
*/
|
||||||
public class RandomGeoGenerator {
|
public class RandomGeoGenerator {
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import org.elasticsearch.core.TimeValue;
|
||||||
import org.elasticsearch.core.Tuple;
|
import org.elasticsearch.core.Tuple;
|
||||||
import org.elasticsearch.index.IndexSettings;
|
import org.elasticsearch.index.IndexSettings;
|
||||||
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
|
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
|
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
|
||||||
import org.elasticsearch.ingest.IngestService;
|
import org.elasticsearch.ingest.IngestService;
|
||||||
import org.elasticsearch.ingest.PipelineConfiguration;
|
import org.elasticsearch.ingest.PipelineConfiguration;
|
||||||
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
|
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
|
||||||
|
@ -224,7 +224,7 @@ public class ClusterDeprecationChecks {
|
||||||
XContentType.JSON);
|
XContentType.JSON);
|
||||||
Map<String, Object> mappingAsMap = tuple.v2();
|
Map<String, Object> mappingAsMap = tuple.v2();
|
||||||
List<String> messages = mappingAsMap == null ? Collections.emptyList() :
|
List<String> messages = mappingAsMap == null ? Collections.emptyList() :
|
||||||
IndexDeprecationChecks.findInPropertiesRecursively(LegacyGeoShapeFieldMapper.CONTENT_TYPE,
|
IndexDeprecationChecks.findInPropertiesRecursively(GeoShapeFieldMapper.CONTENT_TYPE,
|
||||||
mappingAsMap,
|
mappingAsMap,
|
||||||
IndexDeprecationChecks::isGeoShapeFieldWithDeprecatedParam,
|
IndexDeprecationChecks::isGeoShapeFieldWithDeprecatedParam,
|
||||||
IndexDeprecationChecks::formatDeprecatedGeoShapeParamMessage);
|
IndexDeprecationChecks::formatDeprecatedGeoShapeParamMessage);
|
||||||
|
@ -253,7 +253,7 @@ public class ClusterDeprecationChecks {
|
||||||
XContentType.JSON);
|
XContentType.JSON);
|
||||||
Map<String, Object> mappingAsMap = (Map<String, Object>) tuple.v2().get("_doc");
|
Map<String, Object> mappingAsMap = (Map<String, Object>) tuple.v2().get("_doc");
|
||||||
List<String> messages = mappingAsMap == null ? Collections.emptyList() :
|
List<String> messages = mappingAsMap == null ? Collections.emptyList() :
|
||||||
IndexDeprecationChecks.findInPropertiesRecursively(LegacyGeoShapeFieldMapper.CONTENT_TYPE,
|
IndexDeprecationChecks.findInPropertiesRecursively(GeoShapeFieldMapper.CONTENT_TYPE,
|
||||||
mappingAsMap,
|
mappingAsMap,
|
||||||
IndexDeprecationChecks::isGeoShapeFieldWithDeprecatedParam,
|
IndexDeprecationChecks::isGeoShapeFieldWithDeprecatedParam,
|
||||||
IndexDeprecationChecks::formatDeprecatedGeoShapeParamMessage);
|
IndexDeprecationChecks::formatDeprecatedGeoShapeParamMessage);
|
||||||
|
|
|
@ -16,10 +16,10 @@ import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.index.IndexModule;
|
import org.elasticsearch.index.IndexModule;
|
||||||
import org.elasticsearch.index.IndexSettings;
|
import org.elasticsearch.index.IndexSettings;
|
||||||
import org.elasticsearch.index.IndexingSlowLog;
|
import org.elasticsearch.index.IndexingSlowLog;
|
||||||
|
import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
|
||||||
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
|
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
|
||||||
import org.elasticsearch.index.SearchSlowLog;
|
import org.elasticsearch.index.SearchSlowLog;
|
||||||
import org.elasticsearch.index.SlowLogLevel;
|
import org.elasticsearch.index.SlowLogLevel;
|
||||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
|
|
||||||
import org.elasticsearch.search.SearchModule;
|
import org.elasticsearch.search.SearchModule;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -384,8 +384,8 @@ public class IndexDeprecationChecks {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static boolean isGeoShapeFieldWithDeprecatedParam(Map<?, ?> property) {
|
protected static boolean isGeoShapeFieldWithDeprecatedParam(Map<?, ?> property) {
|
||||||
return LegacyGeoShapeFieldMapper.CONTENT_TYPE.equals(property.get("type")) &&
|
return GeoShapeFieldMapper.CONTENT_TYPE.equals(property.get("type")) &&
|
||||||
LegacyGeoShapeFieldMapper.DEPRECATED_PARAMETERS.stream().anyMatch(deprecatedParameter ->
|
GeoShapeFieldMapper.DEPRECATED_PARAMETERS.stream().anyMatch(deprecatedParameter ->
|
||||||
property.containsKey(deprecatedParameter)
|
property.containsKey(deprecatedParameter)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -393,7 +393,7 @@ public class IndexDeprecationChecks {
|
||||||
protected static String formatDeprecatedGeoShapeParamMessage(String type, Map.Entry<?, ?> entry) {
|
protected static String formatDeprecatedGeoShapeParamMessage(String type, Map.Entry<?, ?> entry) {
|
||||||
String fieldName = entry.getKey().toString();
|
String fieldName = entry.getKey().toString();
|
||||||
Map<?, ?> value = (Map<?, ?>) entry.getValue();
|
Map<?, ?> value = (Map<?, ?>) entry.getValue();
|
||||||
return LegacyGeoShapeFieldMapper.DEPRECATED_PARAMETERS.stream()
|
return GeoShapeFieldMapper.DEPRECATED_PARAMETERS.stream()
|
||||||
.filter(deprecatedParameter -> value.containsKey(deprecatedParameter))
|
.filter(deprecatedParameter -> value.containsKey(deprecatedParameter))
|
||||||
.map(deprecatedParameter -> String.format(Locale.ROOT, "parameter [%s] in field [%s]", deprecatedParameter, fieldName))
|
.map(deprecatedParameter -> String.format(Locale.ROOT, "parameter [%s] in field [%s]", deprecatedParameter, fieldName))
|
||||||
.collect(Collectors.joining("; "));
|
.collect(Collectors.joining("; "));
|
||||||
|
@ -405,7 +405,7 @@ public class IndexDeprecationChecks {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Map<String, Object> sourceAsMap = indexMetadata.mapping().getSourceAsMap();
|
Map<String, Object> sourceAsMap = indexMetadata.mapping().getSourceAsMap();
|
||||||
List<String> messages = findInPropertiesRecursively(LegacyGeoShapeFieldMapper.CONTENT_TYPE, sourceAsMap,
|
List<String> messages = findInPropertiesRecursively(GeoShapeFieldMapper.CONTENT_TYPE, sourceAsMap,
|
||||||
IndexDeprecationChecks::isGeoShapeFieldWithDeprecatedParam,
|
IndexDeprecationChecks::isGeoShapeFieldWithDeprecatedParam,
|
||||||
IndexDeprecationChecks::formatDeprecatedGeoShapeParamMessage);
|
IndexDeprecationChecks::formatDeprecatedGeoShapeParamMessage);
|
||||||
if (messages.isEmpty()) {
|
if (messages.isEmpty()) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ dependencies {
|
||||||
|
|
||||||
testImplementation project(path: xpackModule('monitoring'))
|
testImplementation project(path: xpackModule('monitoring'))
|
||||||
testImplementation project(path: xpackModule('spatial'))
|
testImplementation project(path: xpackModule('spatial'))
|
||||||
|
testImplementation project(path: ':modules:legacy-geo')
|
||||||
testImplementation project(path: ':modules:percolator')
|
testImplementation project(path: ':modules:percolator')
|
||||||
testImplementation project(path: xpackModule('sql:sql-action'))
|
testImplementation project(path: xpackModule('sql:sql-action'))
|
||||||
testImplementation project(path: ':modules:analysis-common')
|
testImplementation project(path: ':modules:analysis-common')
|
||||||
|
|
|
@ -6,13 +6,15 @@ esplugin {
|
||||||
name 'spatial'
|
name 'spatial'
|
||||||
description 'A plugin for Basic Spatial features'
|
description 'A plugin for Basic Spatial features'
|
||||||
classname 'org.elasticsearch.xpack.spatial.SpatialPlugin'
|
classname 'org.elasticsearch.xpack.spatial.SpatialPlugin'
|
||||||
extendedPlugins = ['x-pack-core']
|
extendedPlugins = ['x-pack-core', 'legacy-geo']
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
compileOnly project(path: ':modules:legacy-geo')
|
||||||
compileOnly project(path: xpackModule('core'))
|
compileOnly project(path: xpackModule('core'))
|
||||||
testImplementation(testArtifact(project(xpackModule('core'))))
|
testImplementation(testArtifact(project(xpackModule('core'))))
|
||||||
testImplementation project(path: xpackModule('vector-tile'))
|
testImplementation project(path: xpackModule('vector-tile'))
|
||||||
|
testImplementation project(path: ':modules:legacy-geo')
|
||||||
yamlRestTestImplementation(testArtifact(project(xpackModule('core'))))
|
yamlRestTestImplementation(testArtifact(project(xpackModule('core'))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ import org.elasticsearch.index.mapper.GeoShapeFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.GeoShapeIndexer;
|
import org.elasticsearch.index.mapper.GeoShapeIndexer;
|
||||||
import org.elasticsearch.index.mapper.GeoShapeParser;
|
import org.elasticsearch.index.mapper.GeoShapeParser;
|
||||||
import org.elasticsearch.index.mapper.GeoShapeQueryable;
|
import org.elasticsearch.index.mapper.GeoShapeQueryable;
|
||||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
|
|
||||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
import org.elasticsearch.index.mapper.Mapper;
|
import org.elasticsearch.index.mapper.Mapper;
|
||||||
import org.elasticsearch.index.mapper.MapperBuilderContext;
|
import org.elasticsearch.index.mapper.MapperBuilderContext;
|
||||||
|
@ -39,6 +38,7 @@ import org.elasticsearch.index.mapper.MapperParsingException;
|
||||||
import org.elasticsearch.index.mapper.MappingParserContext;
|
import org.elasticsearch.index.mapper.MappingParserContext;
|
||||||
import org.elasticsearch.index.query.QueryShardException;
|
import org.elasticsearch.index.query.QueryShardException;
|
||||||
import org.elasticsearch.index.query.SearchExecutionContext;
|
import org.elasticsearch.index.query.SearchExecutionContext;
|
||||||
|
import org.elasticsearch.legacygeo.mapper.LegacyGeoShapeFieldMapper;
|
||||||
import org.elasticsearch.search.lookup.SearchLookup;
|
import org.elasticsearch.search.lookup.SearchLookup;
|
||||||
import org.elasticsearch.xpack.spatial.index.fielddata.plain.AbstractLatLonShapeIndexFieldData;
|
import org.elasticsearch.xpack.spatial.index.fielddata.plain.AbstractLatLonShapeIndexFieldData;
|
||||||
import org.elasticsearch.xpack.spatial.search.aggregations.support.GeoShapeValuesSourceType;
|
import org.elasticsearch.xpack.spatial.search.aggregations.support.GeoShapeValuesSourceType;
|
||||||
|
@ -280,7 +280,7 @@ public class GeoShapeWithDocValuesFieldMapper extends AbstractShapeGeometryField
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void checkIncomingMergeType(FieldMapper mergeWith) {
|
protected void checkIncomingMergeType(FieldMapper mergeWith) {
|
||||||
if (mergeWith instanceof LegacyGeoShapeFieldMapper) {
|
if (mergeWith instanceof GeoShapeWithDocValuesFieldMapper == false && CONTENT_TYPE.equals(mergeWith.typeName())) {
|
||||||
throw new IllegalArgumentException("mapper [" + name()
|
throw new IllegalArgumentException("mapper [" + name()
|
||||||
+ "] of type [geo_shape] cannot change strategy from [BKD] to [recursive]");
|
+ "] of type [geo_shape] cannot change strategy from [BKD] to [recursive]");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
import org.elasticsearch.index.mapper.DocumentMapper;
|
import org.elasticsearch.index.mapper.DocumentMapper;
|
||||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
|
|
||||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||||
import org.elasticsearch.index.mapper.Mapper;
|
import org.elasticsearch.index.mapper.Mapper;
|
||||||
import org.elasticsearch.index.mapper.MapperParsingException;
|
import org.elasticsearch.index.mapper.MapperParsingException;
|
||||||
|
@ -32,6 +31,7 @@ import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.index.mapper.MapperTestCase;
|
import org.elasticsearch.index.mapper.MapperTestCase;
|
||||||
import org.elasticsearch.index.mapper.ParsedDocument;
|
import org.elasticsearch.index.mapper.ParsedDocument;
|
||||||
import org.elasticsearch.index.mapper.SourceToParse;
|
import org.elasticsearch.index.mapper.SourceToParse;
|
||||||
|
import org.elasticsearch.legacygeo.mapper.LegacyGeoShapeFieldMapper;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
import org.elasticsearch.test.VersionUtils;
|
import org.elasticsearch.test.VersionUtils;
|
||||||
import org.elasticsearch.xpack.spatial.LocalStateSpatialPlugin;
|
import org.elasticsearch.xpack.spatial.LocalStateSpatialPlugin;
|
||||||
|
|
|
@ -18,8 +18,8 @@ import org.elasticsearch.geo.GeometryTestUtils;
|
||||||
import org.elasticsearch.geometry.Geometry;
|
import org.elasticsearch.geometry.Geometry;
|
||||||
import org.elasticsearch.geometry.MultiPoint;
|
import org.elasticsearch.geometry.MultiPoint;
|
||||||
import org.elasticsearch.geometry.Point;
|
import org.elasticsearch.geometry.Point;
|
||||||
import org.elasticsearch.index.mapper.LegacyGeoShapeFieldMapper;
|
|
||||||
import org.elasticsearch.index.mapper.MapperParsingException;
|
import org.elasticsearch.index.mapper.MapperParsingException;
|
||||||
|
import org.elasticsearch.legacygeo.mapper.LegacyGeoShapeFieldMapper;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
import org.elasticsearch.search.geo.GeoShapeQueryTestCase;
|
import org.elasticsearch.search.geo.GeoShapeQueryTestCase;
|
||||||
import org.elasticsearch.xpack.spatial.LocalStateSpatialPlugin;
|
import org.elasticsearch.xpack.spatial.LocalStateSpatialPlugin;
|
||||||
|
|
|
@ -100,6 +100,7 @@ subprojects {
|
||||||
|
|
||||||
// spatial dependency
|
// spatial dependency
|
||||||
testRuntimeOnly project(path: xpackModule('spatial'))
|
testRuntimeOnly project(path: xpackModule('spatial'))
|
||||||
|
testRuntimeOnly project(path: ':modules:legacy-geo')
|
||||||
|
|
||||||
testRuntimeOnly "org.slf4j:slf4j-api:1.7.25"
|
testRuntimeOnly "org.slf4j:slf4j-api:1.7.25"
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ dependencies {
|
||||||
compileOnly project(path: xpackModule('core'))
|
compileOnly project(path: xpackModule('core'))
|
||||||
compileOnly project(path: xpackModule('spatial'))
|
compileOnly project(path: xpackModule('spatial'))
|
||||||
testImplementation(testArtifact(project(xpackModule('core'))))
|
testImplementation(testArtifact(project(xpackModule('core'))))
|
||||||
|
compileOnly "org.locationtech.jts:jts-core:${versions.jts}"
|
||||||
api "com.wdtinc:mapbox-vector-tile:3.1.0"
|
api "com.wdtinc:mapbox-vector-tile:3.1.0"
|
||||||
api "com.google.protobuf:protobuf-java:3.14.0"
|
api "com.google.protobuf:protobuf-java:3.14.0"
|
||||||
runtimeOnly("org.slf4j:slf4j-api:${versions.slf4j}")
|
runtimeOnly("org.slf4j:slf4j-api:${versions.slf4j}")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue