├── .classpath ├── .github ├── dependabot.yml └── workflows │ ├── codeql-analysis.yml │ └── sonarcloud.yml ├── .gitignore ├── .project ├── .settings ├── edu.umd.cs.findbugs.core.prefs ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.apt.core.prefs ├── org.eclipse.jdt.core.prefs ├── org.eclipse.jdt.ui.prefs ├── org.eclipse.m2e.core.prefs ├── org.eclipse.wst.common.component ├── org.eclipse.wst.common.project.facet.core.xml └── org.eclipse.wst.validation.prefs ├── AUTHORS ├── ClassHierarchy.png ├── ClassHierarchy2.png ├── LICENSE ├── README.md ├── pom.xml ├── postgis-java-ng dependencies.launch ├── postgis-java-ng only release (MacOS).launch ├── postgis-java-ng only release (Windows).launch ├── postgis-java-ng package.launch ├── postgis-java-ng release (MacOS).launch ├── postgis-java-ng release (Windows).launch └── src ├── main ├── java │ └── io │ │ └── github │ │ └── sebasbaumh │ │ └── postgis │ │ ├── CircularString.java │ │ ├── CompoundCurve.java │ │ ├── Curve.java │ │ ├── CurvePolygon.java │ │ ├── DriverWrapper.java │ │ ├── Geometry.java │ │ ├── GeometryCollection.java │ │ ├── LineBasedGeometry.java │ │ ├── LineString.java │ │ ├── LinearRing.java │ │ ├── MultiCurve.java │ │ ├── MultiGeometry.java │ │ ├── MultiLineString.java │ │ ├── MultiPoint.java │ │ ├── MultiPolygon.java │ │ ├── MultiSurface.java │ │ ├── PGbox2d.java │ │ ├── PGbox3d.java │ │ ├── PGboxbase.java │ │ ├── PGgeography.java │ │ ├── PGgeometry.java │ │ ├── PGgeometrybase.java │ │ ├── Point.java │ │ ├── Polygon.java │ │ ├── PolygonBase.java │ │ ├── PostGisUtil.java │ │ └── binary │ │ ├── BinaryParser.java │ │ ├── BinaryValueGetter.java │ │ ├── BinaryValueSetter.java │ │ ├── BinaryWriter.java │ │ ├── StringValueGetter.java │ │ ├── StringValueSetter.java │ │ ├── ValueGetter.java │ │ ├── ValueSetter.java │ │ └── package-info.java └── resources │ ├── META-INF │ └── services │ │ └── java.sql.Driver │ └── org │ └── postgresql │ └── driverconfig.properties └── test └── java └── io └── github └── sebasbaumh └── postgis ├── BoxesTest.java ├── DatabaseTestBase.java ├── DatatypesTest.java ├── DriverWrapperTest.java ├── EmptyGeometriesTest.java ├── GeographyTest.java ├── ParserLocalTest.java ├── ParserTest.java ├── PostgisDatabaseTest.java ├── SerializationTest.java ├── ServerTest.java ├── ServiceTest.java ├── TokenizerTest.java └── VersionPrinterTest.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "maven" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | - package-ecosystem: "github-actions" 13 | directory: "/" 14 | schedule: 15 | interval: "weekly" 16 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [master] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [master] 20 | schedule: 21 | - cron: '0 16 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'java' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v4 42 | 43 | # setup Java 21 using Eclipse Temurin/Adoptium 44 | - uses: actions/setup-java@v4 45 | with: 46 | java-version: 21 47 | distribution: temurin 48 | cache: maven 49 | 50 | # Initializes the CodeQL tools for scanning. 51 | - name: Initialize CodeQL 52 | uses: github/codeql-action/init@v3 53 | with: 54 | languages: ${{ matrix.language }} 55 | # If you wish to specify custom queries, you can do so here or in a config file. 56 | # By default, queries listed here will override any specified in a config file. 57 | # Prefix the list here with "+" to use these queries and those in the config file. 58 | 59 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 60 | # queries: security-extended,security-and-quality 61 | 62 | 63 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 64 | # If this step fails, then you should remove it and run the build manually (see below) 65 | - name: Autobuild 66 | uses: github/codeql-action/autobuild@v3 67 | 68 | # ℹ️ Command-line programs to run using the OS shell. 69 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 70 | 71 | # If the Autobuild fails above, remove it and uncomment the following three lines. 72 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 73 | 74 | # - run: | 75 | # echo "Run, Build Application using script" 76 | # ./location_of_script_within_repo/buildscript.sh 77 | 78 | - name: Perform CodeQL Analysis 79 | uses: github/codeql-action/analyze@v3 80 | -------------------------------------------------------------------------------- /.github/workflows/sonarcloud.yml: -------------------------------------------------------------------------------- 1 | name: sonarcloud 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | with: 12 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 13 | - name: Set up JDK 21 14 | uses: actions/setup-java@v4 15 | with: 16 | java-version: 21 17 | distribution: temurin 18 | cache: maven 19 | - name: Analyze with sonarcloud 20 | run: mvn --batch-mode verify sonar:sonar -Dsonar.projectKey=sebasbaumh_postgis-java-ng -Dsonar.organization=sebasbaumh -Dsonar.host.url=https://sonarcloud.io -Dsonar.token=${{ secrets.SONAR_TOKEN }} 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | 24 | # Maven build/release 25 | /target/ 26 | *.releaseBackup 27 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | postgis-java-ng 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.common.project.facet.core.builder 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | 35 | org.eclipse.jem.workbench.JavaEMFNature 36 | org.eclipse.wst.common.modulecore.ModuleCoreNature 37 | org.eclipse.jdt.core.javanature 38 | org.eclipse.m2e.core.maven2Nature 39 | edu.umd.cs.findbugs.plugin.eclipse.findbugsNature 40 | org.eclipse.wst.common.project.facet.core.nature 41 | 42 | 43 | 44 | 1714375844981 45 | 46 | 30 47 | 48 | org.eclipse.core.resources.regexFilterMatcher 49 | node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/main/resources=UTF-8 4 | encoding//src/test/java=UTF-8 5 | encoding//src/test/resources=UTF-8 6 | encoding/=UTF-8 7 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.apt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.apt.aptEnabled=false 3 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.ui.prefs: -------------------------------------------------------------------------------- 1 | cleanup.add_all=false 2 | cleanup.add_default_serial_version_id=false 3 | cleanup.add_generated_serial_version_id=true 4 | cleanup.add_missing_annotations=true 5 | cleanup.add_missing_deprecated_annotations=true 6 | cleanup.add_missing_methods=true 7 | cleanup.add_missing_nls_tags=false 8 | cleanup.add_missing_override_annotations=true 9 | cleanup.add_missing_override_annotations_interface_methods=true 10 | cleanup.add_serial_version_id=true 11 | cleanup.always_use_blocks=true 12 | cleanup.always_use_parentheses_in_expressions=false 13 | cleanup.always_use_this_for_non_static_field_access=false 14 | cleanup.always_use_this_for_non_static_method_access=false 15 | cleanup.array_with_curly=false 16 | cleanup.arrays_fill=false 17 | cleanup.bitwise_conditional_expression=false 18 | cleanup.boolean_literal=false 19 | cleanup.boolean_value_rather_than_comparison=true 20 | cleanup.break_loop=false 21 | cleanup.collection_cloning=false 22 | cleanup.comparing_on_criteria=false 23 | cleanup.comparison_statement=false 24 | cleanup.controlflow_merge=false 25 | cleanup.convert_functional_interfaces=false 26 | cleanup.convert_to_enhanced_for_loop=false 27 | cleanup.convert_to_enhanced_for_loop_if_loop_var_used=false 28 | cleanup.convert_to_switch_expressions=false 29 | cleanup.correct_indentation=true 30 | cleanup.do_while_rather_than_while=true 31 | cleanup.double_negation=false 32 | cleanup.else_if=false 33 | cleanup.embedded_if=false 34 | cleanup.evaluate_nullable=false 35 | cleanup.extract_increment=false 36 | cleanup.format_source_code=true 37 | cleanup.format_source_code_changes_only=false 38 | cleanup.hash=false 39 | cleanup.if_condition=false 40 | cleanup.insert_inferred_type_arguments=false 41 | cleanup.instanceof=false 42 | cleanup.instanceof_keyword=false 43 | cleanup.invert_equals=false 44 | cleanup.join=false 45 | cleanup.lazy_logical_operator=true 46 | cleanup.make_local_variable_final=false 47 | cleanup.make_parameters_final=false 48 | cleanup.make_private_fields_final=false 49 | cleanup.make_type_abstract_if_missing_method=false 50 | cleanup.make_variable_declarations_final=true 51 | cleanup.map_cloning=false 52 | cleanup.merge_conditional_blocks=false 53 | cleanup.multi_catch=false 54 | cleanup.never_use_blocks=false 55 | cleanup.never_use_parentheses_in_expressions=true 56 | cleanup.no_string_creation=false 57 | cleanup.no_super=false 58 | cleanup.number_suffix=true 59 | cleanup.objects_equals=false 60 | cleanup.one_if_rather_than_duplicate_blocks_that_fall_through=false 61 | cleanup.operand_factorization=false 62 | cleanup.organize_imports=true 63 | cleanup.overridden_assignment=false 64 | cleanup.plain_replacement=false 65 | cleanup.precompile_regex=false 66 | cleanup.primitive_comparison=false 67 | cleanup.primitive_parsing=false 68 | cleanup.primitive_rather_than_wrapper=true 69 | cleanup.primitive_serialization=false 70 | cleanup.pull_out_if_from_if_else=false 71 | cleanup.pull_up_assignment=false 72 | cleanup.push_down_negation=false 73 | cleanup.qualify_static_field_accesses_with_declaring_class=false 74 | cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true 75 | cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true 76 | cleanup.qualify_static_member_accesses_with_declaring_class=true 77 | cleanup.qualify_static_method_accesses_with_declaring_class=false 78 | cleanup.reduce_indentation=false 79 | cleanup.redundant_comparator=false 80 | cleanup.redundant_falling_through_block_end=false 81 | cleanup.remove_private_constructors=true 82 | cleanup.remove_redundant_modifiers=true 83 | cleanup.remove_redundant_semicolons=true 84 | cleanup.remove_redundant_type_arguments=false 85 | cleanup.remove_trailing_whitespaces=true 86 | cleanup.remove_trailing_whitespaces_all=true 87 | cleanup.remove_trailing_whitespaces_ignore_empty=false 88 | cleanup.remove_unnecessary_array_creation=true 89 | cleanup.remove_unnecessary_casts=true 90 | cleanup.remove_unnecessary_nls_tags=true 91 | cleanup.remove_unused_imports=true 92 | cleanup.remove_unused_local_variables=true 93 | cleanup.remove_unused_private_fields=true 94 | cleanup.remove_unused_private_members=true 95 | cleanup.remove_unused_private_methods=true 96 | cleanup.remove_unused_private_types=true 97 | cleanup.return_expression=false 98 | cleanup.simplify_lambda_expression_and_method_ref=false 99 | cleanup.single_used_field=false 100 | cleanup.sort_members=true 101 | cleanup.sort_members_all=true 102 | cleanup.standard_comparison=false 103 | cleanup.static_inner_class=false 104 | cleanup.strictly_equal_or_different=false 105 | cleanup.stringbuffer_to_stringbuilder=false 106 | cleanup.stringbuilder=false 107 | cleanup.stringbuilder_for_local_vars=true 108 | cleanup.stringconcat_to_textblock=false 109 | cleanup.substring=false 110 | cleanup.switch=false 111 | cleanup.system_property=false 112 | cleanup.system_property_boolean=false 113 | cleanup.system_property_file_encoding=false 114 | cleanup.system_property_file_separator=false 115 | cleanup.system_property_line_separator=false 116 | cleanup.system_property_path_separator=false 117 | cleanup.ternary_operator=false 118 | cleanup.try_with_resource=false 119 | cleanup.unlooped_while=false 120 | cleanup.unreachable_block=false 121 | cleanup.use_anonymous_class_creation=false 122 | cleanup.use_autoboxing=false 123 | cleanup.use_blocks=false 124 | cleanup.use_blocks_only_for_return_and_throw=false 125 | cleanup.use_directly_map_method=false 126 | cleanup.use_lambda=true 127 | cleanup.use_parentheses_in_expressions=false 128 | cleanup.use_string_is_blank=false 129 | cleanup.use_this_for_non_static_field_access=false 130 | cleanup.use_this_for_non_static_field_access_only_if_necessary=true 131 | cleanup.use_this_for_non_static_method_access=false 132 | cleanup.use_this_for_non_static_method_access_only_if_necessary=true 133 | cleanup.use_unboxing=false 134 | cleanup.use_var=false 135 | cleanup.useless_continue=false 136 | cleanup.useless_return=false 137 | cleanup.valueof_rather_than_instantiation=false 138 | cleanup_profile=_SB 139 | cleanup_settings_version=2 140 | eclipse.preferences.version=1 141 | formatter_profile=_SB 142 | formatter_settings_version=23 143 | org.eclipse.jdt.ui.text.custom_code_templates= 144 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | disabled=06target 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | (C) 2004 Paul Ramsey, pramsey@refractions.net 2 | (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 3 | (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 4 | (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 5 | -------------------------------------------------------------------------------- /ClassHierarchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebasbaumh/postgis-java-ng/0257200c3424e4129ee9de57b54c4dff5a7c001c/ClassHierarchy.png -------------------------------------------------------------------------------- /ClassHierarchy2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebasbaumh/postgis-java-ng/0257200c3424e4129ee9de57b54c4dff5a7c001c/ClassHierarchy2.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PostGIS Java bindings (Next Generation) # 2 | 3 | [![CodeQL](https://github.com/sebasbaumh/postgis-java-ng/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/sebasbaumh/postgis-java-ng/actions/workflows/codeql-analysis.yml) 4 | [![Maven Central](https://img.shields.io/maven-central/v/io.github.sebasbaumh/postgis-java-ng)](https://search.maven.org/artifact/io.github.sebasbaumh/postgis-java-ng) 5 | [![javadoc](https://javadoc.io/badge2/io.github.sebasbaumh/postgis-java-ng/javadoc.svg)](https://javadoc.io/doc/io.github.sebasbaumh/postgis-java-ng/latest/index.html) 6 | [![License](https://img.shields.io/github/license/sebasbaumh/postgis-java-ng.svg)](https://github.com/sebasbaumh/postgis-java-ng/blob/master/LICENSE) 7 | 8 | [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=sebasbaumh_postgis-java-ng&metric=ncloc)](https://sonarcloud.io/dashboard?id=sebasbaumh_postgis-java-ng) 9 | [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=sebasbaumh_postgis-java-ng&metric=security_rating)](https://sonarcloud.io/dashboard?id=sebasbaumh_postgis-java-ng) 10 | [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=sebasbaumh_postgis-java-ng&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=sebasbaumh_postgis-java-ng) 11 | [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=sebasbaumh_postgis-java-ng&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=sebasbaumh_postgis-java-ng) 12 | 13 | This project contains Java bindings for using [PostGIS](https://postgis.net/) geometries coming from a [PostgreSQL](https://www.postgresql.org/) database. 14 | *It is originally based on [postgis-java](https://github.com/postgis/postgis-java) and I want to thank its authors for their work.* 15 | 16 | **Project goals and improvements:** 17 | * Support for geometries containing arcs like `CIRCULARSTRING` or `CURVEPOLYGON` 18 | * Support for PostGIS [geography datatype](https://postgis.net/docs/using_postgis_dbmanagement.html#PostGIS_Geography) 19 | * Extended support for bounding boxes, i.e. [box2d](https://postgis.net/docs/box2d_type.html)/[box3d](https://postgis.net/docs/box3d_type.html) PostGIS data types (as PGbox2d/PGbox3d) 20 | * Support for wrapped connections (like used in WildFly and c3p0 connection pooling) 21 | * Use generic Java types where possible and simplify/streamline API 22 | * Clean up code to basically only work on [WKB](https://en.wikipedia.org/wiki/Well-known_text#Well-known_binary)/EWKB implementations to reduce code duplication and focus on the actual database format 23 | * Support for binary transfer of geometry data (if enabled in PostgreSQL JDBC driver) 24 | * use PostgreSQL JDBC driver [42.5.1](https://jdbc.postgresql.org/changelogs/2023-01-31-42.5.2-release/) or later to enable it automatically 25 | * Support for the latest PostgreSQL and PostGIS versions 26 | * Recommended are PostgreSQL 15.1 and PostGIS 3.2.2 27 | * Supported are versions starting from PostgreSQL 9.6 and PostGIS 2.3 28 | * Support for current JDKs 29 | * JDK 21 ([main branch](https://github.com/sebasbaumh/postgis-java-ng/tree/master)) 30 | * deprecated branches 31 | * [JDK 17](https://github.com/sebasbaumh/postgis-java-ng/tree/jdk17) 32 | * [JDK 11](https://github.com/sebasbaumh/postgis-java-ng/tree/jdk11) 33 | * [JDK 8](https://github.com/sebasbaumh/postgis-java-ng/tree/jdk8) 34 | * The [license](https://github.com/sebasbaumh/postgis-java-ng/blob/master/LICENSE) is still LGPL 35 | * The authors are listed [here](https://github.com/sebasbaumh/postgis-java-ng/blob/master/AUTHORS) 36 | 37 | **Supported [geometry types](https://postgis.net/docs/using_postgis_dbmanagement.html#RefObject):** 38 | * `Point` 39 | * `LineString` 40 | * `CircularString` 41 | * `CompoundCurve` 42 | * `Polygon` 43 | * `CurvePolygon` 44 | * `MultiPoint` 45 | * `MultiLineString` 46 | * `MultiCurve` 47 | * `MultiPolygon` 48 | * `MultiSurface` 49 | * `GeometryCollection` 50 | * `box2d` 51 | * `box3d` 52 | 53 | ## How to use it ## 54 | There is a Maven artifact in the official Maven repository, so just add this to your Maven POM: 55 | 56 | ```xml 57 | 58 | io.github.sebasbaumh 59 | postgis-java-ng 60 | 25.1.0 61 | 62 | ``` 63 | 64 | The version reflects the year of the release, e.g. `25.1.0` is a version released in 2024. 65 | 66 | The API differs a bit from [postgis-java](https://github.com/postgis/postgis-java) with the main point being a different namespace (`io.github.sebasbaumh.postgis`) as publishing a project to Maven Central requires to own that namespace. 67 | In addition the class structure is a bit different (see below) to support arc geometries and reduce boilerplate code, but you should be able to adapt to it easily. 68 | The implementations of the parser and writer for the geometries have been heavily reworked to speed up processing and reduce complexity. 69 | 70 | ## Hierarchy of geometry classes: ## 71 | 72 | ![Hierarchy of geometry classes](ClassHierarchy.png) 73 | 74 | ![Hierarchy of bounding box classes](ClassHierarchy2.png) 75 | 76 | ## How to run tests utilizing a PostgreSQL server ## 77 | 78 | You will need a PostgreSQL server with installed PostGIS extension for some of the tests. 79 | 80 | In this example the server is named `MyServer` and the database `UnitTestDB`. The database can be empty except installing the PostGIS extension. 81 | 82 | You should set up a database user for the unit tests, which has access rights to this database and only to this one. 83 | In this example the user is called `unittest` and has the password `CHANGEME`. 84 | 85 | To run the unit tests accessing the server, add the following to your VM arguments (eclipse Run Configuration->Arguments->VM arguments): 86 | 87 | `-DtestJdbcUrl="jdbc:postgresql://MyServer/UnitTestDB" -DtestJdbcUsername="unittest" -DtestJdbcPassword="CHANGEME"` 88 | 89 | Or add the following Maven build parameters to the launch configuration in eclipse: 90 | 91 | |Parameter Name|Value| 92 | |--------------|-----| 93 | |`testJdbcUrl`|`jdbc:postgresql://MyServer/UnitTestDB`| 94 | |`testJdbcUsername`|`unittest`| 95 | |`testJdbcPassword`|`CHANGEME`| 96 | 97 | If it works, you will see this line in the build output: 98 | 99 | ``` 100 | Tests are running with a database 101 | ``` 102 | 103 | else 104 | 105 | ``` 106 | Tests are running without a database 107 | ``` 108 | 109 | *There are also local tests contained in the project, so you are still able to test most parts without specifying a PostgreSQL server. And the test console output will show if tests were run with or without a database.* 110 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | io.github.sebasbaumh 5 | postgis-java-ng 6 | 7 | 25.1.1-SNAPSHOT 8 | jar 9 | 10 | PostGIS Java bindings 11 | This project contains Java bindings for using PostGIS geometries coming from a PostgreSQL database. 12 | https://github.com/sebasbaumh/postgis-java-ng 13 | 14 | 15 | 16 | GNU Lesser General Public License v3.0 17 | https://www.gnu.org/licenses/lgpl-3.0.en.html 18 | 19 | 20 | 21 | 22 | 23 | Sebastian Baumhekel 24 | sebastian.baumhekel@gmail.com 25 | https://github.com/sebasbaumh 26 | 27 | 28 | 29 | 30 | scm:git:git://github.com/sebasbaumh/postgis-java-ng.git 31 | scm:git:ssh://github.com:sebasbaumh/postgis-java-ng.git 32 | https://github.com/sebasbaumh/postgis-java-ng/tree/master 33 | v25.1.0 34 | 35 | 36 | 37 | 38 | ossrh 39 | https://s01.oss.sonatype.org/content/repositories/snapshots 40 | 41 | 42 | ossrh 43 | https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ 44 | 45 | 46 | 47 | 48 | 49 | UTF-8 50 | 51 | 52 | 53 | 54 | 55 | com.github.spotbugs 56 | spotbugs-annotations 57 | 4.9.3 58 | provided 59 | 60 | 61 | org.eclipse.jdt 62 | org.eclipse.jdt.annotation 63 | 2.3.100 64 | provided 65 | 66 | 67 | 68 | junit 69 | junit 70 | 4.13.2 71 | test 72 | 73 | 74 | com.mchange 75 | c3p0 76 | 0.11.1 77 | test 78 | 79 | 80 | com.mchange 81 | mchange-commons-java 82 | 0.3.2 83 | test 84 | 85 | 86 | org.slf4j 87 | slf4j-api 88 | 2.0.17 89 | test 90 | 91 | 92 | org.slf4j 93 | slf4j-jdk14 94 | 2.0.17 95 | test 96 | 97 | 98 | 99 | org.postgresql 100 | postgresql 101 | 42.7.6 102 | 103 | 104 | 105 | 106 | 107 | 108 | maven-compiler-plugin 109 | 3.14.0 110 | 111 | 21 112 | 21 113 | -Xlint:all 114 | 115 | 116 | 117 | 118 | 119 | org.apache.maven.plugins 120 | maven-source-plugin 121 | 3.3.1 122 | 123 | 124 | attach-sources 125 | 126 | jar-no-fork 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | org.apache.maven.plugins 135 | maven-javadoc-plugin 136 | 3.11.2 137 | 138 | 139 | attach-javadocs 140 | 141 | jar 142 | 143 | 144 | 145 | 21 146 | 147 | none 148 | false 149 | 150 | 151 | 152 | 153 | 154 | org.apache.maven.plugins 155 | maven-enforcer-plugin 156 | 3.5.0 157 | 158 | 159 | enforce-maven 160 | 161 | enforce 162 | 163 | 164 | 165 | 166 | 3.9 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | org.apache.maven.plugins 176 | maven-deploy-plugin 177 | 3.1.4 178 | 179 | 180 | org.apache.maven.plugins 181 | maven-gpg-plugin 182 | 3.2.7 183 | 184 | 185 | 186 | 187 | 188 | 189 | org.apache.maven.plugins 190 | maven-release-plugin 191 | 3.1.1 192 | 193 | true 194 | false 195 | release-sign-artifacts 196 | v@{project.version} 197 | 198 | 199 | 200 | org.sonatype.central 201 | central-publishing-maven-plugin 202 | 0.7.0 203 | true 204 | 205 | central 206 | true 207 | 208 | 209 | 210 | 211 | org.apache.maven.plugins 212 | maven-dependency-plugin 213 | 3.8.1 214 | 215 | 216 | org.codehaus.mojo 217 | versions-maven-plugin 218 | 2.18.0 219 | 220 | 221 | 222 | 223 | 224 | 230 | 231 | release-sign-artifacts 232 | 233 | 234 | 235 | org.apache.maven.plugins 236 | maven-gpg-plugin 237 | 238 | 239 | sign-artifacts 240 | verify 241 | 242 | sign 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | -------------------------------------------------------------------------------- /postgis-java-ng dependencies.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /postgis-java-ng only release (MacOS).launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /postgis-java-ng only release (Windows).launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /postgis-java-ng package.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /postgis-java-ng release (MacOS).launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /postgis-java-ng release (Windows).launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/CircularString.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * The CIRCULARSTRING is the basic curve type, similar to a LINESTRING in the linear world. A single segment required 29 | * three points, the start and end points (first and third) and any other point on the arc. The exception to this is for 30 | * a closed circle, where the start and end points are the same. In this case the second point MUST be the center of the 31 | * arc, ie the opposite side of the circle. To chain arcs together, the last point of the previous arc becomes the first 32 | * point of the next arc, just like in LINESTRING. This means that a valid circular string must have an odd number of 33 | * points greater than 1. 34 | * @author Sebastian Baumhekel 35 | */ 36 | @NonNullByDefault 37 | public class CircularString extends LineString 38 | { 39 | /* JDK 1.5 Serialization */ 40 | private static final long serialVersionUID = 0x100; 41 | /** 42 | * The OGIS geometry type number for arcs/circles. 43 | */ 44 | public static final int TYPE = 8; 45 | 46 | /** 47 | * Constructs an instance. 48 | */ 49 | public CircularString() 50 | { 51 | super(TYPE); 52 | } 53 | 54 | /** 55 | * Constructs an instance. 56 | * @param points points 57 | */ 58 | public CircularString(Iterable points) 59 | { 60 | super(TYPE); 61 | addAll(points); 62 | } 63 | 64 | /* 65 | * (non-Javadoc) 66 | * @see io.github.sebasbaumh.postgis.LineBasedGeom#length() 67 | */ 68 | @Override 69 | public double length() 70 | { 71 | // FIX: calculate length on arc 72 | return super.length(); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/CompoundCurve.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Collection; 27 | import java.util.Collections; 28 | import java.util.Iterator; 29 | 30 | import javax.annotation.Nullable; 31 | 32 | import org.eclipse.jdt.annotation.NonNullByDefault; 33 | 34 | /** 35 | * A compound curve is a single, continuous curve that has both curved (circular) segments and linear segments. That 36 | * means that in addition to having well-formed components, the end point of every component (except the last) must be 37 | * coincident with the start point of the following component. Just note: here it is treated as a special 38 | * {@link MultiCurve} where the end points of all contained lines match. 39 | * @author Sebastian Baumhekel 40 | */ 41 | @NonNullByDefault 42 | public class CompoundCurve extends Curve implements Iterable 43 | { 44 | private static final long serialVersionUID = 0x100; 45 | /** 46 | * The OGIS geometry type number for single, continuous curves that have both curved (circular) segments and linear 47 | * segments. 48 | */ 49 | public static final int TYPE = 9; 50 | 51 | /** 52 | * Sub geometries. 53 | */ 54 | private final ArrayList subgeoms = new ArrayList(); 55 | 56 | /** 57 | * Constructs an instance. 58 | */ 59 | public CompoundCurve() 60 | { 61 | super(TYPE); 62 | } 63 | 64 | /** 65 | * Constructs an instance. 66 | * @param geoms geometries 67 | */ 68 | public CompoundCurve(Iterable geoms) 69 | { 70 | super(TYPE); 71 | addAll(geoms); 72 | } 73 | 74 | /** 75 | * Adds a geometry. 76 | * @param geom geometry 77 | */ 78 | public void add(LineString geom) 79 | { 80 | subgeoms.add(geom); 81 | } 82 | 83 | /** 84 | * Adds all given geometries. 85 | * @param geoms geometries 86 | */ 87 | public final void addAll(Iterable geoms) 88 | { 89 | for (LineString geom : geoms) 90 | { 91 | subgeoms.add(geom); 92 | } 93 | } 94 | 95 | @Override 96 | public boolean checkConsistency() 97 | { 98 | if (!super.checkConsistency() || subgeoms.isEmpty()) 99 | { 100 | return false; 101 | } 102 | return PostGisUtil.checkConsistency(subgeoms); 103 | } 104 | 105 | /** 106 | * Closes this {@link Curve} if the last coordinate is not already the same as the first coordinate. 107 | */ 108 | @Override 109 | public void close() 110 | { 111 | LineString lsFirst = PostGisUtil.firstOrDefault(subgeoms); 112 | LineString lsLast = PostGisUtil.lastOrDefault(subgeoms); 113 | if ((lsFirst != null) && (lsLast != null)) 114 | { 115 | Point pFirst = lsFirst.getStartPoint(); 116 | Point pLast = lsLast.getEndPoint(); 117 | // check if there is a first point and the last point equals the first one 118 | if ((pFirst != null) && (pLast != null) && !pFirst.coordsAreEqual(pLast)) 119 | { 120 | // add the first point as closing last point 121 | lsLast.add(pFirst.copy()); 122 | } 123 | } 124 | } 125 | 126 | @Override 127 | public boolean equals(@Nullable Object other) 128 | { 129 | // check type and parent 130 | if ((other instanceof CompoundCurve cother) && super.equals(other)) 131 | { 132 | return PostGisUtil.equalsIterable(this.subgeoms, cother.subgeoms); 133 | } 134 | return false; 135 | } 136 | 137 | /* 138 | * (non-Javadoc) 139 | * @see io.github.sebasbaumh.postgis.Geometry#getCoordinates() 140 | */ 141 | @Override 142 | public Iterable getCoordinates() 143 | { 144 | ArrayList l = new ArrayList(); 145 | for (LineString geom : subgeoms) 146 | { 147 | for (Point p : geom.getCoordinates()) 148 | { 149 | l.add(p); 150 | } 151 | } 152 | return l; 153 | } 154 | 155 | /* 156 | * (non-Javadoc) 157 | * @see io.github.sebasbaumh.postgis.LineBasedGeometry#getEndPoint() 158 | */ 159 | @Nullable 160 | @Override 161 | public Point getEndPoint() 162 | { 163 | LineString ls = PostGisUtil.lastOrDefault(subgeoms); 164 | if (ls != null) 165 | { 166 | return ls.getEndPoint(); 167 | } 168 | return null; 169 | } 170 | 171 | /** 172 | * Gets all geometries. 173 | * @return geometries 174 | */ 175 | public Collection getGeometries() 176 | { 177 | return subgeoms; 178 | } 179 | 180 | /* 181 | * (non-Javadoc) 182 | * @see io.github.sebasbaumh.postgis.Geometry#getNumberOfCoordinates() 183 | */ 184 | @Override 185 | public int getNumberOfCoordinates() 186 | { 187 | int n = 0; 188 | for (LineString geom : subgeoms) 189 | { 190 | n += geom.getNumberOfCoordinates(); 191 | } 192 | return n; 193 | } 194 | 195 | /* 196 | * (non-Javadoc) 197 | * @see io.github.sebasbaumh.postgis.LineBasedGeometry#getStartPoint() 198 | */ 199 | @Nullable 200 | @Override 201 | public Point getStartPoint() 202 | { 203 | LineString ls = PostGisUtil.firstOrDefault(subgeoms); 204 | if (ls != null) 205 | { 206 | return ls.getStartPoint(); 207 | } 208 | return null; 209 | } 210 | 211 | @Override 212 | public int hashCode() 213 | { 214 | return 31 * super.hashCode() + subgeoms.hashCode(); 215 | } 216 | 217 | /* 218 | * (non-Javadoc) 219 | * @see io.github.sebasbaumh.postgis.Geometry#hasMeasure() 220 | */ 221 | @Override 222 | public boolean hasMeasure() 223 | { 224 | for (LineString geom : subgeoms) 225 | { 226 | if (geom.hasMeasure()) 227 | { 228 | return true; 229 | } 230 | } 231 | return false; 232 | } 233 | 234 | /* 235 | * (non-Javadoc) 236 | * @see io.github.sebasbaumh.postgis.Geometry#is3d() 237 | */ 238 | @Override 239 | public boolean is3d() 240 | { 241 | for (LineString geom : subgeoms) 242 | { 243 | if (geom.is3d()) 244 | { 245 | return true; 246 | } 247 | } 248 | return false; 249 | } 250 | 251 | /** 252 | * Checks, if there are no sub-geometries. 253 | * @return true on success, else false 254 | */ 255 | @Override 256 | public boolean isEmpty() 257 | { 258 | return subgeoms.isEmpty(); 259 | } 260 | 261 | /* 262 | * (non-Javadoc) 263 | * @see java.lang.Iterable#iterator() 264 | */ 265 | @Override 266 | public Iterator iterator() 267 | { 268 | return subgeoms.iterator(); 269 | } 270 | 271 | /* 272 | * (non-Javadoc) 273 | * @see io.github.sebasbaumh.postgis.LineBasedGeom#length() 274 | */ 275 | @Override 276 | public double length() 277 | { 278 | double d = 0; 279 | for (LineString ls : subgeoms) 280 | { 281 | d += ls.length(); 282 | } 283 | return d; 284 | } 285 | 286 | /* 287 | * (non-Javadoc) 288 | * @see io.github.sebasbaumh.postgis.Curve#reverse() 289 | */ 290 | @Override 291 | public void reverse() 292 | { 293 | // reverse linestrings as a whole 294 | Collections.reverse(subgeoms); 295 | // then reverse all individually 296 | for (LineString ls : subgeoms) 297 | { 298 | ls.reverse(); 299 | } 300 | } 301 | 302 | @Override 303 | public void setSrid(int srid) 304 | { 305 | super.setSrid(srid); 306 | for (LineString geom : subgeoms) 307 | { 308 | geom.setSrid(srid); 309 | } 310 | } 311 | 312 | /** 313 | * Gets the number of contained geometries. 314 | * @return number of contained geometries 315 | */ 316 | public int size() 317 | { 318 | return this.subgeoms.size(); 319 | } 320 | 321 | } 322 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/Curve.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * Base class for simple curves like {@link LineString}s and complex classes like {@link CompoundCurve}s. 29 | * @author Sebastian Baumhekel 30 | */ 31 | @NonNullByDefault 32 | public abstract class Curve extends Geometry implements LineBasedGeometry 33 | { 34 | private static final long serialVersionUID = 0x100; 35 | 36 | /** 37 | * Constructor for subclasses. 38 | * @param type has to be given by all subclasses 39 | */ 40 | protected Curve(int type) 41 | { 42 | super(type); 43 | } 44 | 45 | /** 46 | * Closes this {@link Curve} if the last coordinate is not already the same as the first coordinate. 47 | */ 48 | public abstract void close(); 49 | 50 | /** 51 | * Checks if this ring is oriented in clockwise direction. 52 | * @return true on success, else false 53 | */ 54 | public boolean isClockwise() 55 | { 56 | return isClosed() && (PostGisUtil.calcAreaSigned(getCoordinates()) < 0); 57 | } 58 | 59 | /* 60 | * (non-Javadoc) 61 | * @see io.github.sebasbaumh.postgis.LineBasedGeometry#isClosed() 62 | */ 63 | @Override 64 | public boolean isClosed() 65 | { 66 | Point pFirst = getStartPoint(); 67 | Point pLast = getEndPoint(); 68 | return (pFirst != null) && (pLast != null) && pFirst.coordsAreEqual(pLast); 69 | } 70 | 71 | /** 72 | * Reverses this linestring. 73 | */ 74 | public abstract void reverse(); 75 | 76 | /* 77 | * (non-Javadoc) 78 | * @see java.lang.Object#toString() 79 | */ 80 | @Override 81 | public String toString() 82 | { 83 | return this.getClass().getSimpleName() + " [" + this.getNumberOfCoordinates() + " points]"; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/CurvePolygon.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * A CURVEPOLYGON is just like a polygon, with an outer ring and zero or more inner rings. The difference is that a ring 29 | * can take the form of a circular string, linear string or compound string. 30 | * @author Sebastian Baumhekel 31 | */ 32 | @NonNullByDefault 33 | public class CurvePolygon extends PolygonBase 34 | { 35 | /* JDK 1.5 Serialization */ 36 | private static final long serialVersionUID = 0x100; 37 | /** 38 | * The OGIS geometry type number for polygons with curved segments. 39 | */ 40 | public static final int TYPE = 10; 41 | 42 | /** 43 | * Constructs an instance. 44 | */ 45 | public CurvePolygon() 46 | { 47 | super(TYPE, LineString.class); 48 | } 49 | 50 | /** 51 | * Constructs an instance. 52 | * @param lsOuterRing outer ring 53 | */ 54 | public CurvePolygon(Curve lsOuterRing) 55 | { 56 | super(TYPE, lsOuterRing); 57 | } 58 | 59 | /** 60 | * Constructs an instance. 61 | * @param rings rings (first one will be the outer ring) 62 | */ 63 | public CurvePolygon(Iterable rings) 64 | { 65 | super(TYPE, LineString.class, rings); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/Geometry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.io.Serializable; 26 | 27 | import javax.annotation.Nullable; 28 | 29 | import org.eclipse.jdt.annotation.NonNullByDefault; 30 | 31 | /** 32 | * The base class of all geometries 33 | */ 34 | @NonNullByDefault 35 | public abstract class Geometry implements Serializable 36 | { 37 | private static final long serialVersionUID = 0x100; 38 | 39 | /** 40 | * Official UNKNOWN srid value 41 | */ 42 | public static final int UNKNOWN_SRID = 0; 43 | 44 | /** 45 | * The spacial reference system id of this geometry, default is no srid 46 | */ 47 | private int srid = UNKNOWN_SRID; 48 | 49 | /** 50 | * The OGIS geometry type of this feature. this is final as it never changes, it is bound to the subclass of the 51 | * instance. 52 | */ 53 | private final int type; 54 | 55 | // WKB types: 56 | // POINT 1 57 | // LINESTRING 2 58 | // POLYGON 3 59 | // MULTIPOINT 4 60 | // MULTILINESTRING 5 61 | // MULTIPOLYGON 6 62 | // GEOMETRYCOLLECTION 7 63 | // CIRCULARSTRING 8 64 | // COMPOUNDCURVE 9 65 | // CURVEPOLYGON 10 66 | // MULTICURVE 11 67 | // MULTISURFACE 12 68 | // CURVE 13 69 | // SURFACE 14 70 | // POLYHEDRALSURFACE 15 71 | // TIN 16 72 | // TRIANGLE 17 73 | 74 | /** 75 | * Constructor for subclasses. 76 | * @param type has to be given by all subclasses 77 | */ 78 | protected Geometry(int type) 79 | { 80 | this.type = type; 81 | } 82 | 83 | /** 84 | * Do some internal consistency checks on the geometry. Currently, all Geometries must have a valid dimension (2 or 85 | * 3) and a valid type. Composed geometries must have all equal SRID, dimensionality and measures, as well as that 86 | * they do not contain NULL or inconsistent subgeometries. BinaryParser and WKTParser should only generate 87 | * consistent geometries. BinaryWriter may produce invalid results on inconsistent geometries. 88 | * @return true if all checks are passed. 89 | */ 90 | @SuppressWarnings("static-method") 91 | public boolean checkConsistency() 92 | { 93 | // default is a correct geometry 94 | return true; 95 | } 96 | 97 | /** 98 | * java.lang.Object equals implementation 99 | * @param obj geometry to compare 100 | * @return true if equal, false otherwise 101 | */ 102 | @Override 103 | public boolean equals(@Nullable Object obj) 104 | { 105 | // short cut 106 | if (this == obj) 107 | { 108 | return true; 109 | } 110 | // check for type and null 111 | if (!(obj instanceof Geometry)) 112 | { 113 | return false; 114 | } 115 | // check all properties specific to this instance, rest is checked by subclasses 116 | Geometry other = (Geometry) obj; 117 | return (this.type == other.type) && (this.srid == other.srid); 118 | } 119 | 120 | /** 121 | * Gets the coordinates of this {@link Geometry}. 122 | * @return coordinates 123 | */ 124 | public abstract Iterable getCoordinates(); 125 | 126 | /** 127 | * Gets the number of coordinates of this {@link Geometry}. 128 | * @return number of coordinates 129 | */ 130 | public abstract int getNumberOfCoordinates(); 131 | 132 | /** 133 | * The OGIS geometry type number of this geometry. 134 | * @return the SRID of this geometry 135 | */ 136 | public int getSrid() 137 | { 138 | return this.srid; 139 | } 140 | 141 | /** 142 | * Gets the OGIS geometry type number of this geometry. 143 | * @return type of this geometry 144 | */ 145 | public int getType() 146 | { 147 | return this.type; 148 | } 149 | 150 | /* 151 | * (non-Javadoc) 152 | * @see java.lang.Object#hashCode() 153 | */ 154 | @Override 155 | public int hashCode() 156 | { 157 | return 31 * (31 + this.srid) + this.type; 158 | } 159 | 160 | /** 161 | * Returns whether we have a measure (4th dimension) 162 | * @return true if the geometry has a measure, false otherwise 163 | */ 164 | public abstract boolean hasMeasure(); 165 | 166 | /** 167 | * Checks if this {@link Geometry} is 3d. 168 | * @return true on success, else false 169 | */ 170 | public abstract boolean is3d(); 171 | 172 | /** 173 | * Ist this {@link Geometry} empty, so does it contain no coordinates or other geometries? 174 | * @return true on success, else false 175 | */ 176 | public abstract boolean isEmpty(); 177 | 178 | /** 179 | * Recursively sets the srid on this geometry and all contained subgeometries 180 | * @param srid the SRID for this geometry 181 | */ 182 | public void setSrid(int srid) 183 | { 184 | this.srid = srid; 185 | } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/GeometryCollection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * Geometry Collection. 29 | * @author markus.schaber@logix-tt.com 30 | */ 31 | @NonNullByDefault 32 | public class GeometryCollection extends MultiGeometry 33 | { 34 | /* JDK 1.5 Serialization */ 35 | private static final long serialVersionUID = 0x100; 36 | /** 37 | * The OGIS geometry type number for feature collections. 38 | */ 39 | public static final int TYPE = 7; 40 | 41 | /** 42 | * Constructs an instance. 43 | */ 44 | public GeometryCollection() 45 | { 46 | super(TYPE); 47 | } 48 | 49 | /** 50 | * Constructs an instance. 51 | * @param geoms geometries 52 | */ 53 | public GeometryCollection(Iterable geoms) 54 | { 55 | super(TYPE, geoms); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/LineBasedGeometry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import javax.annotation.Nullable; 26 | 27 | /** 28 | * Interface to mark line based geometries. 29 | * @author Sebastian Baumhekel 30 | */ 31 | public interface LineBasedGeometry 32 | { 33 | /** 34 | * Gets the end point. 35 | * @return {@link Point} on success, else null 36 | */ 37 | @Nullable 38 | Point getEndPoint(); 39 | 40 | /** 41 | * Gets the start point. 42 | * @return {@link Point} on success, else null 43 | */ 44 | @Nullable 45 | Point getStartPoint(); 46 | 47 | /** 48 | * Checks if this line is closed, so the last coordinate is the same as the first coordinate. 49 | * @return true on success, else false 50 | */ 51 | boolean isClosed(); 52 | 53 | /** 54 | * Gets the length of this line. 55 | * @return length 56 | */ 57 | double length(); 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/LineString.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Collections; 27 | import java.util.Iterator; 28 | 29 | import javax.annotation.Nullable; 30 | 31 | import org.eclipse.jdt.annotation.NonNullByDefault; 32 | 33 | /** 34 | * Linestring. 35 | * @author Sebastian Baumhekel 36 | */ 37 | @NonNullByDefault 38 | public class LineString extends Curve implements Iterable 39 | { 40 | /* JDK 1.5 Serialization */ 41 | private static final long serialVersionUID = 0x100; 42 | 43 | /** 44 | * The OGIS geometry type number for lines. 45 | */ 46 | public static final int TYPE = 2; 47 | 48 | private final ArrayList points = new ArrayList(); 49 | 50 | /** 51 | * Constructs an instance. 52 | */ 53 | public LineString() 54 | { 55 | super(TYPE); 56 | } 57 | 58 | /** 59 | * Constructor for subclasses. 60 | * @param type has to be given by all subclasses. 61 | */ 62 | protected LineString(int type) 63 | { 64 | super(type); 65 | } 66 | 67 | /** 68 | * Constructor for subclasses. 69 | * @param type has to be given by all subclasses. 70 | * @param points {@link Point}s 71 | */ 72 | protected LineString(int type, Iterable points) 73 | { 74 | super(type); 75 | addAll(points); 76 | } 77 | 78 | /** 79 | * Constructs an instance. 80 | * @param points points 81 | */ 82 | public LineString(Iterable points) 83 | { 84 | super(LineString.TYPE); 85 | addAll(points); 86 | } 87 | 88 | /** 89 | * Adds the given point. 90 | * @param p point 91 | */ 92 | public void add(Point p) 93 | { 94 | points.add(p); 95 | } 96 | 97 | /** 98 | * Adds all given points. 99 | * @param geoms points 100 | */ 101 | public final void addAll(Iterable geoms) 102 | { 103 | for (Point geom : geoms) 104 | { 105 | points.add(geom); 106 | } 107 | } 108 | 109 | @Override 110 | public boolean checkConsistency() 111 | { 112 | if (!super.checkConsistency() || points.isEmpty()) 113 | { 114 | return false; 115 | } 116 | return PostGisUtil.checkConsistency(points); 117 | } 118 | 119 | /** 120 | * Closes this {@link LineString} if the last coordinate is not already the same as the first coordinate. 121 | */ 122 | @Override 123 | public void close() 124 | { 125 | Point pFirst = getStartPoint(); 126 | Point pLast = getEndPoint(); 127 | // check if there is a first point and the last point equals the first one 128 | if ((pFirst != null) && (pLast != null) && !pFirst.coordsAreEqual(pLast)) 129 | { 130 | // add the first point as closing last point 131 | add(pFirst.copy()); 132 | } 133 | } 134 | 135 | @Override 136 | public boolean equals(@Nullable Object other) 137 | { 138 | // check type and parent 139 | if ((other instanceof LineString ls) && super.equals(other)) 140 | { 141 | // check all points 142 | return PostGisUtil.equalsIterable(this.points, ls.points); 143 | } 144 | return false; 145 | } 146 | 147 | /* 148 | * (non-Javadoc) 149 | * @see io.github.sebasbaumh.postgis.Geometry#getCoordinates() 150 | */ 151 | @Override 152 | public Iterable getCoordinates() 153 | { 154 | return this.points; 155 | } 156 | 157 | /* 158 | * (non-Javadoc) 159 | * @see io.github.sebasbaumh.postgis.LineBasedGeometry#getEndPoint() 160 | */ 161 | @Nullable 162 | @Override 163 | public Point getEndPoint() 164 | { 165 | return PostGisUtil.lastOrDefault(points); 166 | } 167 | 168 | /* 169 | * (non-Javadoc) 170 | * @see io.github.sebasbaumh.postgis.Geometry#getNumberOfCoordinates() 171 | */ 172 | @Override 173 | public int getNumberOfCoordinates() 174 | { 175 | return this.points.size(); 176 | } 177 | 178 | /* 179 | * (non-Javadoc) 180 | * @see io.github.sebasbaumh.postgis.LineBasedGeometry#getStartPoint() 181 | */ 182 | @Nullable 183 | @Override 184 | public Point getStartPoint() 185 | { 186 | return PostGisUtil.firstOrDefault(points); 187 | } 188 | 189 | @Override 190 | public int hashCode() 191 | { 192 | return 31 * super.hashCode() + points.hashCode(); 193 | } 194 | 195 | /* 196 | * (non-Javadoc) 197 | * @see io.github.sebasbaumh.postgis.Geometry#hasMeasure() 198 | */ 199 | @Override 200 | public boolean hasMeasure() 201 | { 202 | for (Point geom : points) 203 | { 204 | if (geom.hasMeasure()) 205 | { 206 | return true; 207 | } 208 | } 209 | return false; 210 | } 211 | 212 | /* 213 | * (non-Javadoc) 214 | * @see io.github.sebasbaumh.postgis.Geometry#is3d() 215 | */ 216 | @Override 217 | public boolean is3d() 218 | { 219 | for (Point geom : points) 220 | { 221 | if (geom.is3d()) 222 | { 223 | return true; 224 | } 225 | } 226 | return false; 227 | } 228 | 229 | /* 230 | * (non-Javadoc) 231 | * @see io.github.sebasbaumh.postgis.Geometry#isEmpty() 232 | */ 233 | @Override 234 | public boolean isEmpty() 235 | { 236 | return this.points.isEmpty(); 237 | } 238 | 239 | /* 240 | * (non-Javadoc) 241 | * @see java.lang.Iterable#iterator() 242 | */ 243 | @Override 244 | public Iterator iterator() 245 | { 246 | return this.points.iterator(); 247 | } 248 | 249 | @Override 250 | public double length() 251 | { 252 | double len = 0; 253 | if (points.size() > 1) 254 | { 255 | Point p0 = points.get(0); 256 | for (int i = 1; i < points.size(); i++) 257 | { 258 | Point p = points.get(i); 259 | len += p0.distance(p); 260 | p0 = p; 261 | } 262 | } 263 | return len; 264 | } 265 | 266 | /** 267 | * Reverses this linestring. 268 | */ 269 | @Override 270 | public void reverse() 271 | { 272 | Collections.reverse(this.points); 273 | } 274 | 275 | } 276 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/LinearRing.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * This represents the LinearRing GIS datatype. This type is used to construct the polygon types, but is not stored or 29 | * retrieved directly from the database. 30 | */ 31 | @NonNullByDefault 32 | public class LinearRing extends LineString 33 | { 34 | private static final long serialVersionUID = 0x100; 35 | // Fake type for linear ring 36 | private static final int TYPE = 0; 37 | 38 | /** 39 | * Constructs an instance. 40 | */ 41 | public LinearRing() 42 | { 43 | super(LinearRing.TYPE); 44 | } 45 | 46 | /** 47 | * Constructs an instance. 48 | * @param points points 49 | */ 50 | public LinearRing(Iterable points) 51 | { 52 | super(LinearRing.TYPE, points); 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/MultiCurve.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * The MULTICURVE is a collection of curves, which can include linear strings, circular strings or compound strings. It 29 | * only specifies a type of {@link Geometry} as it could contain {@link LineString}s and {@link CompoundCurve}s. 30 | * @author Sebastian Baumhekel 31 | */ 32 | @NonNullByDefault 33 | public class MultiCurve extends MultiGeometry 34 | { 35 | /* JDK 1.5 Serialization */ 36 | private static final long serialVersionUID = 0x100; 37 | /** 38 | * The OGIS geometry type number for aggregate curves, which can include linear strings, circular strings or 39 | * compound strings. 40 | */ 41 | public static final int TYPE = 11; 42 | 43 | /** 44 | * Constructs an instance. 45 | */ 46 | public MultiCurve() 47 | { 48 | super(TYPE); 49 | } 50 | 51 | /** 52 | * Constructs an instance. 53 | * @param lines lines 54 | * @throws IllegalArgumentException if given lines are not of a curve type 55 | */ 56 | public MultiCurve(Iterable lines) 57 | { 58 | super(TYPE); 59 | for (Curve geom : lines) 60 | { 61 | add(geom); 62 | } 63 | } 64 | 65 | /** 66 | * Gets the length of this line. 67 | * @return length 68 | */ 69 | public double length() 70 | { 71 | double d = 0; 72 | for (Geometry ls : subgeoms) 73 | { 74 | if (ls instanceof LineBasedGeometry lbg) 75 | { 76 | d += lbg.length(); 77 | } 78 | } 79 | return d; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/MultiGeometry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Collection; 27 | import java.util.Iterator; 28 | 29 | import javax.annotation.Nullable; 30 | 31 | import org.eclipse.jdt.annotation.NonNullByDefault; 32 | 33 | /** 34 | * Base class for multi geometries. 35 | * @author Sebastian Baumhekel 36 | * @param {@link Geometry} type 37 | */ 38 | @NonNullByDefault 39 | public abstract class MultiGeometry extends Geometry implements Iterable 40 | { 41 | /* JDK 1.5 Serialization */ 42 | private static final long serialVersionUID = 0x100; 43 | 44 | /** 45 | * Sub geometries. 46 | */ 47 | protected final ArrayList subgeoms = new ArrayList(); 48 | 49 | /** 50 | * Constructs an instance with the specified type. 51 | * @param type int value corresponding to the geometry type 52 | */ 53 | protected MultiGeometry(int type) 54 | { 55 | super(type); 56 | } 57 | 58 | /** 59 | * Constructs an instance with the specified type and geometries. 60 | * @param type int value corresponding to the geometry type 61 | * @param geoms geometries 62 | */ 63 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("PCOA_PARTIALLY_CONSTRUCTED_OBJECT_ACCESS") 64 | protected MultiGeometry(int type, Iterable geoms) 65 | { 66 | this(type); 67 | this.addAll(geoms); 68 | } 69 | 70 | /** 71 | * Adds a geometry. 72 | * @param geom geometry 73 | */ 74 | public void add(T geom) 75 | { 76 | subgeoms.add(geom); 77 | } 78 | 79 | /** 80 | * Adds all given geometries. 81 | * @param geoms geometries 82 | */ 83 | public void addAll(Iterable geoms) 84 | { 85 | for (T geom : geoms) 86 | { 87 | subgeoms.add(geom); 88 | } 89 | } 90 | 91 | @Override 92 | public boolean checkConsistency() 93 | { 94 | if (!super.checkConsistency() || subgeoms.isEmpty()) 95 | { 96 | return false; 97 | } 98 | return PostGisUtil.checkConsistency(subgeoms); 99 | } 100 | 101 | @Override 102 | public boolean equals(@Nullable Object other) 103 | { 104 | // check type and parent 105 | if ((other instanceof MultiGeometry cother) && super.equals(other)) 106 | { 107 | return PostGisUtil.equalsIterable(this.subgeoms, cother.subgeoms); 108 | } 109 | return false; 110 | } 111 | 112 | /* 113 | * (non-Javadoc) 114 | * @see io.github.sebasbaumh.postgis.Geometry#getCoordinates() 115 | */ 116 | @Override 117 | public Iterable getCoordinates() 118 | { 119 | ArrayList l = new ArrayList(); 120 | for (T geom : subgeoms) 121 | { 122 | for (Point p : geom.getCoordinates()) 123 | { 124 | l.add(p); 125 | } 126 | } 127 | return l; 128 | } 129 | 130 | /** 131 | * Gets all geometries. 132 | * @return geometries 133 | */ 134 | public Collection getGeometries() 135 | { 136 | return subgeoms; 137 | } 138 | 139 | /* 140 | * (non-Javadoc) 141 | * @see io.github.sebasbaumh.postgis.Geometry#getNumberOfCoordinates() 142 | */ 143 | @Override 144 | public int getNumberOfCoordinates() 145 | { 146 | int n = 0; 147 | for (T geom : subgeoms) 148 | { 149 | n += geom.getNumberOfCoordinates(); 150 | } 151 | return n; 152 | } 153 | 154 | @Override 155 | public int hashCode() 156 | { 157 | return 31 * super.hashCode() + subgeoms.hashCode(); 158 | } 159 | 160 | /* 161 | * (non-Javadoc) 162 | * @see io.github.sebasbaumh.postgis.Geometry#hasMeasure() 163 | */ 164 | @Override 165 | public boolean hasMeasure() 166 | { 167 | for (T geom : subgeoms) 168 | { 169 | if (geom.hasMeasure()) 170 | { 171 | return true; 172 | } 173 | } 174 | return false; 175 | } 176 | 177 | /* 178 | * (non-Javadoc) 179 | * @see io.github.sebasbaumh.postgis.Geometry#is3d() 180 | */ 181 | @Override 182 | public boolean is3d() 183 | { 184 | for (T geom : subgeoms) 185 | { 186 | if (geom.is3d()) 187 | { 188 | return true; 189 | } 190 | } 191 | return false; 192 | } 193 | 194 | /** 195 | * Checks, if there are no sub-geometries. 196 | * @return true on success, else false 197 | */ 198 | @Override 199 | public boolean isEmpty() 200 | { 201 | return subgeoms.isEmpty(); 202 | } 203 | 204 | /* 205 | * (non-Javadoc) 206 | * @see java.lang.Iterable#iterator() 207 | */ 208 | @Override 209 | public Iterator iterator() 210 | { 211 | return subgeoms.iterator(); 212 | } 213 | 214 | @Override 215 | public void setSrid(int srid) 216 | { 217 | super.setSrid(srid); 218 | for (T geom : subgeoms) 219 | { 220 | geom.setSrid(srid); 221 | } 222 | } 223 | 224 | /** 225 | * Gets the number of contained geometries. 226 | * @return number of contained geometries 227 | */ 228 | public int size() 229 | { 230 | return this.subgeoms.size(); 231 | } 232 | 233 | /* 234 | * (non-Javadoc) 235 | * @see java.lang.Object#toString() 236 | */ 237 | @Override 238 | public String toString() 239 | { 240 | return this.getClass().getSimpleName() + " [" + this.size() + " geometries]"; 241 | } 242 | 243 | } 244 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/MultiLineString.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * A multi line. 29 | * @author Sebastian Baumhekel 30 | */ 31 | @NonNullByDefault 32 | public class MultiLineString extends MultiGeometry 33 | { 34 | /* JDK 1.5 Serialization */ 35 | private static final long serialVersionUID = 0x100; 36 | /** 37 | * The OGIS geometry type number for aggregate lines. 38 | */ 39 | public static final int TYPE = 5; 40 | 41 | /** 42 | * Constructs an instance. 43 | */ 44 | public MultiLineString() 45 | { 46 | super(TYPE); 47 | } 48 | 49 | /** 50 | * Constructs an instance. 51 | * @param lines lines 52 | */ 53 | public MultiLineString(Iterable lines) 54 | { 55 | super(TYPE, lines); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/MultiPoint.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * A multi point. 29 | * @author Sebastian Baumhekel 30 | */ 31 | @NonNullByDefault 32 | public class MultiPoint extends MultiGeometry 33 | { 34 | /* JDK 1.5 Serialization */ 35 | private static final long serialVersionUID = 0x100; 36 | /** 37 | * The OGIS geometry type number for aggregate points. 38 | */ 39 | public static final int TYPE = 4; 40 | 41 | /** 42 | * Constructs an instance. 43 | */ 44 | public MultiPoint() 45 | { 46 | super(TYPE); 47 | } 48 | 49 | /** 50 | * Constructs an instance. 51 | * @param points points 52 | */ 53 | public MultiPoint(Iterable points) 54 | { 55 | super(TYPE, points); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/MultiPolygon.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * A multi polygon. 29 | * @author Sebastian Baumhekel 30 | */ 31 | @NonNullByDefault 32 | public class MultiPolygon extends MultiGeometry 33 | { 34 | /* JDK 1.5 Serialization */ 35 | private static final long serialVersionUID = 0x100; 36 | /** 37 | * The OGIS geometry type number for aggregate polygons. 38 | */ 39 | public static final int TYPE = 6; 40 | 41 | /** 42 | * Constructs an instance. 43 | */ 44 | public MultiPolygon() 45 | { 46 | super(TYPE); 47 | } 48 | 49 | /** 50 | * Constructs an instance. 51 | * @param polygons polygons 52 | */ 53 | public MultiPolygon(Iterable polygons) 54 | { 55 | super(TYPE, polygons); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/MultiSurface.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * The MULTISURFACE is a collection of surfaces, which can be (linear) polygons or curve polygons. 29 | * @author Sebastian Baumhekel 30 | */ 31 | @NonNullByDefault 32 | public class MultiSurface extends MultiGeometry> 33 | { 34 | private static final long serialVersionUID = 0x100; 35 | /** 36 | * The OGIS geometry type number for multi surfaces, which can be (linear) polygons or curve polygons. 37 | */ 38 | public static final int TYPE = 12; 39 | 40 | /** 41 | * Constructs an instance. 42 | */ 43 | public MultiSurface() 44 | { 45 | super(TYPE); 46 | } 47 | 48 | /** 49 | * Constructs an instance. 50 | * @param lines lines 51 | */ 52 | public > MultiSurface(Iterable lines) 53 | { 54 | super(TYPE); 55 | for (T geom : lines) 56 | { 57 | add(geom); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/PGbox2d.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.SQLException; 26 | 27 | import org.postgresql.util.PGobject; 28 | 29 | /** 30 | * BOX2D representing the maximum extents of the geometry. 31 | * @author Sebastian Baumhekel 32 | */ 33 | public class PGbox2d extends PGboxbase 34 | { 35 | /** 36 | * Type of the {@link PGobject}. 37 | */ 38 | private static final String PG_TYPE = "box2d"; 39 | /* JDK 1.5 Serialization */ 40 | private static final long serialVersionUID = 0x100; 41 | 42 | /** 43 | * Constructs an instance. 44 | */ 45 | public PGbox2d() 46 | { 47 | super(PG_TYPE); 48 | } 49 | 50 | /** 51 | * Constructs an instance. 52 | * @param llb lower-left point 53 | * @param urt upper-right point 54 | */ 55 | public PGbox2d(Point llb, Point urt) 56 | { 57 | super(PG_TYPE, llb, urt); 58 | } 59 | 60 | /** 61 | * Constructs an instance. 62 | * @param value WKT 63 | * @throws SQLException 64 | */ 65 | public PGbox2d(String value) throws SQLException 66 | { 67 | super(PG_TYPE, value); 68 | } 69 | 70 | @Override 71 | public PGbox2d clone() throws CloneNotSupportedException 72 | { 73 | return (PGbox2d)super.clone(); 74 | } 75 | 76 | @Override 77 | public String getPrefix() 78 | { 79 | return "BOX"; 80 | } 81 | 82 | @Override 83 | public boolean is3d() 84 | { 85 | return false; 86 | } 87 | 88 | @Override 89 | public void setValue(String value) throws SQLException 90 | { 91 | super.setValue(value); 92 | // force 2 dimensions 93 | if (llb.is3d()) 94 | { 95 | llb = llb.to2d(); 96 | } 97 | if (urt.is3d()) 98 | { 99 | urt = urt.to2d(); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/PGbox3d.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.SQLException; 26 | 27 | import org.postgresql.util.PGobject; 28 | 29 | /** 30 | * BOX3D representing the maximum extents of the geometry. 31 | * @author Sebastian Baumhekel 32 | */ 33 | public class PGbox3d extends PGboxbase 34 | { 35 | /** 36 | * Type of the {@link PGobject}. 37 | */ 38 | private static final String PG_TYPE = "box3d"; 39 | /* JDK 1.5 Serialization */ 40 | private static final long serialVersionUID = 0x100; 41 | 42 | /** 43 | * Constructs an instance. 44 | */ 45 | public PGbox3d() 46 | { 47 | super(PG_TYPE); 48 | } 49 | 50 | /** 51 | * Constructs an instance. 52 | * @param llb lower-left point 53 | * @param urt upper-right point 54 | */ 55 | public PGbox3d(Point llb, Point urt) 56 | { 57 | super(PG_TYPE, llb, urt); 58 | } 59 | 60 | /** 61 | * Constructs an instance. 62 | * @param value WKT 63 | * @throws SQLException 64 | */ 65 | public PGbox3d(String value) throws SQLException 66 | { 67 | super(PG_TYPE, value); 68 | } 69 | 70 | @Override 71 | public PGbox3d clone() throws CloneNotSupportedException 72 | { 73 | return (PGbox3d)super.clone(); 74 | } 75 | 76 | @Override 77 | public String getPrefix() 78 | { 79 | return "BOX3D"; 80 | } 81 | 82 | @Override 83 | public boolean is3d() 84 | { 85 | return true; 86 | } 87 | 88 | /** 89 | * Gets this {@link Point} as a 2d object. 90 | * @return {@link Point} 91 | */ 92 | public PGbox2d to2d() 93 | { 94 | return new PGbox2d(llb.to2d(), urt.to2d()); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/PGboxbase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.SQLException; 26 | import java.util.List; 27 | import java.util.Objects; 28 | 29 | import javax.annotation.Nonnull; 30 | import javax.annotation.Nullable; 31 | 32 | import org.eclipse.jdt.annotation.DefaultLocation; 33 | import org.eclipse.jdt.annotation.NonNullByDefault; 34 | import org.postgresql.util.PGobject; 35 | 36 | /** 37 | * Base class for bounding boxes. 38 | * @author Sebastian Baumhekel 39 | */ 40 | @NonNullByDefault({ DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE }) 41 | public abstract class PGboxbase extends PGobject 42 | { 43 | /* JDK 1.5 Serialization */ 44 | private static final long serialVersionUID = 0x100; 45 | 46 | /** 47 | * The lower left bottom corner of the box. 48 | */ 49 | protected Point llb; 50 | 51 | /** 52 | * The upper right top corner of the box. 53 | */ 54 | protected Point urt; 55 | 56 | /** 57 | * Constructs an instance. 58 | * @param type type of this {@link PGobject} 59 | */ 60 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings({ "PCOA_PARTIALLY_CONSTRUCTED_OBJECT_ACCESS", 61 | "NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" }) 62 | protected PGboxbase(String type) 63 | { 64 | this.setType(type); 65 | } 66 | 67 | /** 68 | * Constructs an instance. 69 | * @param type type of this {@link PGobject} 70 | * @param llb lower left {@link Point} 71 | * @param urt upper right {@link Point} 72 | */ 73 | protected PGboxbase(String type, Point llb, Point urt) 74 | { 75 | this.setType(type); 76 | this.llb = llb; 77 | this.urt = urt; 78 | } 79 | 80 | /** 81 | * Constructs an instance. 82 | * @param type type of this {@link PGobject} 83 | * @param value WKT 84 | * @throws SQLException 85 | */ 86 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings({ "PCOA_PARTIALLY_CONSTRUCTED_OBJECT_ACCESS", 87 | "NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" }) 88 | protected PGboxbase(String type, String value) throws SQLException 89 | { 90 | this.setType(type); 91 | setValue(value); 92 | } 93 | 94 | /** 95 | * Appends a double value to a {@link StringBuilder}. In contrast to {@link StringBuilder#append(double)} it omits a 96 | * 0 decimal like "1.0" it will output "1". 97 | * @param sb {@link StringBuilder} 98 | * @param d double 99 | */ 100 | private static void appendDouble(StringBuilder sb, double d) 101 | { 102 | // check for fractional digits (or if the double exceeds the long range) 103 | if (((d % 1.0) != 0) || (d >= Long.MAX_VALUE) || (d <= Long.MIN_VALUE)) 104 | { 105 | sb.append(d); 106 | } 107 | else 108 | { 109 | // omit 0-digit 110 | sb.append((long) d); 111 | } 112 | } 113 | 114 | /** 115 | * Converts a point to an inner WKT string like "1 2" or "1 2 3". 116 | * @param sb {@link StringBuilder} 117 | * @param p {@link Point} 118 | */ 119 | private static void appendPoint(StringBuilder sb, Point p) 120 | { 121 | PGboxbase.appendDouble(sb, p.getX()); 122 | sb.append(' '); 123 | PGboxbase.appendDouble(sb, p.getY()); 124 | if (p.is3d()) 125 | { 126 | sb.append(' '); 127 | PGboxbase.appendDouble(sb, p.getZ()); 128 | } 129 | } 130 | 131 | /** 132 | * Gets a point from an inner WKT string like "1 2" or "1 2 3". 133 | * @param wkt WKT 134 | * @return {@link Point} on success, else null 135 | * @throws NumberFormatException if a coordinate is invalid 136 | */ 137 | private static Point pointFromWKT(String wkt) 138 | { 139 | List tokens = PostGisUtil.split(wkt.trim(), ' '); 140 | double x = Double.parseDouble(tokens.get(0)); 141 | double y = Double.parseDouble(tokens.get(1)); 142 | // 3d? 143 | if (tokens.size() == 3) 144 | { 145 | double z = Double.parseDouble(tokens.get(2)); 146 | return new Point(x, y, z); 147 | } 148 | return new Point(x, y); 149 | } 150 | 151 | @Override 152 | public PGboxbase clone() throws CloneNotSupportedException 153 | { 154 | PGboxbase o = (PGboxbase) super.clone(); 155 | o.setType(this.getType()); 156 | o.llb = llb.copy(); 157 | o.urt = urt.copy(); 158 | return o; 159 | } 160 | 161 | @Override 162 | public boolean equals(@Nullable Object obj) 163 | { 164 | // short cut 165 | if (this == obj) 166 | { 167 | return true; 168 | } 169 | // check for type and null 170 | if (!(obj instanceof PGboxbase)) 171 | { 172 | return false; 173 | } 174 | PGboxbase otherbox = (PGboxbase) obj; 175 | // Compare two coordinates. As the Server always returns Box3D with three dimensions, z==0 equals dimensions==2 176 | return (this.llb.coordsAreEqual(otherbox.llb) && this.urt.coordsAreEqual(otherbox.urt)); 177 | } 178 | 179 | /** 180 | * Returns the lower left bottom corner of the box as a Point object 181 | * @return lower left bottom corner of this box 182 | */ 183 | public Point getLLB() 184 | { 185 | return llb; 186 | } 187 | 188 | /** 189 | * The Prefix we have in WKT rep. I use an abstract method here so we do not need to replicate the String object in 190 | * every instance. 191 | * @return the prefix, as a string 192 | */ 193 | protected abstract String getPrefix(); 194 | 195 | /** 196 | * The OGIS geometry type number of this geometry. 197 | * @return the SRID of this geometry 198 | */ 199 | public int getSrid() 200 | { 201 | return this.llb.getSrid(); 202 | } 203 | 204 | /** 205 | * Returns the upper right top corner of the box as a Point object 206 | * @return upper right top corner of this box 207 | */ 208 | public Point getURT() 209 | { 210 | return urt; 211 | } 212 | 213 | @Nonnull 214 | @Override 215 | public String getValue() 216 | { 217 | StringBuilder sb = new StringBuilder(); 218 | // add SRID? 219 | int srid = getSrid(); 220 | if (srid != Geometry.UNKNOWN_SRID) 221 | { 222 | sb.append("SRID="); 223 | sb.append(srid); 224 | sb.append(';'); 225 | } 226 | // write prefix and points 227 | sb.append(getPrefix()); 228 | sb.append('('); 229 | PGboxbase.appendPoint(sb, llb); 230 | sb.append(','); 231 | PGboxbase.appendPoint(sb, urt); 232 | sb.append(')'); 233 | return sb.toString(); 234 | } 235 | 236 | @Override 237 | public int hashCode() 238 | { 239 | return Objects.hash(llb, urt); 240 | } 241 | 242 | /** 243 | * Checks if this box is 3d. 244 | * @return true on success, else false 245 | */ 246 | public abstract boolean is3d(); 247 | 248 | /** 249 | * Ist this box empty, so does it contain no coordinates? 250 | * @return true on success, else false 251 | */ 252 | public boolean isEmpty() 253 | { 254 | return llb.isEmpty() && urt.isEmpty(); 255 | } 256 | 257 | /** 258 | * Recursively sets the srid on this geometry and all contained subgeometries 259 | * @param srid the SRID for this geometry 260 | */ 261 | public void setSrid(int srid) 262 | { 263 | this.llb.setSrid(srid); 264 | this.urt.setSrid(srid); 265 | } 266 | 267 | @Override 268 | public void setValue(@SuppressWarnings("null") @Nonnull String value) throws SQLException 269 | { 270 | try 271 | { 272 | int srid = Geometry.UNKNOWN_SRID; 273 | value = value.trim(); 274 | if (value.startsWith("SRID=")) 275 | { 276 | int index = value.indexOf(';', 5); // sridprefix length is 5 277 | if (index < 0) 278 | { 279 | throw new SQLException("Error parsing Geometry - SRID not delimited with ';' "); 280 | } 281 | String sSrid = value.substring(5, index); 282 | value = value.substring(index + 1).trim(); 283 | srid = Integer.parseInt(sSrid); 284 | // ensure valid SRID 285 | if (srid < 0) 286 | { 287 | srid = Geometry.UNKNOWN_SRID; 288 | } 289 | } 290 | String myPrefix = getPrefix(); 291 | if (value.startsWith(myPrefix)) 292 | { 293 | value = value.substring(myPrefix.length()).trim(); 294 | } 295 | String valueNoParans = PostGisUtil.removeBrackets(value); 296 | List tokens = PostGisUtil.split(valueNoParans, ','); 297 | llb = PGboxbase.pointFromWKT(tokens.get(0)); 298 | urt = PGboxbase.pointFromWKT(tokens.get(1)); 299 | if (srid != Geometry.UNKNOWN_SRID) 300 | { 301 | llb.setSrid(srid); 302 | urt.setSrid(srid); 303 | } 304 | } 305 | catch (NumberFormatException | IndexOutOfBoundsException ex) 306 | { 307 | throw new SQLException("Error parsing Point: " + ex.getMessage(), ex); 308 | } 309 | } 310 | 311 | /** 312 | * Unlike geometries, toString() does _not_ contain the srid, as server-side PostGIS cannot parse this. 313 | * @return String representation of this box 314 | */ 315 | @Override 316 | public String toString() 317 | { 318 | return getValue(); 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/PGgeography.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.SQLException; 26 | 27 | import org.postgresql.util.PGobject; 28 | 29 | /** 30 | * Geometry class for geographic geometries. 31 | * @author Sebastian Baumhekel 32 | */ 33 | public class PGgeography extends PGgeometrybase 34 | { 35 | /** 36 | * Type of the {@link PGobject}. 37 | */ 38 | private static final String PG_TYPE = "geography"; 39 | /* JDK 1.5 Serialization */ 40 | private static final long serialVersionUID = 0x100; 41 | 42 | /** 43 | * Constructs an instance. 44 | */ 45 | public PGgeography() 46 | { 47 | super(PG_TYPE); 48 | } 49 | 50 | /** 51 | * Constructs an instance. 52 | * @param geom {@link Geometry} 53 | */ 54 | public PGgeography(Geometry geom) 55 | { 56 | super(PG_TYPE, geom); 57 | } 58 | 59 | /** 60 | * Constructs an instance. 61 | * @param value geometry 62 | * @throws SQLException 63 | */ 64 | public PGgeography(String value) throws SQLException 65 | { 66 | super(PG_TYPE, value); 67 | } 68 | 69 | @Override 70 | public PGgeography clone() throws CloneNotSupportedException 71 | { 72 | return (PGgeography) super.clone(); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/PGgeometry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.SQLException; 26 | 27 | import org.postgresql.util.PGobject; 28 | 29 | /** 30 | * Geometry class. 31 | * @author Sebastian Baumhekel 32 | */ 33 | public class PGgeometry extends PGgeometrybase 34 | { 35 | /** 36 | * Type of the {@link PGobject}. 37 | */ 38 | private static final String PG_TYPE = "geometry"; 39 | /* JDK 1.5 Serialization */ 40 | private static final long serialVersionUID = 0x100; 41 | 42 | /** 43 | * Constructs an instance. 44 | */ 45 | public PGgeometry() 46 | { 47 | super(PG_TYPE); 48 | } 49 | 50 | /** 51 | * Constructs an instance. 52 | * @param geom {@link Geometry} 53 | */ 54 | public PGgeometry(Geometry geom) 55 | { 56 | super(PG_TYPE, geom); 57 | } 58 | 59 | /** 60 | * Constructs an instance. 61 | * @param value geometry 62 | * @throws SQLException 63 | */ 64 | public PGgeometry(String value) throws SQLException 65 | { 66 | super(PG_TYPE, value); 67 | } 68 | 69 | @Override 70 | public PGgeometry clone() throws CloneNotSupportedException 71 | { 72 | return (PGgeometry) super.clone(); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/PGgeometrybase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.SQLException; 26 | import java.util.Objects; 27 | 28 | import javax.annotation.Nonnull; 29 | import javax.annotation.Nullable; 30 | 31 | import org.eclipse.jdt.annotation.DefaultLocation; 32 | import org.eclipse.jdt.annotation.NonNullByDefault; 33 | import org.postgresql.util.PGBinaryObject; 34 | import org.postgresql.util.PGobject; 35 | 36 | import io.github.sebasbaumh.postgis.binary.BinaryParser; 37 | import io.github.sebasbaumh.postgis.binary.BinaryWriter; 38 | 39 | /** 40 | * A PostgreSQL JDBC {@link PGobject} extension data type modeling a "geo" type. This class serves as a common 41 | * superclass for classes such as {@link PGgeometry} and {@link PGgeography} which model more specific type semantics. 42 | * @author Phillip Ross 43 | */ 44 | @NonNullByDefault({ DefaultLocation.PARAMETER, DefaultLocation.RETURN_TYPE }) 45 | public abstract class PGgeometrybase extends PGobject implements PGBinaryObject 46 | { 47 | /* JDK 1.5 Serialization */ 48 | private static final long serialVersionUID = 0x100; 49 | 50 | /** 51 | * Underlying geometry. 52 | */ 53 | @Nullable 54 | protected Geometry geometry; 55 | 56 | /** 57 | * Geometry data as bytes. 58 | */ 59 | @Nullable 60 | private byte[] geometryData; 61 | 62 | /** 63 | * Constructs an instance. 64 | * @param type type of this {@link PGobject} 65 | */ 66 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR") 67 | protected PGgeometrybase(String type) 68 | { 69 | this.setType(type); 70 | } 71 | 72 | /** 73 | * Constructs an instance. 74 | * @param type type of this {@link PGobject} 75 | * @param geom {@link Geometry} 76 | */ 77 | protected PGgeometrybase(String type, Geometry geom) 78 | { 79 | this.setType(type); 80 | this.geometry = geom; 81 | } 82 | 83 | /** 84 | * Constructs an instance. 85 | * @param type type of this {@link PGobject} 86 | * @param value geometry 87 | * @throws SQLException 88 | */ 89 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings({ "PCOA_PARTIALLY_CONSTRUCTED_OBJECT_ACCESS", 90 | "NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR" }) 91 | protected PGgeometrybase(String type, String value) throws SQLException 92 | { 93 | this.setType(type); 94 | setValue(value); 95 | } 96 | 97 | @Override 98 | public PGgeometrybase clone() throws CloneNotSupportedException 99 | { 100 | PGgeometrybase o = (PGgeometrybase) super.clone(); 101 | o.setType(this.getType()); 102 | o.setGeometry(this.getGeometry()); 103 | return o; 104 | } 105 | 106 | @Override 107 | public boolean equals(@Nullable Object obj) 108 | { 109 | if (this == obj) 110 | { 111 | return true; 112 | } 113 | if (!(obj instanceof PGgeometrybase)) 114 | { 115 | return false; 116 | } 117 | PGgeometrybase other = (PGgeometrybase) obj; 118 | return Objects.equals(this.geometry, other.geometry); 119 | } 120 | 121 | /** 122 | * Gets the binary value. 123 | * @return binary value on success, else null 124 | */ 125 | @Nullable 126 | private byte[] getBinaryValue() 127 | { 128 | // short cut 129 | if (this.geometryData != null) 130 | { 131 | return this.geometryData; 132 | } 133 | // check if geometry is there 134 | if (this.geometry != null) 135 | { 136 | // build geometry data and remember it 137 | byte[] data = BinaryWriter.writeBinary(geometry); 138 | this.geometryData = data; 139 | return data; 140 | } 141 | // no geometry 142 | return null; 143 | } 144 | 145 | /** 146 | * Gets the underlying {@link Geometry}. 147 | * @return {@link Geometry} on success, else null 148 | */ 149 | @Nullable 150 | public Geometry getGeometry() 151 | { 152 | return geometry; 153 | } 154 | 155 | @Nullable 156 | @Override 157 | public String getValue() 158 | { 159 | if (geometry != null) 160 | { 161 | return BinaryWriter.writeHexed(geometry); 162 | } 163 | return null; 164 | } 165 | 166 | @Override 167 | public int hashCode() 168 | { 169 | return Objects.hashCode(geometry); 170 | } 171 | 172 | @Override 173 | public int lengthInBytes() 174 | { 175 | byte[] data = getBinaryValue(); 176 | if (data != null) 177 | { 178 | return data.length; 179 | } 180 | // no geometry 181 | return 0; 182 | } 183 | 184 | @Override 185 | public void setByteValue(@SuppressWarnings("null") byte[] value, int offset) throws SQLException 186 | { 187 | // parse the given bytes 188 | this.geometry = BinaryParser.parse(value, offset); 189 | } 190 | 191 | /** 192 | * Sets the underlying {@link Geometry}. 193 | * @param newgeom {@link Geometry} (can be null) 194 | */ 195 | public void setGeometry(@Nullable Geometry newgeom) 196 | { 197 | this.geometry = newgeom; 198 | // reset binary data 199 | this.geometryData = null; 200 | } 201 | 202 | @Override 203 | public void setValue(@SuppressWarnings("null") @Nonnull String value) throws SQLException 204 | { 205 | this.geometry = BinaryParser.parse(value); 206 | // reset binary data 207 | this.geometryData = null; 208 | } 209 | 210 | @Override 211 | public void toBytes(@SuppressWarnings("null") byte[] bytes, int offset) 212 | { 213 | byte[] data = getBinaryValue(); 214 | if (data != null) 215 | { 216 | // make sure array is large enough 217 | if ((bytes.length - offset) <= data.length) 218 | { 219 | // copy data 220 | System.arraycopy(data, 0, bytes, offset, data.length); 221 | } 222 | else 223 | { 224 | throw new IllegalArgumentException( 225 | "byte array is too small, expected: " + data.length + " got: " + (bytes.length - offset)); 226 | } 227 | } 228 | else 229 | { 230 | throw new IllegalStateException("no geometry has been set"); 231 | } 232 | } 233 | 234 | @Override 235 | public String toString() 236 | { 237 | return String.valueOf(geometry); 238 | } 239 | 240 | } 241 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/Point.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.util.Collections; 26 | import java.util.Objects; 27 | 28 | import javax.annotation.Nullable; 29 | 30 | import org.eclipse.jdt.annotation.NonNullByDefault; 31 | 32 | /** 33 | * Point geometry. 34 | * @author Sebastian Baumhekel 35 | */ 36 | @NonNullByDefault 37 | public class Point extends Geometry 38 | { 39 | private static final long serialVersionUID = 0x100; 40 | 41 | /** 42 | * The OGIS geometry type number for points. 43 | */ 44 | public static final int TYPE = 1; 45 | 46 | /** 47 | * The measure of the point. 48 | */ 49 | private double m; 50 | 51 | /** 52 | * The X coordinate of the point. In most long/lat systems, this is the longitude. 53 | */ 54 | private double x; 55 | 56 | /** 57 | * The Y coordinate of the point. In most long/lat systems, this is the latitude. 58 | */ 59 | private double y; 60 | 61 | /** 62 | * The Z coordinate of the point. In most long/lat systems, this is a radius from the center of the earth, or the 63 | * height / elevation over the ground. 64 | */ 65 | private double z; 66 | 67 | /** 68 | * Constructs an empty instance. 69 | */ 70 | public Point() 71 | { 72 | this(Double.NaN, Double.NaN, Double.NaN, Double.NaN); 73 | } 74 | 75 | /** 76 | * Constructs a new Point 77 | * @param x the longitude / x ordinate 78 | * @param y the latitude / y ordinate 79 | */ 80 | public Point(double x, double y) 81 | { 82 | this(x, y, Double.NaN, Double.NaN); 83 | } 84 | 85 | /** 86 | * Constructs a new Point 87 | * @param x the longitude / x ordinate 88 | * @param y the latitude / y ordinate 89 | * @param z the radius / height / elevation / z ordinate (can be {@link Double#NaN} for no coordinate) 90 | */ 91 | public Point(double x, double y, double z) 92 | { 93 | this(x, y, z, Double.NaN); 94 | } 95 | 96 | /** 97 | * Constructs a new Point 98 | * @param x the longitude / x ordinate 99 | * @param y the latitude / y ordinate 100 | * @param z the radius / height / elevation / z ordinate (can be {@link Double#NaN} for no coordinate) 101 | * @param m measure (4th dimension) 102 | */ 103 | public Point(double x, double y, double z, double m) 104 | { 105 | super(TYPE); 106 | this.x = x; 107 | this.y = y; 108 | this.z = z; 109 | this.m = m; 110 | } 111 | 112 | @Override 113 | public boolean checkConsistency() 114 | { 115 | return super.checkConsistency() && !Double.isNaN(this.x) && !Double.isNaN(this.y); 116 | } 117 | 118 | /** 119 | * Checks it the coordinates of the given {@link Point} are equal to this {@link Point}. 120 | * @param other {@link Point} 121 | * @return true on success, else false 122 | */ 123 | public boolean coordsAreEqual(Point other) 124 | { 125 | return PostGisUtil.equalsDouble(x, other.x) && PostGisUtil.equalsDouble(y, other.y) 126 | && (!is3d() || PostGisUtil.equalsDouble(z, other.z)) 127 | && (!hasMeasure() || PostGisUtil.equalsDouble(m, other.m)); 128 | } 129 | 130 | /** 131 | * Creates a copy of this {@link Point}. 132 | * @return {@link Point} 133 | */ 134 | public Point copy() 135 | { 136 | Point p = new Point(this.x, this.y, this.z, this.m); 137 | p.setSrid(getSrid()); 138 | return p; 139 | } 140 | 141 | /** 142 | * Calculates the distance to the given {@link Point}. 143 | * @param p {@link Point} 144 | * @return distance 145 | */ 146 | public double distance(Point p) 147 | { 148 | double dX = (p.x - this.x); 149 | double dY = (p.y - this.y); 150 | double d = dX * dX + dY * dY; 151 | if (this.is3d() && p.is3d()) 152 | { 153 | double dZ = (p.z - this.z); 154 | d += dZ * dZ; 155 | } 156 | return Math.sqrt(d); 157 | } 158 | 159 | @Override 160 | public boolean equals(@Nullable Object other) 161 | { 162 | // check type and parent 163 | if ((other instanceof Point p) && super.equals(other)) 164 | { 165 | return coordsAreEqual(p); 166 | } 167 | return false; 168 | } 169 | 170 | /* 171 | * (non-Javadoc) 172 | * @see io.github.sebasbaumh.postgis.Geometry#getCoordinates() 173 | */ 174 | @Override 175 | public Iterable getCoordinates() 176 | { 177 | return Collections.singleton(this); 178 | } 179 | 180 | /** 181 | * Gets the measurement. 182 | * @return measurement on success, else {@link Double#NaN} 183 | */ 184 | public double getM() 185 | { 186 | return m; 187 | } 188 | 189 | /* 190 | * (non-Javadoc) 191 | * @see io.github.sebasbaumh.postgis.Geometry#getNumberOfCoordinates() 192 | */ 193 | @Override 194 | public int getNumberOfCoordinates() 195 | { 196 | return 1; 197 | } 198 | 199 | /** 200 | * Gets the X-coordinate. 201 | * @return X-coordinate on success, else {@link Double#NaN} 202 | */ 203 | public double getX() 204 | { 205 | return x; 206 | } 207 | 208 | /** 209 | * Gets the Y-coordinate. 210 | * @return Y-coordinate on success, else {@link Double#NaN} 211 | */ 212 | public double getY() 213 | { 214 | return y; 215 | } 216 | 217 | /** 218 | * Gets the Z-coordinate. 219 | * @return Z-coordinate on success, else {@link Double#NaN} 220 | */ 221 | public double getZ() 222 | { 223 | return z; 224 | } 225 | 226 | @Override 227 | public int hashCode() 228 | { 229 | return Objects.hash(x, y, z, m); 230 | } 231 | 232 | /* 233 | * (non-Javadoc) 234 | * @see io.github.sebasbaumh.postgis.Geometry#hasMeasure() 235 | */ 236 | @Override 237 | public boolean hasMeasure() 238 | { 239 | return !Double.isNaN(this.m); 240 | } 241 | 242 | /* 243 | * (non-Javadoc) 244 | * @see io.github.sebasbaumh.postgis.Geometry#is3d() 245 | */ 246 | @Override 247 | public boolean is3d() 248 | { 249 | return !Double.isNaN(this.z); 250 | } 251 | 252 | /* 253 | * (non-Javadoc) 254 | * @see io.github.sebasbaumh.postgis.Geometry#isEmpty() 255 | */ 256 | @Override 257 | public boolean isEmpty() 258 | { 259 | return Double.isNaN(this.x) && Double.isNaN(this.y); 260 | } 261 | 262 | /** 263 | * Sets the measurement. 264 | * @param m measurement 265 | */ 266 | public void setM(double m) 267 | { 268 | this.m = m; 269 | } 270 | 271 | /** 272 | * Sets the X-coordinate. 273 | * @param x X-coordinate 274 | */ 275 | public void setX(double x) 276 | { 277 | this.x = x; 278 | } 279 | 280 | /** 281 | * Sets the Y-coordinate. 282 | * @param y Y-coordinate 283 | */ 284 | public void setY(double y) 285 | { 286 | this.y = y; 287 | } 288 | 289 | /** 290 | * Sets the Z-coordinate. 291 | * @param z Z-coordinate 292 | */ 293 | public void setZ(double z) 294 | { 295 | this.z = z; 296 | } 297 | 298 | /** 299 | * Gets this {@link Point} as a 2d object. 300 | * @return {@link Point} 301 | */ 302 | public Point to2d() 303 | { 304 | // create a new instance with x/y and measure (if set) 305 | return new Point(this.x, this.y, Double.NaN, this.m); 306 | } 307 | 308 | /* 309 | * (non-Javadoc) 310 | * @see java.lang.Object#toString() 311 | */ 312 | @Override 313 | public String toString() 314 | { 315 | StringBuilder sb = new StringBuilder(); 316 | sb.append("Point ["); 317 | int srid = super.getSrid(); 318 | if (srid != UNKNOWN_SRID) 319 | { 320 | sb.append("srid="); 321 | sb.append(srid); 322 | sb.append(','); 323 | } 324 | sb.append(this.x); 325 | sb.append(','); 326 | sb.append(this.y); 327 | if (is3d()) 328 | { 329 | sb.append(','); 330 | sb.append(this.z); 331 | } 332 | sb.append(']'); 333 | return sb.toString(); 334 | } 335 | 336 | } 337 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/Polygon.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import org.eclipse.jdt.annotation.NonNullByDefault; 26 | 27 | /** 28 | * A polygon. 29 | * @author Sebastian Baumhekel 30 | */ 31 | @NonNullByDefault 32 | public class Polygon extends PolygonBase 33 | { 34 | private static final long serialVersionUID = 0x100; 35 | /** 36 | * The OGIS geometry type number for polygons. 37 | */ 38 | public static final int TYPE = 3; 39 | 40 | /** 41 | * Constructs an instance. 42 | */ 43 | public Polygon() 44 | { 45 | super(TYPE, LinearRing.class); 46 | } 47 | 48 | /** 49 | * Constructs an instance with the given rings. 50 | * @param rings rings (first one will be the outer ring) 51 | */ 52 | public Polygon(Iterable rings) 53 | { 54 | super(TYPE, LinearRing.class, rings); 55 | } 56 | 57 | /** 58 | * Constructs an instance. 59 | * @param lsOuterRing outer ring 60 | */ 61 | public Polygon(LinearRing lsOuterRing) 62 | { 63 | super(TYPE, lsOuterRing); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/PolygonBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.lang.reflect.InvocationTargetException; 26 | import java.util.ArrayList; 27 | import java.util.Iterator; 28 | import java.util.Objects; 29 | 30 | import javax.annotation.Nullable; 31 | 32 | import org.eclipse.jdt.annotation.NonNullByDefault; 33 | 34 | /** 35 | * Base class for a polygon to allow similar handling of straight and circular polygons. 36 | * @author Sebastian Baumhekel 37 | * @param type of the ring geometries 38 | */ 39 | @NonNullByDefault 40 | public abstract class PolygonBase extends Geometry implements Iterable, LineBasedGeometry 41 | { 42 | /* JDK 1.5 Serialization */ 43 | private static final long serialVersionUID = 0x100; 44 | 45 | private T lsOuterRing; 46 | private final ArrayList rings = new ArrayList(); 47 | 48 | /** 49 | * Constructor for subclasses. 50 | * @param clazzRing class of the ring 51 | * @param type has to be given by all subclasses 52 | */ 53 | protected PolygonBase(int type, Class clazzRing) 54 | { 55 | super(type); 56 | this.lsOuterRing = createRing(clazzRing); 57 | } 58 | 59 | /** 60 | * Constructor for subclasses. 61 | * @param clazzRing class of the ring 62 | * @param type has to be given by all subclasses 63 | * @param rings rings 64 | */ 65 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("PCOA_PARTIALLY_CONSTRUCTED_OBJECT_ACCESS") 66 | protected PolygonBase(int type, Class clazzRing, Iterable rings) 67 | { 68 | super(type); 69 | Iterator it = rings.iterator(); 70 | // first the outer ring 71 | if (it.hasNext()) 72 | { 73 | this.lsOuterRing = it.next(); 74 | // inner rings 75 | while (it.hasNext()) 76 | { 77 | addRing(it.next()); 78 | } 79 | } 80 | else 81 | { 82 | this.lsOuterRing = createRing(clazzRing); 83 | } 84 | } 85 | 86 | /** 87 | * Constructor for subclasses. 88 | * @param type has to be given by all subclasses 89 | * @param lsOuterRing outer ring 90 | */ 91 | protected PolygonBase(int type, U lsOuterRing) 92 | { 93 | super(type); 94 | this.lsOuterRing = lsOuterRing; 95 | } 96 | 97 | /** 98 | * Adds a ring. 99 | * @param ring ring 100 | */ 101 | public void addRing(T ring) 102 | { 103 | // ensure ring is closed 104 | if (!ring.isClosed()) 105 | { 106 | ring.close(); 107 | } 108 | // use correct orientation for holes 109 | if (!ring.isClockwise()) 110 | { 111 | ring.reverse(); 112 | } 113 | this.rings.add(ring); 114 | } 115 | 116 | @Override 117 | public boolean checkConsistency() 118 | { 119 | if (!super.checkConsistency()) 120 | { 121 | return false; 122 | } 123 | return PostGisUtil.checkConsistency(rings); 124 | } 125 | 126 | /** 127 | * Clears all rings. 128 | */ 129 | public void clearRings() 130 | { 131 | this.rings.clear(); 132 | } 133 | 134 | /** 135 | * Creates a new empty ring. 136 | * @param clazzRing class of the ring 137 | * @return ring 138 | * @throws IllegalArgumentException if the class could not be created 139 | */ 140 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS") 141 | private T createRing(Class clazzRing) 142 | { 143 | try 144 | { 145 | return clazzRing.getDeclaredConstructor().newInstance(); 146 | } 147 | catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException 148 | | NoSuchMethodException | SecurityException e) 149 | { 150 | throw new IllegalArgumentException("unable to create empty ring", e); 151 | } 152 | } 153 | 154 | @Override 155 | public boolean equals(@Nullable Object other) 156 | { 157 | // check type and parent 158 | if ((other instanceof PolygonBase poly) && super.equals(other)) 159 | { 160 | return PostGisUtil.equalsIterable(this.rings, poly.rings); 161 | } 162 | return false; 163 | } 164 | 165 | /* 166 | * (non-Javadoc) 167 | * @see io.github.sebasbaumh.postgis.Geometry#getCoordinates() 168 | */ 169 | @Override 170 | public Iterable getCoordinates() 171 | { 172 | return lsOuterRing.getCoordinates(); 173 | } 174 | 175 | /* 176 | * (non-Javadoc) 177 | * @see io.github.sebasbaumh.postgis.LineBasedGeometry#getEndPoint() 178 | */ 179 | @Nullable 180 | @Override 181 | public Point getEndPoint() 182 | { 183 | return lsOuterRing.getEndPoint(); 184 | } 185 | 186 | /* 187 | * (non-Javadoc) 188 | * @see io.github.sebasbaumh.postgis.Geometry#getNumberOfCoordinates() 189 | */ 190 | @Override 191 | public int getNumberOfCoordinates() 192 | { 193 | return lsOuterRing.getNumberOfCoordinates(); 194 | } 195 | 196 | /** 197 | * Gets the number of rings. 198 | * @return number of rings. 199 | */ 200 | public int getNumberOfRings() 201 | { 202 | return rings.size(); 203 | } 204 | 205 | /** 206 | * Gets the outer ring/boundary of the polygon. 207 | * @return outer ring 208 | */ 209 | public T getOuterRing() 210 | { 211 | return this.lsOuterRing; 212 | } 213 | 214 | /** 215 | * Gets all inner rings. 216 | * @return inner rings 217 | */ 218 | public Iterable getRings() 219 | { 220 | return this.rings; 221 | } 222 | 223 | /* 224 | * (non-Javadoc) 225 | * @see io.github.sebasbaumh.postgis.LineBasedGeometry#getStartPoint() 226 | */ 227 | @Nullable 228 | @Override 229 | public Point getStartPoint() 230 | { 231 | return lsOuterRing.getStartPoint(); 232 | } 233 | 234 | @Override 235 | public int hashCode() 236 | { 237 | return 31 * super.hashCode() + Objects.hash(lsOuterRing, rings); 238 | } 239 | 240 | /* 241 | * (non-Javadoc) 242 | * @see io.github.sebasbaumh.postgis.Geometry#hasMeasure() 243 | */ 244 | @Override 245 | public boolean hasMeasure() 246 | { 247 | for (T geom : rings) 248 | { 249 | if (geom.hasMeasure()) 250 | { 251 | return true; 252 | } 253 | } 254 | return false; 255 | } 256 | 257 | /* 258 | * (non-Javadoc) 259 | * @see io.github.sebasbaumh.postgis.Geometry#is3d() 260 | */ 261 | @Override 262 | public boolean is3d() 263 | { 264 | for (T geom : rings) 265 | { 266 | if (geom.is3d()) 267 | { 268 | return true; 269 | } 270 | } 271 | return false; 272 | } 273 | 274 | /** 275 | * Checks if this polygon is oriented in clockwise direction. Is false for the outer polygon and true for its holes. 276 | * @return true on success, else false 277 | */ 278 | public boolean isClockwise() 279 | { 280 | return lsOuterRing.isClockwise(); 281 | } 282 | 283 | /* 284 | * (non-Javadoc) 285 | * @see io.github.sebasbaumh.postgis.LineBasedGeometry#isClosed() 286 | */ 287 | @Override 288 | public boolean isClosed() 289 | { 290 | return this.lsOuterRing.isClosed(); 291 | } 292 | 293 | /* 294 | * (non-Javadoc) 295 | * @see io.github.sebasbaumh.postgis.Geometry#isEmpty() 296 | */ 297 | @Override 298 | public boolean isEmpty() 299 | { 300 | return lsOuterRing.isEmpty(); 301 | } 302 | 303 | /* 304 | * (non-Javadoc) 305 | * @see java.lang.Iterable#iterator() 306 | */ 307 | @Override 308 | public Iterator iterator() 309 | { 310 | return this.rings.iterator(); 311 | } 312 | 313 | /* 314 | * (non-Javadoc) 315 | * @see io.github.sebasbaumh.postgis.LineBasedGeom#length() 316 | */ 317 | @Override 318 | public double length() 319 | { 320 | return this.lsOuterRing.length(); 321 | } 322 | 323 | /** 324 | * Sets the outer ring/boundary of the polygon. 325 | * @param ls outer ring 326 | */ 327 | public void setOuterRing(T ls) 328 | { 329 | this.lsOuterRing = ls; 330 | } 331 | 332 | /* 333 | * (non-Javadoc) 334 | * @see java.lang.Object#toString() 335 | */ 336 | @Override 337 | public String toString() 338 | { 339 | return this.getClass().getSimpleName() + " [" + this.getNumberOfCoordinates() + " points, " + getNumberOfRings() 340 | + " inner rings]"; 341 | } 342 | 343 | } 344 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/binary/BinaryParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis.binary; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Collection; 27 | 28 | import io.github.sebasbaumh.postgis.CircularString; 29 | import io.github.sebasbaumh.postgis.CompoundCurve; 30 | import io.github.sebasbaumh.postgis.Curve; 31 | import io.github.sebasbaumh.postgis.CurvePolygon; 32 | import io.github.sebasbaumh.postgis.Geometry; 33 | import io.github.sebasbaumh.postgis.GeometryCollection; 34 | import io.github.sebasbaumh.postgis.LineString; 35 | import io.github.sebasbaumh.postgis.LinearRing; 36 | import io.github.sebasbaumh.postgis.MultiCurve; 37 | import io.github.sebasbaumh.postgis.MultiLineString; 38 | import io.github.sebasbaumh.postgis.MultiPoint; 39 | import io.github.sebasbaumh.postgis.MultiPolygon; 40 | import io.github.sebasbaumh.postgis.MultiSurface; 41 | import io.github.sebasbaumh.postgis.Point; 42 | import io.github.sebasbaumh.postgis.Polygon; 43 | import io.github.sebasbaumh.postgis.PolygonBase; 44 | 45 | /** 46 | * A parser for reading geometries from a binary or hex string representation. 47 | * @author Sebastian Baumhekel 48 | */ 49 | public final class BinaryParser 50 | { 51 | 52 | // prevent instantiating this class 53 | @Deprecated 54 | private BinaryParser() 55 | { 56 | } 57 | 58 | /** 59 | * Parse a hex encoded geometry 60 | * @param value byte array containing the data to be parsed 61 | * @param offset offset 62 | * @return resulting geometry for the parsed data 63 | * @throws IllegalArgumentException if a contained geometry is of the wrong type or the encoding type is unknown 64 | */ 65 | public static Geometry parse(byte[] value, int offset) 66 | { 67 | return parseGeometry(new BinaryValueGetter(value, offset)); 68 | } 69 | 70 | /** 71 | * Parse a hex encoded geometry 72 | * @param value String containing the data to be parsed 73 | * @return resulting geometry for the parsed data 74 | * @throws IllegalArgumentException if a contained geometry is of the wrong type or the encoding type is unknown 75 | */ 76 | public static Geometry parse(String value) 77 | { 78 | return parseGeometry(new StringValueGetter(value)); 79 | } 80 | 81 | /** 82 | * Parse multiple geometries into a {@link Collection}. The number of geometries is read upfront from the 83 | * {@link ValueGetter}. 84 | * @param clazz {@link Class} of the geometries 85 | * @param data {@link ValueGetter} 86 | * @return {@link Collection} of geometries 87 | * @throws IllegalArgumentException if a contained geometry is of the wrong type 88 | */ 89 | @SuppressWarnings("unchecked") 90 | private static Collection parseGeometries(Class clazz, ValueGetter data) 91 | { 92 | // get number of geometries to parse 93 | int count = data.getInt(); 94 | ArrayList l = new ArrayList(count); 95 | // parse geometries 96 | for (int i = 0; i < count; i++) 97 | { 98 | Geometry geom = parseGeometry(data); 99 | // check if the geometry is of the correct type 100 | if (clazz.isInstance(geom)) 101 | { 102 | l.add((T) geom); 103 | } 104 | else 105 | { 106 | throw new IllegalArgumentException( 107 | "expected: " + clazz.getCanonicalName() + " got: " + geom.getClass().getCanonicalName()); 108 | } 109 | } 110 | return l; 111 | } 112 | 113 | /** 114 | * Parse a geometry starting at offset. 115 | * @param data ValueGetter with the data to be parsed 116 | * @return the parsed geometry 117 | * @throws IllegalArgumentException for unknown geometry types 118 | */ 119 | private static Geometry parseGeometry(ValueGetter data) 120 | { 121 | // read endian flag 122 | data.readEncoding(); 123 | // and get the type 124 | int typeword = data.getInt(); 125 | int geometryType = typeword & 0x1FFFFFFF; // cut off high flag bits 126 | 127 | boolean haveZ = (typeword & 0x80000000) != 0; 128 | boolean haveM = (typeword & 0x40000000) != 0; 129 | boolean haveS = (typeword & 0x20000000) != 0; 130 | 131 | int srid = Geometry.UNKNOWN_SRID; 132 | if (haveS) 133 | { 134 | // ensure valid SRID 135 | srid = data.getInt(); 136 | if (srid < 0) 137 | { 138 | srid = Geometry.UNKNOWN_SRID; 139 | } 140 | } 141 | // parse geometry according to type 142 | Geometry result; 143 | switch (geometryType) 144 | { 145 | case Point.TYPE: 146 | result = parsePoint(data, haveZ, haveM); 147 | break; 148 | case LineString.TYPE: 149 | result = new LineString(parsePoints(data, haveZ, haveM)); 150 | break; 151 | case CircularString.TYPE: 152 | result = new CircularString(parsePoints(data, haveZ, haveM)); 153 | break; 154 | case CompoundCurve.TYPE: 155 | result = new CompoundCurve(parseGeometries(LineString.class, data)); 156 | break; 157 | case Polygon.TYPE: 158 | result = parsePolygon(data, haveZ, haveM); 159 | break; 160 | case CurvePolygon.TYPE: 161 | result = new CurvePolygon(parseGeometries(Curve.class, data)); 162 | break; 163 | case MultiPoint.TYPE: 164 | result = new MultiPoint(parseGeometries(Point.class, data)); 165 | break; 166 | case MultiLineString.TYPE: 167 | result = new MultiLineString(parseGeometries(LineString.class, data)); 168 | break; 169 | case MultiCurve.TYPE: 170 | result = new MultiCurve(parseGeometries(Curve.class, data)); 171 | break; 172 | case MultiPolygon.TYPE: 173 | result = new MultiPolygon(parseGeometries(Polygon.class, data)); 174 | break; 175 | case MultiSurface.TYPE: 176 | result = new MultiSurface(parseGeometries(PolygonBase.class, data)); 177 | break; 178 | case GeometryCollection.TYPE: 179 | result = new GeometryCollection(parseGeometries(Geometry.class, data)); 180 | break; 181 | default: 182 | throw new IllegalArgumentException("Unknown Geometry Type: " + geometryType); 183 | } 184 | // set SRID and return the geometry 185 | result.setSrid(srid); 186 | return result; 187 | } 188 | 189 | /** 190 | * Parse a single point. 191 | * @param data {@link ValueGetter} 192 | * @param haveZ parse z value? 193 | * @param haveM parse measure value? 194 | * @return {@link Point} 195 | */ 196 | private static Point parsePoint(ValueGetter data, boolean haveZ, boolean haveM) 197 | { 198 | double x = data.getDouble(); 199 | double y = data.getDouble(); 200 | Point result; 201 | // parse z? 202 | if (haveZ) 203 | { 204 | result = new Point(x, y, data.getDouble()); 205 | } 206 | else 207 | { 208 | result = new Point(x, y); 209 | } 210 | // parse measure? 211 | if (haveM) 212 | { 213 | result.setM(data.getDouble()); 214 | } 215 | return result; 216 | } 217 | 218 | /** 219 | * Parse an Array of "slim" {@link Point}s (without endianness and type, part of {@link LinearRing} and 220 | * {@link LineString}, but not {@link MultiPoint}! 221 | * @param data {@link ValueGetter} 222 | * @param haveZ parse z value? 223 | * @param haveM parse measure value? 224 | * @return {@link Collection} of {@link Point}s 225 | */ 226 | private static Collection parsePoints(ValueGetter data, boolean haveZ, boolean haveM) 227 | { 228 | int count = data.getInt(); 229 | ArrayList l = new ArrayList(count); 230 | for (int i = 0; i < count; i++) 231 | { 232 | l.add(parsePoint(data, haveZ, haveM)); 233 | } 234 | return l; 235 | } 236 | 237 | /** 238 | * Parse a {@link Polygon}. 239 | * @param data {@link ValueGetter} 240 | * @param haveZ parse z value? 241 | * @param haveM parse measure value? 242 | * @return {@link Polygon} 243 | */ 244 | private static Polygon parsePolygon(ValueGetter data, boolean haveZ, boolean haveM) 245 | { 246 | int count = data.getInt(); 247 | ArrayList rings = new ArrayList(count); 248 | for (int i = 0; i < count; i++) 249 | { 250 | rings.add(new LinearRing(parsePoints(data, haveZ, haveM))); 251 | } 252 | return new Polygon(rings); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/binary/BinaryValueGetter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis.binary; 24 | 25 | /** 26 | * Allows reading values from a byte array. 27 | * @author Sebastian Baumhekel 28 | */ 29 | public class BinaryValueGetter extends ValueGetter 30 | { 31 | private int position; 32 | private final byte[] value; 33 | 34 | /** 35 | * Constructs an instance. 36 | * @param value value 37 | * @param offset offset to use 38 | */ 39 | public BinaryValueGetter(byte[] value, int offset) 40 | { 41 | this.value = value; 42 | this.position = offset; 43 | } 44 | 45 | @Override 46 | public int getInt() 47 | { 48 | // get current position and advance it 49 | int index = position; 50 | position += 4; 51 | // be sure to use ints as Java byte is signed 52 | int i1 = (value[index]) & 0xFF; 53 | int i2 = (value[index + 1]) & 0xFF; 54 | int i3 = (value[index + 2]) & 0xFF; 55 | int i4 = (value[index + 3]) & 0xFF; 56 | // optimize by not calling getNextByte() for every byte, but just taking them directly from the array 57 | return funcInt.getInt(i1, i2, i3, i4); 58 | } 59 | 60 | @Override 61 | public long getLong() 62 | { 63 | // get current position and advance it 64 | int index = position; 65 | position += 8; 66 | // be sure to use ints as Java byte is signed 67 | int i1 = (value[index]) & 0xFF; 68 | int i2 = (value[index + 1]) & 0xFF; 69 | int i3 = (value[index + 2]) & 0xFF; 70 | int i4 = (value[index + 3]) & 0xFF; 71 | int i5 = (value[index + 4]) & 0xFF; 72 | int i6 = (value[index + 5]) & 0xFF; 73 | int i7 = (value[index + 6]) & 0xFF; 74 | int i8 = (value[index + 7]) & 0xFF; 75 | // optimize by not calling getNextByte() for every byte, but just taking them directly from the array 76 | return funcLong.getLong(i1, i2, i3, i4, i5, i6, i7, i8); 77 | } 78 | 79 | @Override 80 | protected int getNextByte() 81 | { 82 | // get current position and advance it to the next byte 83 | int index = position; 84 | position++; 85 | // make sure the signed byte in the array gets converted to an unsigned value 86 | return (value[index]) & 0xFF; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/binary/BinaryValueSetter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis.binary; 24 | 25 | import java.io.ByteArrayOutputStream; 26 | 27 | /** 28 | * Allows writing values to a byte array in little endian format. 29 | * @author Sebastian Baumhekel 30 | */ 31 | public class BinaryValueSetter extends ValueSetter 32 | { 33 | private final ByteArrayOutputStream out = new ByteArrayOutputStream(); 34 | 35 | /** 36 | * Gets the written value. 37 | * @return value 38 | */ 39 | public byte[] getValue() 40 | { 41 | return out.toByteArray(); 42 | } 43 | 44 | @Override 45 | public void setByte(byte b) 46 | { 47 | out.write(b); 48 | } 49 | 50 | @Override 51 | public void setInt(int value) 52 | { 53 | out.write((value >>> 0) & 0xFF); 54 | out.write((value >>> 8) & 0xFF); 55 | out.write((value >>> 16) & 0xFF); 56 | out.write((value >>> 24) & 0xFF); 57 | } 58 | 59 | @Override 60 | public void setLong(long value) 61 | { 62 | out.write((int) ((value >>> 0) & 0xFF)); 63 | out.write((int) ((value >>> 8) & 0xFF)); 64 | out.write((int) ((value >>> 16) & 0xFF)); 65 | out.write((int) ((value >>> 24) & 0xFF)); 66 | out.write((int) ((value >>> 32) & 0xFF)); 67 | out.write((int) ((value >>> 40) & 0xFF)); 68 | out.write((int) ((value >>> 48) & 0xFF)); 69 | out.write((int) ((value >>> 56) & 0xFF)); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/binary/BinaryWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis.binary; 24 | 25 | import java.util.ArrayList; 26 | import java.util.Collection; 27 | 28 | import io.github.sebasbaumh.postgis.CircularString; 29 | import io.github.sebasbaumh.postgis.CompoundCurve; 30 | import io.github.sebasbaumh.postgis.Curve; 31 | import io.github.sebasbaumh.postgis.CurvePolygon; 32 | import io.github.sebasbaumh.postgis.Geometry; 33 | import io.github.sebasbaumh.postgis.GeometryCollection; 34 | import io.github.sebasbaumh.postgis.LineString; 35 | import io.github.sebasbaumh.postgis.LinearRing; 36 | import io.github.sebasbaumh.postgis.MultiCurve; 37 | import io.github.sebasbaumh.postgis.MultiLineString; 38 | import io.github.sebasbaumh.postgis.MultiPoint; 39 | import io.github.sebasbaumh.postgis.MultiPolygon; 40 | import io.github.sebasbaumh.postgis.MultiSurface; 41 | import io.github.sebasbaumh.postgis.Point; 42 | import io.github.sebasbaumh.postgis.Polygon; 43 | import io.github.sebasbaumh.postgis.PolygonBase; 44 | import io.github.sebasbaumh.postgis.PostGisUtil; 45 | 46 | /** 47 | * A writer for building a binary or hex string representation of geometries. 48 | * @author Sebastian Baumhekel 49 | */ 50 | public final class BinaryWriter 51 | { 52 | // prevent instantiating this class 53 | @Deprecated 54 | private BinaryWriter() 55 | { 56 | } 57 | 58 | /** 59 | * Write a binary encoded geometry. The geometry you put in must be consistent, geom.checkConsistency() must return 60 | * true. If not, the result may be invalid WKB. 61 | * @see Geometry#checkConsistency() the consistency checker 62 | * @param geom the geometry to be written 63 | * @return byte arrray containing the encoded geometry 64 | */ 65 | public static byte[] writeBinary(Geometry geom) 66 | { 67 | BinaryValueSetter bytes = new BinaryValueSetter(); 68 | writeGeometry(geom, bytes); 69 | return bytes.getValue(); 70 | } 71 | 72 | /** 73 | * Parse a geometry starting at offset. 74 | * @param geom the geometry to write 75 | * @param dest the value setting to be used for writing 76 | */ 77 | private static void writeGeometry(Geometry geom, ValueSetter dest) 78 | { 79 | // write endian flag, NDR (little endian) 80 | dest.setByte(PostGisUtil.LITTLE_ENDIAN); 81 | 82 | // write typeword 83 | int typeword = geom.getType(); 84 | if (geom.is3d()) 85 | { 86 | typeword |= 0x80000000; 87 | } 88 | if (geom.hasMeasure()) 89 | { 90 | typeword |= 0x40000000; 91 | } 92 | if (geom.getSrid() != Geometry.UNKNOWN_SRID) 93 | { 94 | typeword |= 0x20000000; 95 | } 96 | dest.setInt(typeword); 97 | 98 | if (geom.getSrid() != Geometry.UNKNOWN_SRID) 99 | { 100 | dest.setInt(geom.getSrid()); 101 | } 102 | 103 | switch (geom.getType()) 104 | { 105 | case Point.TYPE: 106 | writePoint((Point) geom, dest); 107 | break; 108 | case LineString.TYPE: 109 | writePoints((LineString) geom, dest); 110 | break; 111 | case CircularString.TYPE: 112 | writePoints((CircularString) geom, dest); 113 | break; 114 | case CompoundCurve.TYPE: 115 | writeMultiGeometry(((CompoundCurve) geom).getGeometries(), dest); 116 | break; 117 | case Polygon.TYPE: 118 | writePolygon((Polygon) geom, dest); 119 | break; 120 | case CurvePolygon.TYPE: 121 | writePolygon((CurvePolygon) geom, dest); 122 | break; 123 | case MultiPoint.TYPE: 124 | writeMultiGeometry(((MultiPoint) geom).getGeometries(), dest); 125 | break; 126 | case MultiLineString.TYPE: 127 | writeMultiGeometry(((MultiLineString) geom).getGeometries(), dest); 128 | break; 129 | case MultiCurve.TYPE: 130 | writeMultiGeometry(((MultiCurve) geom).getGeometries(), dest); 131 | break; 132 | case MultiPolygon.TYPE: 133 | writeMultiGeometry(((MultiPolygon) geom).getGeometries(), dest); 134 | break; 135 | case MultiSurface.TYPE: 136 | writeMultiGeometry(((MultiSurface) geom).getGeometries(), dest); 137 | break; 138 | case GeometryCollection.TYPE: 139 | writeMultiGeometry(((GeometryCollection) geom).getGeometries(), dest); 140 | break; 141 | default: 142 | throw new IllegalArgumentException("Unknown Geometry Type: " + geom.getType()); 143 | } 144 | } 145 | 146 | /** 147 | * Write a hex encoded geometry. The geometry you put in must be consistent, geom.checkConsistency() must return 148 | * true. If not, the result may be invalid WKB. 149 | * @see Geometry#checkConsistency() the consistency checker 150 | * @param geom the geometry to be written 151 | * @return String containing the hex encoded geometry 152 | */ 153 | public static String writeHexed(Geometry geom) 154 | { 155 | StringValueSetter bytes = new StringValueSetter(); 156 | writeGeometry(geom, bytes); 157 | return bytes.getValue(); 158 | } 159 | 160 | /** 161 | * Writes multiple geometries preceded by their count. 162 | * @param geoms geometries 163 | * @param dest writer 164 | */ 165 | private static void writeMultiGeometry(Collection geoms, ValueSetter dest) 166 | { 167 | dest.setInt(geoms.size()); 168 | for (Geometry geom : geoms) 169 | { 170 | writeGeometry(geom, dest); 171 | } 172 | } 173 | 174 | /** 175 | * Writes a "slim" Point (without endiannes, srid ant type, only the ordinates and measure. Used by writeGeometry as 176 | * ell as writePointArray. 177 | * @param geom geometry 178 | * @param dest writer 179 | */ 180 | private static void writePoint(Point geom, ValueSetter dest) 181 | { 182 | dest.setDouble(geom.getX()); 183 | dest.setDouble(geom.getY()); 184 | // write z coordinate? 185 | if (geom.is3d()) 186 | { 187 | dest.setDouble(geom.getZ()); 188 | } 189 | // write measure? 190 | if (geom.hasMeasure()) 191 | { 192 | dest.setDouble(geom.getM()); 193 | } 194 | } 195 | 196 | /** 197 | * Write an Array of "slim" Points (without endianness, srid and type, part of LinearRing and Linestring, but not 198 | * MultiPoint! 199 | * @param geom geometry 200 | * @param dest writer 201 | */ 202 | private static void writePoints(LineString geom, ValueSetter dest) 203 | { 204 | // number of points 205 | dest.setInt(geom.getNumberOfCoordinates()); 206 | for (Point p : geom) 207 | { 208 | writePoint(p, dest); 209 | } 210 | } 211 | 212 | /** 213 | * Writes a {@link Polygon}. 214 | * @param geom {@link Polygon} 215 | * @param dest writer 216 | */ 217 | private static void writePolygon(PolygonBase geom, ValueSetter dest) 218 | { 219 | // collect all rings (outer ring+inner rings) 220 | ArrayList rings = new ArrayList(geom.getNumberOfRings() + 1); 221 | rings.add(geom.getOuterRing()); 222 | for (T ring : geom.getRings()) 223 | { 224 | rings.add(ring); 225 | } 226 | // write number of rings 227 | dest.setInt(rings.size()); 228 | // then all rings 229 | for (T ring : rings) 230 | { 231 | // polygon linear rings are just written as a plain set of points 232 | if (ring instanceof LinearRing lr) 233 | { 234 | writePoints(lr, dest); 235 | } 236 | else 237 | { 238 | // curve polygons can have different geometries 239 | writeGeometry(ring, dest); 240 | } 241 | } 242 | } 243 | 244 | } 245 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/binary/StringValueGetter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis.binary; 24 | 25 | import io.github.sebasbaumh.postgis.PostGisUtil; 26 | 27 | /** 28 | * Allows reading values from a string. 29 | * @author Sebastian Baumhekel 30 | */ 31 | public class StringValueGetter extends ValueGetter 32 | { 33 | private int position; 34 | private final String value; 35 | 36 | /** 37 | * Constructs an instance. 38 | * @param value value as hex string 39 | */ 40 | public StringValueGetter(String value) 41 | { 42 | this.value = value; 43 | } 44 | 45 | @Override 46 | protected int getNextByte() 47 | { 48 | // get current position (and respect that every byte consists of 2 hex characters) 49 | int index = position * 2; 50 | // then advance the position to the next byte 51 | position++; 52 | return ((PostGisUtil.toHexByte(value.charAt(index)) << 4) | PostGisUtil.toHexByte(value.charAt(index + 1))); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/binary/StringValueSetter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis.binary; 24 | 25 | import io.github.sebasbaumh.postgis.PostGisUtil; 26 | 27 | /** 28 | * Allows writing values as a string in little endian encoding and hex format. 29 | * @author Sebastian Baumhekel 30 | */ 31 | public class StringValueSetter extends ValueSetter 32 | { 33 | private final StringBuilder sb = new StringBuilder(); 34 | 35 | /** 36 | * Constructs an instance. 37 | */ 38 | public StringValueSetter() 39 | { 40 | } 41 | 42 | /** 43 | * Gets the written value. 44 | * @return value 45 | */ 46 | public String getValue() 47 | { 48 | return sb.toString(); 49 | } 50 | 51 | @Override 52 | public void setByte(byte b) 53 | { 54 | sb.append(PostGisUtil.HEX_CHAR[(b >> 4) & 0xF]); 55 | sb.append(PostGisUtil.HEX_CHAR[b & 0xF]); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/binary/ValueGetter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis.binary; 24 | 25 | import io.github.sebasbaumh.postgis.PostGisUtil; 26 | 27 | /** 28 | * A base class for value readers. 29 | * @author Sebastian Baumhekel 30 | */ 31 | public abstract class ValueGetter 32 | { 33 | 34 | /** 35 | * Int builder for big endian encoding. 36 | */ 37 | private static final IntBuilder INT_BUILDER_BIG_ENDIAN = (b1, b2, b3, b4) -> 38 | (b1 << 24) + (b2 << 16) + (b3 << 8) + b4; 39 | 40 | /** 41 | * Int builder for little endian encoding. 42 | */ 43 | private static final IntBuilder INT_BUILDER_LITTLE_ENDIAN = (b1, b2, b3, b4) -> 44 | (b4 << 24) + (b3 << 16) + (b2 << 8) + b1; 45 | 46 | /** 47 | * Int builder for big endian encoding. 48 | */ 49 | private static final LongBuilder LONG_BUILDER_BIG_ENDIAN = (b1, b2, b3, b4, b5, b6, b7, b8) -> 50 | (b1 << 56) + (b2 << 48) + (b3 << 40) + (b4 << 32) + (b5 << 24) + (b6 << 16) + (b7 << 8) + b8; 51 | 52 | /** 53 | * Int builder for little endian encoding. 54 | */ 55 | private static final LongBuilder LONG_BUILDER_LITTLE_ENDIAN = (b1, b2, b3, b4, b5, b6, b7, b8) -> 56 | (b8 << 56) + (b7 << 48) + (b6 << 40) + (b5 << 32) + (b4 << 24) + (b3 << 16) + (b2 << 8) + b1; 57 | 58 | /** 59 | * Current encoding (default is little endian encoding). 60 | */ 61 | protected int endian = PostGisUtil.LITTLE_ENDIAN; 62 | /** 63 | * Builder for integer values respecting the current encoding (default is little endian encoding). 64 | */ 65 | protected IntBuilder funcInt = INT_BUILDER_LITTLE_ENDIAN; 66 | /** 67 | * Builder for long values respecting the current encoding (default is little endian encoding). 68 | */ 69 | protected LongBuilder funcLong = LONG_BUILDER_LITTLE_ENDIAN; 70 | 71 | /** 72 | * Constructs an instance. 73 | */ 74 | public ValueGetter() 75 | { 76 | } 77 | 78 | /** 79 | * Get a double value. 80 | * @return double value 81 | */ 82 | public double getDouble() 83 | { 84 | return Double.longBitsToDouble(getLong()); 85 | } 86 | 87 | /** 88 | * Get an integer value. 89 | * @return integer value 90 | */ 91 | public int getInt() 92 | { 93 | return funcInt.getInt(getNextByte(), getNextByte(), getNextByte(), getNextByte()); 94 | } 95 | 96 | /** 97 | * Get a long value. 98 | * @return long value 99 | */ 100 | public long getLong() 101 | { 102 | return funcLong.getLong(getNextByte(), getNextByte(), getNextByte(), getNextByte(), getNextByte(), 103 | getNextByte(), getNextByte(), getNextByte()); 104 | } 105 | 106 | /** 107 | * Gets a byte at the current index. 108 | * @return byte 109 | * @throws IndexOutOfBoundsException if the current index is out of the range 110 | */ 111 | protected abstract int getNextByte(); 112 | 113 | /** 114 | * Reads the encoding and adjusts the internal decoder if necessary. 115 | * @throws IllegalArgumentException if the endian type is unknown 116 | */ 117 | public void readEncoding() 118 | { 119 | // get byte for endian check 120 | int newEndian = getNextByte(); 121 | // only do something if encoding differs from the current setting 122 | if (newEndian != this.endian) 123 | { 124 | this.endian = newEndian; 125 | switch (newEndian) 126 | { 127 | case PostGisUtil.LITTLE_ENDIAN: 128 | { 129 | this.funcInt = INT_BUILDER_LITTLE_ENDIAN; 130 | this.funcLong = LONG_BUILDER_LITTLE_ENDIAN; 131 | } 132 | break; 133 | case PostGisUtil.BIG_ENDIAN: 134 | { 135 | this.funcInt = INT_BUILDER_BIG_ENDIAN; 136 | this.funcLong = LONG_BUILDER_BIG_ENDIAN; 137 | } 138 | break; 139 | default: 140 | throw new IllegalArgumentException("Unknown Endian type:" + endian); 141 | } 142 | } 143 | } 144 | 145 | /** 146 | * Builder for an int from a byte sequence. 147 | */ 148 | @FunctionalInterface 149 | protected interface IntBuilder 150 | { 151 | /** 152 | * Get an integer. 153 | * @param b1 byte 1 154 | * @param b2 byte 2 155 | * @param b3 byte 3 156 | * @param b4 byte 4 157 | * @return integer 158 | */ 159 | int getInt(int b1, int b2, int b3, int b4); 160 | } 161 | 162 | /** 163 | * Builder for a long from a byte sequence. 164 | */ 165 | @FunctionalInterface 166 | protected interface LongBuilder 167 | { 168 | /** 169 | * Get a long. 170 | * @param b1 byte 1 171 | * @param b2 byte 2 172 | * @param b3 byte 3 173 | * @param b4 byte 4 174 | * @param b5 byte 5 175 | * @param b6 byte 6 176 | * @param b7 byte 7 177 | * @param b8 byte 8 178 | * @return long 179 | */ 180 | long getLong(long b1, long b2, long b3, long b4, long b5, long b6, long b7, long b8); 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/binary/ValueSetter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis.binary; 24 | 25 | /** 26 | * A base class for value setters. 27 | * @author Sebastian Baumhekel 28 | */ 29 | public abstract class ValueSetter 30 | { 31 | 32 | /** 33 | * Constructs an instance. 34 | */ 35 | public ValueSetter() 36 | { 37 | } 38 | 39 | /** 40 | * Sets a byte. 41 | * @param b byte value to set with 42 | */ 43 | public abstract void setByte(byte b); 44 | 45 | /** 46 | * Writes a double. 47 | * @param data double value to be set with 48 | */ 49 | public void setDouble(double data) 50 | { 51 | setLong(Double.doubleToLongBits(data)); 52 | } 53 | 54 | /** 55 | * Sets a 32-Bit integer 56 | * @param value int value to be set with 57 | */ 58 | public void setInt(int value) 59 | { 60 | setByte((byte) value); 61 | setByte((byte) (value >> 8)); 62 | setByte((byte) (value >> 16)); 63 | setByte((byte) (value >> 24)); 64 | } 65 | 66 | /** 67 | * Sets a long value. This is not needed directly, but as a nice side-effect from setDouble. 68 | * @param value value value to be set with 69 | */ 70 | public void setLong(long value) 71 | { 72 | setByte((byte) value); 73 | setByte((byte) (value >> 8)); 74 | setByte((byte) (value >> 16)); 75 | setByte((byte) (value >> 24)); 76 | setByte((byte) (value >> 32)); 77 | setByte((byte) (value >> 40)); 78 | setByte((byte) (value >> 48)); 79 | setByte((byte) (value >> 56)); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/io/github/sebasbaumh/postgis/binary/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Binary parser package. 3 | * @author Sebastian Baumhekel 4 | */ 5 | @org.eclipse.jdt.annotation.NonNullByDefault 6 | package io.github.sebasbaumh.postgis.binary; -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/java.sql.Driver: -------------------------------------------------------------------------------- 1 | io.github.sebasbaumh.postgis.DriverWrapper -------------------------------------------------------------------------------- /src/main/resources/org/postgresql/driverconfig.properties: -------------------------------------------------------------------------------- 1 | # 2 | # This property file is included in the postgis jar and autoregisters the 3 | # PostGIS datatypes within the jdbc driver. 4 | # 5 | 6 | datatype.geometry=io.github.sebasbaumh.postgis.PGgeometry 7 | datatype.geography=io.github.sebasbaumh.postgis.PGgeography 8 | datatype.box2d=io.github.sebasbaumh.postgis.PGbox2d 9 | datatype.box3d=io.github.sebasbaumh.postgis.PGbox3d 10 | datatype.public.geometry=io.github.sebasbaumh.postgis.PGgeometry 11 | datatype.public.geography=io.github.sebasbaumh.postgis.PGgeography 12 | datatype.public.box2d=io.github.sebasbaumh.postgis.PGbox2d 13 | datatype.public.box3d=io.github.sebasbaumh.postgis.PGbox3d 14 | -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/BoxesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.SQLException; 26 | 27 | import org.junit.Assert; 28 | import org.junit.Test; 29 | import org.postgresql.util.PGobject; 30 | 31 | @SuppressWarnings({ "javadoc", "static-method" }) 32 | public class BoxesTest 33 | { 34 | 35 | private static void cloneTest(T o) 36 | { 37 | try 38 | { 39 | Object o2 = o.clone(); 40 | Assert.assertEquals(o.getClass(), o2.getClass()); 41 | @SuppressWarnings("unchecked") 42 | T t2 = (T) o2; 43 | Assert.assertEquals(o, o2); 44 | Assert.assertEquals(o.getType(), t2.getType()); 45 | Assert.assertNotSame(o, o2); 46 | } 47 | catch (CloneNotSupportedException ex) 48 | { 49 | Assert.fail("Clone not supported: " + ex.getMessage()); 50 | } 51 | } 52 | 53 | @Test 54 | public void testBox2d() throws SQLException 55 | { 56 | PGbox2d box = new PGbox2d("BOX(1 2,3 4)"); 57 | Point p0 = box.getLLB(); 58 | Assert.assertNotNull(p0); 59 | Assert.assertEquals(1, p0.getX(), 0.0001); 60 | Assert.assertEquals(2, p0.getY(), 0.0001); 61 | Assert.assertFalse(p0.is3d()); 62 | Point p1 = box.getURT(); 63 | Assert.assertNotNull(p1); 64 | Assert.assertEquals(3, p1.getX(), 0.0001); 65 | Assert.assertEquals(4, p1.getY(), 0.0001); 66 | Assert.assertFalse(p1.is3d()); 67 | } 68 | 69 | @Test 70 | public void testBox3d() throws SQLException 71 | { 72 | PGbox3d box = new PGbox3d("BOX3D(1 2 3,4 5 6)"); 73 | Point p0 = box.getLLB(); 74 | Assert.assertNotNull(p0); 75 | Assert.assertEquals(1, p0.getX(), 0.0001); 76 | Assert.assertEquals(2, p0.getY(), 0.0001); 77 | Assert.assertEquals(3, p0.getZ(), 0.0001); 78 | Assert.assertTrue(p0.is3d()); 79 | Point p1 = box.getURT(); 80 | Assert.assertNotNull(p1); 81 | Assert.assertEquals(4, p1.getX(), 0.0001); 82 | Assert.assertEquals(5, p1.getY(), 0.0001); 83 | Assert.assertEquals(6, p1.getZ(), 0.0001); 84 | Assert.assertTrue(p1.is3d()); 85 | } 86 | 87 | @Test 88 | public void testBox3d_2() throws SQLException 89 | { 90 | PGbox3d box = new PGbox3d("BOX3D(1 2,4 5)"); 91 | Point p0 = box.getLLB(); 92 | Assert.assertNotNull(p0); 93 | Assert.assertEquals(1, p0.getX(), 0.0001); 94 | Assert.assertEquals(2, p0.getY(), 0.0001); 95 | Assert.assertFalse(p0.is3d()); 96 | Point p1 = box.getURT(); 97 | Assert.assertNotNull(p1); 98 | Assert.assertEquals(4, p1.getX(), 0.0001); 99 | Assert.assertEquals(5, p1.getY(), 0.0001); 100 | Assert.assertFalse(p1.is3d()); 101 | } 102 | 103 | @Test 104 | public void testClone() throws SQLException 105 | { 106 | cloneTest(new PGbox2d("BOX(1 2,3 4)")); 107 | cloneTest(new PGbox3d("BOX3D(1 2 3,4 5 6)")); 108 | cloneTest(new PGbox3d("BOX3D(1 2,4 5)")); 109 | } 110 | 111 | } -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/DatatypesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.SQLException; 26 | 27 | import org.junit.Test; 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | 31 | @SuppressWarnings("javadoc") 32 | public class DatatypesTest extends DatabaseTestBase 33 | { 34 | 35 | private static final String CR_STR = "CIRCULARSTRING(-9 2,-8 3,-7 2)"; 36 | 37 | private static final String CR_STR2 = "CIRCULARSTRING(0 -1,-1 0,0 1,1 0,0 -1)"; 38 | 39 | private static final String LNG_STR = "LINESTRING (10 10 20,20 20 20, 50 50 50, 34 34 34)"; 40 | 41 | private static final Logger logger = LoggerFactory.getLogger(DatatypesTest.class); 42 | 43 | private static final String MLNG_STR = "MULTILINESTRING ((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"; 44 | 45 | private static final String MPLG_STR = "MULTIPOLYGON (((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"; 46 | 47 | private static final String PLG_STR = "POLYGON ((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"; 48 | 49 | private static final String PTG_STR = "POINT(10 10 20)"; 50 | 51 | @SuppressWarnings("unchecked") 52 | private T assertGeometry(Class clazz, String wkt) throws SQLException 53 | { 54 | Geometry geom = getGeometryFromWKT(wkt); 55 | if (clazz.isInstance(geom)) 56 | { 57 | return (T) geom; 58 | } 59 | throw new IllegalArgumentException( 60 | "expected: " + clazz.getCanonicalName() + " got: " + geom.getClass().getCanonicalName()); 61 | } 62 | 63 | @Test 64 | public void testCircularString() throws SQLException 65 | { 66 | if (!hasDatabase()) 67 | { 68 | return; 69 | } 70 | logger.trace("void testCircularString()"); 71 | logger.debug(CR_STR); 72 | CircularString lng = assertGeometry(CircularString.class, CR_STR); 73 | logger.debug(lng.toString()); 74 | } 75 | 76 | @Test 77 | public void testCircularString2() throws SQLException 78 | { 79 | if (!hasDatabase()) 80 | { 81 | return; 82 | } 83 | logger.trace("void testCircularString2()"); 84 | logger.debug(CR_STR2); 85 | CircularString lng = assertGeometry(CircularString.class, CR_STR2); 86 | logger.debug(lng.toString()); 87 | } 88 | 89 | @Test 90 | public void testLineString() throws SQLException 91 | { 92 | if (!hasDatabase()) 93 | { 94 | return; 95 | } 96 | logger.trace("void testLineString()"); 97 | logger.debug(LNG_STR); 98 | LineString lng = assertGeometry(LineString.class, LNG_STR); 99 | logger.debug(lng.toString()); 100 | } 101 | 102 | @Test 103 | public void testMultiLineString() throws SQLException 104 | { 105 | if (!hasDatabase()) 106 | { 107 | return; 108 | } 109 | logger.trace("void testMultiLineString()"); 110 | logger.debug(MLNG_STR); 111 | MultiLineString mlng = assertGeometry(MultiLineString.class, MLNG_STR); 112 | logger.debug(mlng.toString()); 113 | } 114 | 115 | @Test 116 | public void testMultiPolygon() throws SQLException 117 | { 118 | if (!hasDatabase()) 119 | { 120 | return; 121 | } 122 | logger.trace("void testMultiPolygon()"); 123 | logger.debug(MPLG_STR); 124 | MultiPolygon mplg = assertGeometry(MultiPolygon.class, MPLG_STR); 125 | logger.debug(mplg.toString()); 126 | } 127 | 128 | @Test 129 | public void testPGgeometry() throws SQLException 130 | { 131 | if (!hasDatabase()) 132 | { 133 | return; 134 | } 135 | logger.trace("void testPGgeometry()"); 136 | logger.debug(MLNG_STR); 137 | PGgeometry pgf = new PGgeometry(getWKBFromWKT(MLNG_STR)); 138 | logger.debug(pgf.toString()); 139 | } 140 | 141 | @Test 142 | public void testPoint() throws SQLException 143 | { 144 | if (!hasDatabase()) 145 | { 146 | return; 147 | } 148 | logger.trace("void testPoint()"); 149 | logger.debug(PTG_STR); 150 | Point ptg = assertGeometry(Point.class, PTG_STR); 151 | logger.debug(ptg.toString()); 152 | } 153 | 154 | @Test 155 | public void testPolygon() throws SQLException 156 | { 157 | if (!hasDatabase()) 158 | { 159 | return; 160 | } 161 | logger.trace("void testPolygon()"); 162 | logger.debug(PLG_STR); 163 | Polygon plg = assertGeometry(Polygon.class, PLG_STR); 164 | logger.debug(plg.toString()); 165 | } 166 | 167 | } -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/DriverWrapperTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.Connection; 26 | import java.sql.DriverManager; 27 | import java.sql.ResultSet; 28 | import java.sql.SQLException; 29 | import java.sql.Statement; 30 | 31 | import javax.sql.DataSource; 32 | 33 | import org.junit.Assert; 34 | import org.junit.Test; 35 | 36 | /** 37 | * Test PostGIS connection. 38 | * @author Sebastian Baumhekel 39 | */ 40 | @SuppressWarnings("javadoc") 41 | public class DriverWrapperTest extends DatabaseTestBase 42 | { 43 | @Test 44 | public void testPooled() throws Exception 45 | { 46 | if (!hasDatabase()) 47 | { 48 | return; 49 | } 50 | DataSource ds = getPooledDataSource(); 51 | try (Connection conn = ds.getConnection()) 52 | { 53 | DriverWrapper.registerDataTypes(conn); 54 | try (Statement st = conn.createStatement()) 55 | { 56 | try (ResultSet rs = st.executeQuery("SELECT postgis_version()")) 57 | { 58 | Assert.assertTrue(rs.next()); 59 | Assert.assertNotNull(rs.getString(1)); 60 | } 61 | } 62 | } 63 | closeDataSource(ds); 64 | } 65 | 66 | // test based on https://github.com/postgis/postgis-java/pull/115 67 | @SuppressWarnings({ "static-method", "resource" }) 68 | @Test 69 | public void testThatPostGisDoesNotOverwriteSavedExceptionForUnsupportedConnectionString() 70 | { 71 | try 72 | { 73 | DriverManager.getConnection("jdbc:missing"); 74 | } 75 | catch (SQLException e) 76 | { 77 | // This should not be "Unknown protocol or subprotocol in url jdbc:missing", which 78 | // would indicate that PostGIS threw an exception instead of returning `null` from 79 | // the `connect` method for an unsupported connection string. 80 | // (This is documented in `java.sql.Driver.connect`.) 81 | // 82 | // The former behavior is not desirable as throwing an exception causes a previously 83 | // saved exception from a "better fitting" driver to be overwritten by PostGis, despite 84 | // PostGis not actually being able to handle the connection. 85 | // 86 | // (Imagine an Oracle connection string with a wrong password, in which the Oracle 87 | // driver's exception regarding the wrong password would be replaced with a generic 88 | // nonsensical PostGis exception.) 89 | Assert.assertEquals("No suitable driver found for jdbc:missing", e.getMessage()); 90 | } 91 | } 92 | 93 | @Test 94 | public void testUnpooled() throws Exception 95 | { 96 | if (!hasDatabase()) 97 | { 98 | return; 99 | } 100 | DataSource ds = getUnpooledDataSource(); 101 | try (Connection conn = ds.getConnection()) 102 | { 103 | DriverWrapper.registerDataTypes(conn); 104 | try (Statement st = conn.createStatement()) 105 | { 106 | try (ResultSet rs = st.executeQuery("SELECT postgis_version()")) 107 | { 108 | Assert.assertTrue(rs.next()); 109 | Assert.assertNotNull(rs.getString(1)); 110 | } 111 | } 112 | } 113 | closeDataSource(ds); 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/EmptyGeometriesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.Connection; 26 | import java.sql.PreparedStatement; 27 | import java.sql.ResultSet; 28 | import java.sql.SQLException; 29 | import java.sql.Statement; 30 | import java.util.ArrayList; 31 | import java.util.List; 32 | 33 | import org.junit.Test; 34 | import org.slf4j.Logger; 35 | import org.slf4j.LoggerFactory; 36 | 37 | /** 38 | * This class contains tests for handling of empty geometries. 39 | * @author Phillip Ross {@literal } 40 | */ 41 | @SuppressWarnings("javadoc") 42 | public class EmptyGeometriesTest extends DatabaseTestBase 43 | { 44 | private static final String[] castTypes = new String[] { "bytea", "text", "geometry" }; 45 | 46 | private static final String[] geometriesToTest = new String[] { "POINT", "LINESTRING", "POLYGON", "MULTIPOINT", 47 | "MULTILINESTRING", "MULTIPOLYGON", "GEOMETRYCOLLECTION", }; 48 | 49 | private static final Logger logger = LoggerFactory.getLogger(EmptyGeometriesTest.class); 50 | 51 | private Connection connection = null; 52 | 53 | private Statement statement = null; 54 | 55 | private static List generateSqlStatements() 56 | { 57 | List sqlStatementList = new ArrayList<>(); 58 | for (String geometry : geometriesToTest) 59 | { 60 | StringBuilder stringBuilder = new StringBuilder("select "); 61 | for (String castType : castTypes) 62 | { 63 | stringBuilder.append("geometry_in('").append(geometry).append(" EMPTY')::").append(castType) 64 | .append(", "); 65 | } 66 | String sqlStatement = stringBuilder.substring(0, stringBuilder.lastIndexOf(",")); 67 | logger.debug("generate sql statement: {}", sqlStatement); 68 | sqlStatementList.add(sqlStatement); 69 | } 70 | return sqlStatementList; 71 | } 72 | 73 | /* 74 | * (non-Javadoc) 75 | * @see io.github.sebasbaumh.postgis.DatabaseTest#afterDatabaseSetup() 76 | */ 77 | @Override 78 | protected void afterDatabaseSetup() throws SQLException 79 | { 80 | connection = getConnection(); 81 | statement = connection.createStatement(); 82 | } 83 | 84 | /* 85 | * (non-Javadoc) 86 | * @see io.github.sebasbaumh.postgis.DatabaseTest#beforeDatabaseShutdown() 87 | */ 88 | @Override 89 | protected void beforeDatabaseShutdown() throws SQLException 90 | { 91 | if ((statement != null) && (!statement.isClosed())) 92 | { 93 | statement.close(); 94 | } 95 | if ((connection != null) && (!connection.isClosed())) 96 | { 97 | connection.close(); 98 | } 99 | } 100 | 101 | @Test 102 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("SQL_INJECTION_JDBC") 103 | public void testSqlStatements() throws SQLException 104 | { 105 | if (!hasDatabase()) 106 | { 107 | return; 108 | } 109 | for (String sqlStatement : generateSqlStatements()) 110 | { 111 | logger.debug("**********"); 112 | logger.debug("* Executing sql statemnent => [{}]", sqlStatement); 113 | logger.debug("**********"); 114 | try (PreparedStatement preparedStatement = connection.prepareStatement(sqlStatement); 115 | ResultSet resultSet = preparedStatement.executeQuery()) 116 | { 117 | resultSet.next(); 118 | for (int i = 1; i <= 3; i++) 119 | { 120 | Object resultSetObject = resultSet.getObject(i); 121 | logger.debug("returned resultSetObject {} => (class=[{}]) {}", i, 122 | resultSetObject.getClass().getName(), resultSetObject); 123 | } 124 | } 125 | } 126 | } 127 | 128 | } -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/GeographyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.SQLException; 26 | 27 | import org.junit.Test; 28 | 29 | /** 30 | * Test geometries of geography type. 31 | * @author Sebastian Baumhekel 32 | */ 33 | @SuppressWarnings("javadoc") 34 | public class GeographyTest extends PostgisDatabaseTest 35 | { 36 | private static final String LNG_STR = "LINESTRING (10 10 20,20 20 20, 50 50 50, 34 34 34)"; 37 | 38 | private static final String MLNG_STR = "MULTILINESTRING ((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"; 39 | 40 | private static final String MPLG_STR = "MULTIPOLYGON (((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"; 41 | 42 | private static final String PLG_STR = "POLYGON ((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"; 43 | 44 | private static final String PTG_STR = "POINT(10 10 20)"; 45 | 46 | @SuppressWarnings("unchecked") 47 | private T assertGeometry(Class clazz, String wkt) throws SQLException 48 | { 49 | Geometry geom = getGeographyGeometryFromWKT(wkt); 50 | if (clazz.isInstance(geom)) 51 | { 52 | return (T) geom; 53 | } 54 | throw new IllegalArgumentException( 55 | "expected: " + clazz.getCanonicalName() + " got: " + geom.getClass().getCanonicalName()); 56 | } 57 | 58 | @Test 59 | public void testLineString() throws SQLException 60 | { 61 | if (!hasDatabase()) 62 | { 63 | return; 64 | } 65 | assertGeometry(LineString.class, LNG_STR); 66 | } 67 | 68 | @Test 69 | public void testMultiLineString() throws SQLException 70 | { 71 | if (!hasDatabase()) 72 | { 73 | return; 74 | } 75 | assertGeometry(MultiLineString.class, MLNG_STR); 76 | } 77 | 78 | @Test 79 | public void testMultiPolygon() throws SQLException 80 | { 81 | if (!hasDatabase()) 82 | { 83 | return; 84 | } 85 | assertGeometry(MultiPolygon.class, MPLG_STR); 86 | } 87 | 88 | @SuppressWarnings("unused") 89 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("DLS_DEAD_LOCAL_STORE") 90 | @Test 91 | public void testPGgeometry() throws SQLException 92 | { 93 | if (!hasDatabase()) 94 | { 95 | return; 96 | } 97 | new PGgeometry(getWKBFromWKT(MLNG_STR)); 98 | } 99 | 100 | @Test 101 | public void testPoint() throws SQLException 102 | { 103 | if (!hasDatabase()) 104 | { 105 | return; 106 | } 107 | assertGeometry(Point.class, PTG_STR); 108 | } 109 | 110 | @Test 111 | public void testPolygon() throws SQLException 112 | { 113 | if (!hasDatabase()) 114 | { 115 | return; 116 | } 117 | assertGeometry(Polygon.class, PLG_STR); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/PostgisDatabaseTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.Connection; 26 | import java.sql.ResultSet; 27 | import java.sql.SQLException; 28 | import java.sql.Statement; 29 | 30 | import org.junit.Assert; 31 | import org.junit.Test; 32 | 33 | /** 34 | * Test PostGIS connection. 35 | * @author Sebastian Baumhekel 36 | */ 37 | @SuppressWarnings("javadoc") 38 | public class PostgisDatabaseTest extends DatabaseTestBase 39 | { 40 | 41 | @Test 42 | public void test() throws SQLException 43 | { 44 | if (!hasDatabase()) 45 | { 46 | return; 47 | } 48 | try (Connection conn = getConnection()) 49 | { 50 | try (Statement st = conn.createStatement()) 51 | { 52 | try (ResultSet rs = st.executeQuery("SELECT postgis_version()")) 53 | { 54 | Assert.assertTrue(rs.next()); 55 | Assert.assertNotNull(rs.getString(1)); 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/SerializationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.io.ByteArrayOutputStream; 26 | import java.io.NotSerializableException; 27 | import java.io.ObjectOutputStream; 28 | 29 | import org.junit.Assert; 30 | import org.junit.Test; 31 | 32 | @SuppressWarnings("javadoc") 33 | public class SerializationTest extends DatabaseTestBase 34 | { 35 | 36 | @Test 37 | public void serializationCheckPGgeometry() throws Exception 38 | { 39 | if (!hasDatabase()) 40 | { 41 | return; 42 | } 43 | try 44 | { 45 | new ObjectOutputStream(new ByteArrayOutputStream()) 46 | .writeObject(new PGgeometry(getWKBFromWKT("MULTIPOLYGON(((1 1,1 2,2 1,1 1)))"))); 47 | } 48 | catch (NotSerializableException ex) 49 | { 50 | Assert.fail("serialization of PGgeometry failed: " + ex); 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/ServerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.Connection; 26 | import java.sql.DatabaseMetaData; 27 | import java.sql.ResultSet; 28 | import java.sql.SQLException; 29 | import java.sql.Statement; 30 | import java.util.UUID; 31 | 32 | import org.junit.Test; 33 | import org.slf4j.Logger; 34 | import org.slf4j.LoggerFactory; 35 | 36 | @SuppressWarnings("javadoc") 37 | public class ServerTest extends DatabaseTestBase 38 | { 39 | 40 | private static final String DATABASE_TABLE_NAME_PREFIX = "jdbc_test"; 41 | private static final Logger logger = LoggerFactory.getLogger(ServerTest.class); 42 | private Connection connection = null; 43 | private Statement statement = null; 44 | 45 | /* 46 | * (non-Javadoc) 47 | * @see io.github.sebasbaumh.postgis.DatabaseTest#afterDatabaseSetup() 48 | */ 49 | @Override 50 | protected void afterDatabaseSetup() throws SQLException 51 | { 52 | connection = getConnection(); 53 | statement = connection.createStatement(); 54 | } 55 | 56 | /* 57 | * (non-Javadoc) 58 | * @see io.github.sebasbaumh.postgis.DatabaseTest#beforeDatabaseShutdown() 59 | */ 60 | @Override 61 | protected void beforeDatabaseShutdown() throws SQLException 62 | { 63 | if ((statement != null) && (!statement.isClosed())) 64 | { 65 | statement.close(); 66 | } 67 | if ((connection != null) && (!connection.isClosed())) 68 | { 69 | connection.close(); 70 | } 71 | } 72 | 73 | @Test 74 | public void testServer() throws Exception 75 | { 76 | if (!hasDatabase()) 77 | { 78 | return; 79 | } 80 | 81 | String dbtable = DATABASE_TABLE_NAME_PREFIX + "_" 82 | + UUID.randomUUID().toString().replaceAll("-", "").toLowerCase(); 83 | 84 | String dropSQL = "drop table " + dbtable; 85 | String createSQL = "create table " + dbtable + " (geom geometry, id int4)"; 86 | String insertPointSQL = "insert into " + dbtable + " values ('POINT (10 10 10)',1)"; 87 | String insertPolygonSQL = "insert into " + dbtable 88 | + " values ('POLYGON ((0 0 0,0 10 0,10 10 0,10 0 0,0 0 0))',2)"; 89 | 90 | logger.debug("Adding geometric type entries..."); 91 | ((org.postgresql.PGConnection) connection).addDataType("geometry", PGgeometry.class); 92 | ((org.postgresql.PGConnection) connection).addDataType("box2d", PGbox2d.class); 93 | ((org.postgresql.PGConnection) connection).addDataType("box3d", PGbox3d.class); 94 | 95 | logger.debug("Creating table with geometric types..."); 96 | boolean tableExists = false; 97 | DatabaseMetaData databaseMetaData = connection.getMetaData(); 98 | try (ResultSet resultSet = databaseMetaData.getTables(null, null, dbtable, new String[] { "TABLE" })) 99 | { 100 | while (resultSet.next()) 101 | { 102 | tableExists = true; 103 | break; 104 | } 105 | } 106 | if (tableExists) 107 | { 108 | statement.execute(dropSQL); 109 | } 110 | statement.execute(createSQL); 111 | try 112 | { 113 | logger.debug("Inserting point..."); 114 | statement.execute(insertPointSQL); 115 | 116 | logger.debug("Inserting polygon..."); 117 | statement.execute(insertPolygonSQL); 118 | 119 | logger.debug("Querying table..."); 120 | try (ResultSet resultSet = statement.executeQuery("select ST_AsText(geom),id from " + dbtable)) 121 | { 122 | while (resultSet.next()) 123 | { 124 | Object obj = resultSet.getObject(1); 125 | int id = resultSet.getInt(2); 126 | logger.debug("Row {}: {}", id, obj); 127 | } 128 | } 129 | } 130 | finally 131 | { 132 | // make sure to remove the table afterwards 133 | statement.execute(dropSQL); 134 | } 135 | } 136 | 137 | } -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/ServiceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.Driver; 26 | import java.sql.DriverManager; 27 | import java.sql.SQLException; 28 | 29 | import org.junit.Assert; 30 | import org.junit.Test; 31 | 32 | /** 33 | * Tests to ensure that the drivers that are registered as services in META-INF/services/java.sql.Driver are resolved 34 | * correctly. Ported from postgis-java. 35 | */ 36 | @SuppressWarnings({ "static-method", "javadoc" }) 37 | public class ServiceTest 38 | { 39 | 40 | @Test 41 | public void testWrapperService() throws SQLException 42 | { 43 | String jdbcUrl = System.getProperty(DatabaseTestBase.CONFIG_JDBC_URL); 44 | if (jdbcUrl == null) 45 | { 46 | System.out.println("Tests are running without a database"); 47 | return; 48 | } 49 | 50 | if (jdbcUrl.startsWith(DriverWrapper.POSTGRES_PROTOCOL)) 51 | { 52 | jdbcUrl = DriverWrapper.POSTGIS_PROTOCOL + jdbcUrl.substring(DriverWrapper.POSTGRES_PROTOCOL.length()); 53 | } 54 | else 55 | { 56 | throw new SQLException("Unknown protocol or subprotocol in url: " + jdbcUrl); 57 | } 58 | Driver driver = DriverManager.getDriver(jdbcUrl); 59 | Assert.assertEquals(DriverWrapper.class, driver.getClass()); 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/TokenizerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.util.List; 26 | 27 | import org.junit.Test; 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | 31 | @SuppressWarnings({ "static-method", "javadoc" }) 32 | public class TokenizerTest 33 | { 34 | 35 | private static final Logger logger = LoggerFactory.getLogger(TokenizerTest.class); 36 | 37 | @Test 38 | public void testTokenizer() 39 | { 40 | char delimiterL1 = ','; 41 | char delimiterL2 = ' '; 42 | String stringToTokenize = "((1 2 3),(4 5 6),(7 8 9)"; 43 | logger.debug("tokenizing string value => {}", stringToTokenize); 44 | List tokensLevel1 = PostGisUtil.split(PostGisUtil.removeBrackets(stringToTokenize), delimiterL1); 45 | logger.debug("level 1 tokens [delimiter = {}] [tokenCount = {}]", delimiterL1, tokensLevel1.size()); 46 | for (String tokenL1 : tokensLevel1) 47 | { 48 | logger.debug("L1 token => {} / {}", tokenL1, PostGisUtil.removeBrackets(tokenL1)); 49 | List tokensLevel2 = PostGisUtil.split(PostGisUtil.removeBrackets(tokenL1), delimiterL2); 50 | logger.debug("level 2 tokens [delimiter = {}] [tokenCount = {}]", delimiterL2, tokensLevel2.size()); 51 | for (String tokenL2 : tokensLevel2) 52 | { 53 | logger.debug("L2 token => {} / {}", tokenL2, PostGisUtil.removeBrackets(tokenL2)); 54 | } 55 | } 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /src/test/java/io/github/sebasbaumh/postgis/VersionPrinterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * PostGIS extension for PostgreSQL JDBC driver 3 | * 4 | * (C) 2004 Paul Ramsey, pramsey@refractions.net 5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com 6 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com 7 | * (C) 2018-2023 Sebastian Baumhekel, sebastian.baumhekel@gmail.com 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library. If not, see . 21 | */ 22 | 23 | package io.github.sebasbaumh.postgis; 24 | 25 | import java.sql.Connection; 26 | import java.sql.ResultSet; 27 | import java.sql.SQLException; 28 | import java.sql.Statement; 29 | 30 | import org.junit.Assert; 31 | import org.junit.Test; 32 | import org.postgresql.Driver; 33 | import org.postgresql.util.PSQLState; 34 | import org.slf4j.Logger; 35 | import org.slf4j.LoggerFactory; 36 | 37 | /** 38 | * Prints out as much version information as available. 39 | */ 40 | @SuppressWarnings("javadoc") 41 | public class VersionPrinterTest extends DatabaseTestBase 42 | { 43 | 44 | private static final Logger logger = LoggerFactory.getLogger(VersionPrinterTest.class); 45 | 46 | private static final String[] POSTGIS_FUNCTIONS = { "postgis_version", "postgis_proj_version", 47 | "postgis_scripts_installed", "postgis_lib_version", "postgis_scripts_released", "postgis_uses_stats", 48 | "postgis_geos_version", "postgis_scripts_build_date", "postgis_lib_build_date", "postgis_full_version", 49 | "postgis_gdal_version", "postgis_libjson_version", "postgis_libxml_version", "postgis_raster_lib_version", 50 | "postgis_svn_version" }; 51 | 52 | private Connection connection = null; 53 | private Statement statement = null; 54 | 55 | /* 56 | * (non-Javadoc) 57 | * @see io.github.sebasbaumh.postgis.DatabaseTest#afterDatabaseSetup() 58 | */ 59 | @Override 60 | protected void afterDatabaseSetup() throws SQLException 61 | { 62 | connection = getConnection(); 63 | statement = connection.createStatement(); 64 | } 65 | 66 | /* 67 | * (non-Javadoc) 68 | * @see io.github.sebasbaumh.postgis.DatabaseTest#beforeDatabaseShutdown() 69 | */ 70 | @Override 71 | protected void beforeDatabaseShutdown() throws SQLException 72 | { 73 | if ((statement != null) && (!statement.isClosed())) 74 | { 75 | statement.close(); 76 | } 77 | if ((connection != null) && (!connection.isClosed())) 78 | { 79 | connection.close(); 80 | } 81 | } 82 | 83 | private String getVersionString(String function) throws SQLException 84 | { 85 | String result = "-- unavailable -- "; 86 | try 87 | { 88 | try (ResultSet resultSet = statement.executeQuery("SELECT " + function + "()")) 89 | { 90 | if (resultSet.next()) 91 | { 92 | String version = resultSet.getString(1); 93 | if (version != null) 94 | { 95 | result = version.trim(); 96 | } 97 | else 98 | { 99 | result = "-- null result --"; 100 | } 101 | } 102 | else 103 | { 104 | result = "-- no result --"; 105 | } 106 | } 107 | } 108 | catch (SQLException sqle) 109 | { 110 | // If the function does not exist, a SQLException will be thrown, but it should be caught an swallowed if 111 | // the "does not exist" string is in the error message. The SQLException might be thrown for some other 112 | // problem not related to the missing function, so rethrow it if it doesn't contain the string. 113 | if (!PSQLState.UNDEFINED_FUNCTION.getState().equals(sqle.getSQLState())) 114 | { 115 | throw sqle; 116 | } 117 | } 118 | return result; 119 | } 120 | 121 | @Test 122 | @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("CRLF_INJECTION_LOGS") 123 | public void test() throws Exception 124 | { 125 | if (!hasDatabase()) 126 | { 127 | return; 128 | } 129 | 130 | // Print PostGIS version 131 | logger.info("*** PostGIS jdbc client code ***"); 132 | // Print PostgreSQL JDBC Versions 133 | logger.info("*** PostgreSQL JDBC Driver ***"); 134 | @SuppressWarnings("deprecation") 135 | String driverVersion = Driver.getVersion(); 136 | Assert.assertNotNull(driverVersion); 137 | logger.info("\t getVersion: {}", driverVersion); 138 | 139 | try 140 | { 141 | Driver driver = new Driver(); 142 | int majorVersion = driver.getMajorVersion(); 143 | Assert.assertNotEquals(majorVersion, 0); 144 | logger.info("\t getMajorVersion: {}", majorVersion); 145 | int minorVersion = driver.getMinorVersion(); 146 | Assert.assertNotEquals(minorVersion, 0); 147 | logger.info("\t getMinorVersion: {}", majorVersion); 148 | } 149 | catch (Exception e) 150 | { 151 | logger.error("Cannot create Driver instance: {}", e.getMessage()); 152 | } 153 | 154 | // Print PostgreSQL server versions 155 | Assert.assertNotNull(connection); 156 | logger.info("*** PostgreSQL Server ***"); 157 | String versionString = getVersionString("version"); 158 | logger.info("\t version: {}", versionString); 159 | 160 | // Print PostGIS versions 161 | logger.info("*** PostGIS Server ***"); 162 | for (String GISVERSION : POSTGIS_FUNCTIONS) 163 | { 164 | versionString = getVersionString(GISVERSION); 165 | logger.info("\t {} version: {}", GISVERSION, versionString); 166 | } 167 | } 168 | 169 | } --------------------------------------------------------------------------------