Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Keep M measures when writing to WKB and reading from WKB #734

Merged
merged 4 commits into from
Aug 26, 2024

Conversation

kaiwinter
Copy link
Contributor

@kaiwinter kaiwinter commented May 29, 2021

The changes I made (adding ordinateFlags) are mainly taken over from the WKTReader/WKTWriter.

@kaiwinter kaiwinter changed the title Keep M coordinates when writing to WKB Keep M coordinates when writing to WKB and reading from WKB Jun 10, 2021
@kaiwinter
Copy link
Contributor Author

Are there still open issues or may this PR be merged?

@oers
Copy link

oers commented Sep 9, 2022

Any status on this?

@oers
Copy link

oers commented Sep 9, 2022

I had to fix this in WKBWriter, to make it work with XYZM

    private void writeCoordinate(CoordinateSequence seq, int index, OutStream os)
            throws IOException
    {
        ByteOrderValues.putDouble(seq.getX(index), buf, byteOrder);
        os.write(buf, 8);
        ByteOrderValues.putDouble(seq.getY(index), buf, byteOrder);
        os.write(buf, 8);

        // only write 3rd dim if caller has requested it for this writer
        if (outputDimension >= 3) {
            // if 3rd dim is requested, only write it if the CoordinateSequence provides it
            double ordVal = Coordinate.NULL_ORDINATE;
            if (seq.getDimension() == 3)
                ordVal = seq.getOrdinate(index, 2);
            ByteOrderValues.putDouble(ordVal, buf, byteOrder);
            os.write(buf, 8);
        }
        // only write 4th dim if caller has requested it for this writer
        if (outputDimension == 4) {
            // if 4th dim is requested, only write it if the CoordinateSequence provides it
            double ordVal = Coordinate.NULL_ORDINATE;
            if (seq.getDimension() == 4)
                ordVal = seq.getOrdinate(index, 3);
            ByteOrderValues.putDouble(ordVal, buf, byteOrder);
            os.write(buf, 8);
        }
    }

Test for XYZM is missing here

@kaiwinter
Copy link
Contributor Author

@oers Does the WKTWriter handle XYZM coordination correctly? If not this should better be fixed together in a new pull request maybe. If it does I could add your fix to this pull request.

@oers
Copy link

oers commented Sep 9, 2022

@kaiwinter yes, the textwriter works correctly. I tested both with XYZM Coordinates (reading and writing)

@kaiwinter
Copy link
Contributor Author

@oers I don't understand the implementation tbh. I tried to adapt an existing unit test but couldn't even get the WKTReader to parse a XYZM coordinate. So I couldn't verify what your change does exactly. Maybe this should better be an own issue and pull request? What does @dr-jts think?

@oers
Copy link

oers commented Sep 12, 2022

The wrong method in WKB Writer never wrote the 4th dimension. My Method fixes this (the new one below. It still had a bug)

    private void writeCoordinate(CoordinateSequence seq, int index, OutStream os)
            throws IOException
    {
        ByteOrderValues.putDouble(seq.getX(index), buf, byteOrder);
        os.write(buf, 8);
        ByteOrderValues.putDouble(seq.getY(index), buf, byteOrder);
        os.write(buf, 8);

        // only write 3rd dim if caller has requested it for this writer
        if (outputDimension >= 3) {
            // if 3rd dim is requested, only write it if the CoordinateSequence provides it
            double ordVal = seq.getOrdinate(index, 2);
            ByteOrderValues.putDouble(ordVal, buf, byteOrder);
            os.write(buf, 8);
        }
        // only write 4th dim if caller has requested it for this writer
        if (outputDimension == 4) {
            // if 4th dim is requested, only write it if the CoordinateSequence provides it
            double ordVal = seq.getOrdinate(index, 3);
            ByteOrderValues.putDouble(ordVal, buf, byteOrder);
            os.write(buf, 8);
        }
    }

My Test is like this:

    @Test
    void wkbLineStringZM() throws ParseException {
        LineString lineZM = fac.createLineString(new Coordinate[]{new CoordinateXYZM(1,2,3,4), new CoordinateXYZM(5,6,7,8)});
        byte[] write = new WKBWriter(4).write(lineZM);


        LineString deserialisiert = (LineString) new PostgisWKBReader().read(write);

        assertEquals(lineZM, deserialisiert);

        for (int i = 0; i < lineZM.getNumPoints() ; i++) {
            Point geometryN = lineZM.getPointN(1);
            Point geometryN1 = deserialisiert.getPointN(1);

            assertFalse(Double.isNaN(geometryN.getCoordinate().getM()));
            assertFalse(Double.isNaN(geometryN.getCoordinate().getZ()));
            assertFalse(Double.isNaN(geometryN1.getCoordinate().getM()), "M is persisted");
            assertFalse(Double.isNaN(geometryN1.getCoordinate().getZ()), "Z is persisted");

            assertEquals(geometryN, geometryN1);
        }
    }

    @Test
    void wktLineStringZM() throws ParseException {
        LineString lineZM = fac.createLineString(new Coordinate[]{new CoordinateXYZM(1,2,3,4), new CoordinateXYZM(5,6,7,8)});
        String write = new WKTWriter(4).write(lineZM);

        LineString deserialisiert = (LineString) new PostgisWKTReader().read(write);

        assertEquals(lineZM, deserialisiert);

        for (int i = 0; i < lineZM.getNumPoints() ; i++) {
            Point geometryN = lineZM.getPointN(1);
            Point geometryN1 = deserialisiert.getPointN(1);

            assertFalse(Double.isNaN(geometryN.getCoordinate().getM()));
            assertFalse(Double.isNaN(geometryN.getCoordinate().getZ()));
            assertFalse(Double.isNaN(geometryN1.getCoordinate().getM()), "M is persisted");
            assertFalse(Double.isNaN(geometryN1.getCoordinate().getZ()), "Z is persisted");

            assertEquals(geometryN, geometryN1);
        }
    }

@kaiwinter
Copy link
Contributor Author

@oers I added your changes to this pull request.

Copy link

@oers oers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I integrated the changes made here in a project that uses postgis 14. Itworks really well.

@jiayuasu
Copy link
Contributor

jiayuasu commented Jan 8, 2024

@kaiwinter @dr-jts Thanks for the great work. Is there a reason why this PR hasn't been merged after a year? Is there anything others could help?

WKB format is often used for geometry serialization. Silently missing the M value will lead to incorrect results. We at Sedona uses WKB to serialize XYZM data for our Snowflake support.

@jodygarnett
Copy link
Contributor

Can you rebase and resolve conflicts please?

@jiayuasu
Copy link
Contributor

jiayuasu commented Aug 23, 2024

@jodygarnett I am not the author of this PR. @kaiwinter could you help us rebase and resolve conflicts?

I will wait for @kaiwinter 2-3 days. If he is busy, I will be happy to take over the codebase and create a new PR.

This issue might affect multiple Java-based DB engines if Parquet's Geometry type gets merged. We would really appreciate your help to accelerate the review of this PR when the new PR / rebase is ready..

M coordinate is read as Z coordinate after writing/reading.
Referring to WKTReader/WKTWriter I added the EnumSet<Ordinate>
ordinateFlags. The WKBWriter uses these ordinateFlags to set the correct
flags on the byte stream.

Signed-off-by: Kai Winter <[email protected]>
Signed-off-by: Kai Winter <[email protected]>
# Conflicts:
#	modules/core/src/main/java/org/locationtech/jts/io/WKBWriter.java
@kaiwinter
Copy link
Contributor Author

I did a rebase. Would be great if the PR finally gets merged.

@jnh5y
Copy link
Contributor

jnh5y commented Aug 23, 2024

I kicked off CI just now; let's see if it builds a-ok!

Copy link
Contributor

@jodygarnett jodygarnett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading through this I only had minor feedback.

I expect that this may break the GeoTools subclass of WKBReader / WKBWriter that handles curves. With that in mind I am going to check with the GeoTools community to see if some of these methods need to be changed to protected (but this can be done in a separate PR).

We have two things of feedback that can be done as distinct PRs to avoid holding this fix up:

  • The use of EnumSet is a nit more complicated then just covering XY, XYM, XYZ, XYZM cases. If desired such a change should happen in several sections of code.
  • WKBWriter / WKBReader have several private methods that GeoTools subclass duplicate since they cannot override.

Is that about it?

@jodygarnett
Copy link
Contributor

I am now testing a local build of this PR for any regression in GeoTools stack.

@jnh5y
Copy link
Contributor

jnh5y commented Aug 26, 2024

I am now testing a local build of this PR for any regression in GeoTools stack.

@jodygarnett cool. Can you make any of your branches public? It'd be awesome to see if @elahrvivaz can test GeoMesa with those branches.

Also, @jiayuasu is there any testing that the Sedona / GeoParquet communities can be doing here?

Generally, I'd like to point out that we have plenty of time to line all this up! Jody started the paperwork with Eclipse which needs to be done before we release. That'll take a few weeks, so we can take our time, etc.

@jodygarnett
Copy link
Contributor

I am taking notes here geotools/geotools#4884

The branch for that PR is https://github.com/jodygarnett/geotools/tree/jts_1.20.0_update

@jodygarnett jodygarnett merged commit 96805bb into locationtech:master Aug 26, 2024
2 checks passed
@jodygarnett jodygarnett added this to the 1.20.0 milestone Aug 26, 2024
@jodygarnett
Copy link
Contributor

Oh I kind of screwed up, this PR should have included a change to the release notes. Something to consider for next time.

@jodygarnett jodygarnett changed the title Keep M coordinates when writing to WKB and reading from WKB Keep M measures when writing to WKB and reading from WKB Aug 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants