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

Infinite Boundary in PolygonSet #49

Open
wardev opened this issue Oct 18, 2018 · 3 comments
Open

Infinite Boundary in PolygonSet #49

wardev opened this issue Oct 18, 2018 · 3 comments
Labels

Comments

@wardev
Copy link
Contributor

wardev commented Oct 18, 2018

The way SphericalPolygonSet (and presumably PolygonSet) implement the checkPoint(...) method can lead to points arbitrarily far away from the center-line of the boundary being considered part of the boundary. This means that points inside a region and far a way from the center-line of the boundary may be considered to be part of the boundary. Similarly points outside the region and far away from it may be considered to be part of the boundary. Here "far" means the tolerance multiplied by some large number.

The article in 1 provides a good description of the issue. Hipparchus is currently using a mitre (at left) which leads to very long points. Using a round (middle) or bevel (right) would fix the issue. I think a round join is the most intuitive meaning for tolerance.

image

I don't know if this is worth fixing or if this is merely a theoretical problem. Maps (one of the use cases for SphericalPolygonSet) tend to have some very strange boundaries.

I've used the code below with a tolerance of 1e-3 to produce the "Hipparchus" points in the plot below. As you can see, even though a point is several orders of magnitude further away from the center-line of the boundary it can still be considered part of the boundary.

            double tol = 0.001;
            int n = 100;
            double step = FastMath.PI /  n;

            for (int i = 0; i < n; i++) {
                double angle = FastMath.PI - i * step;
                RegionFactory<Sphere2D> factory = new RegionFactory<>();
                SphericalPolygonsSet plusX = new SphericalPolygonsSet(Vector3D.PLUS_I, tol);
                SphericalPolygonsSet plusY = new SphericalPolygonsSet(Vector3D.PLUS_J, tol);
                SphericalPolygonsSet plusZ = new SphericalPolygonsSet(new Vector3D(0, -FastMath.cos(angle), FastMath.sin(angle)), tol);
                SphericalPolygonsSet octant =
                        (SphericalPolygonsSet) factory.intersection(factory.intersection(plusX, plusY), plusZ);
                Circle bisect = new Circle(new Vector3D(0, -FastMath.cos(angle / 2), FastMath.sin(angle / 2)), tol);
                final double phase0 = bisect.getPhase(Vector3D.PLUS_I);
                final double boundary = UnivariateSolverUtils.solve(
                        x -> octant.checkPoint(new S2Point(bisect.getPointAt(x))) == Location.OUTSIDE ? 1 : -1,
                        phase0 - FastMath.PI / 2,
                        phase0);
                final double offset = MathUtils.normalizeAngle(boundary, phase0) - phase0;
                out.write(String.format("%20f %20f\n", angle, offset));

image

@maisonobe
Copy link
Contributor

I think this should be worth fixing, but fear it is difficult. I agree the round join is better, it is more compliant with the semantics of the tolerance.
The same problem probably also appears in 3D polyhedrons set.

@wardev
Copy link
Contributor Author

wardev commented Oct 25, 2018

SphericalPolygonSet.projectToBoundary(point).getOffset() seems to compute the offset from the center-line of the boundary and could be used to implement round corners.

@wardev
Copy link
Contributor Author

wardev commented Oct 25, 2018

Correction, there seems to be a discontinuity in the behavior of projectToBoundary() when the angle of the corner crosses 90 degrees:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants