6.4 Relational Boolean Operators
6.4.3 Algorithm
In order to calculate theDimension Extended 9-Intersection matrixit is necessary to compute the intersections between the line segments of the two input geometries. Hence, a great part of the overlay operation code is reused in this implementation. 1. Create two topological graphs A and B, one for each input geometry(the
same as step 1 in map overlay)
2. Compute the self intersections of each input geometry in A and B(the same as step 3 in map overlay)
3. Compute the intersections between the two input geometries in A and B
(the same as step 4 in map overlay)
4. Label edges and nodes of the two geometriesin A and B in relation to the other input geometry (uses the same code as step 7 in map overlay)
5. Compute the labelling for isolated components of the graph (uses same code as step 8 in map overlay)
6. Compute the intersection matrix by evaluating the labelling of all nodes and edges. Each component sets the value of the intersection matrix at the position according to its label´s attributes to its topological dimension if the previous value at this position is not higher than the new value:
• A node with the attributesa= label[0][on](which is from the set{Inte- rior, Boundary, Exterior}) for its label in relation to A andb=label[1][on] for its label in relation to B object will set the value of the intersection matrix at position[a][b]to at least 0, because the intersection at this posi- tion is a point.
• An edge with the attributeso0 = label[0][on](position in relation to A) ando1 = label[1][on](position in relation to B) will set the value of the intersection matrix at position[a][b]to at least 1, because the intersection at this position is a line. If the edge was created by a polygon boundary, i.e. it describes an area, the intersection dimension of the left (l0 =
label[0][lef t]andl1 = label[1][lef t]) and right side (r0 =label[0][right] andr1 =label[1][right]) of the edge will be evaluated as well. The value of the intersection matrix at position[l0][l1]and[r0][r1]will be set to at least 2, because the intersections at these positions are areas.
The last step of the algorithm uses the following functions, which are described in pseudo code, for each node and edge [viv03b]:
function Node.computeIM(im : IntersectionMatrix) if (label[0] != null and label[1] != null) then
im.setAtLeast(label[0][On], label[1][On], 0) end if
end function
function Edge.computeIM(im : IntersectionMatrix) if (label[0] != null and label[1] != null) then
im.setAtLeast(label[0][On], label[1][On], 1) im.setAtLeast(label[0][Left], label[1][Left], 2) im.setAtLeast(label[0][Right], label[1][Right], 2) end if
end function
Listing 6.1:Functions for nodes and edges to set the intersection matrix
Once the intersection matrix is calculated, it is only necessary to compare it with the configuration of the desired Boolean operator (see previous section Boolean Operators6.4.2).
Since the relational Boolean operators are based on the map overlay algorithms, the asymptotic running time complexity of each relational Boolean operator is O(n·log(n) +I ·log(n)), wherenis the complexity of both geometries, that is the sum of all segments and vertices, andkthe complexity of the overlay, that is the number of all segment intersections within and between two geometric objects. Once all segments are labelled completely, the computation of the intersection matrix is performed in linear time in n and the test for the intersection pattern in constant time. However, prior to performing the map overlay the envelopes of the two objects are tested for intersection. Hence, in the event of disjoint envelopes the result is returned in constant time.
6.5 Constructive Operations
6.5.1 Buffer
The buffer operation extends the geometric object in a certain radius. This opera- tion was not implemented in this work, but is described for the sake of complete- ness. Buffers can be distinguished into positive and negative buffers. A positive buffer extends the point set, a negative buffer diminishes the point set. Figure 6.23 illustrates example of a curve(c1)and its positive buffer(c2). A surface(s1)can be extended by a positive buffer(s2)or reduced by a negative buffer(s3).
Figure 6.23:Examples of buffers: a positive buffer can be performed on a curve (c2) and surface (s2), a negative buffer only on a surface (s3)
The Abstract Specification defines the syntax for a positive buffer: Geometry getBuffer(double distance)
6.5.2 Centroid
Thecentroidof a geometric object is itscentre of mass. Figure 6.24 shows examples of centroids of different geometric objects. The centroid of a point is the point
itself, the centroid of a straight line lies on the mid of the line, the centroid of a point set is the average of the points and so on. As demonstrated in the examples, the centroid does not necessarily have to lie on the object.
Figure 6.24:Examples of centroids of geometric objects: a point set (a), a straight line (b), a curve (c), a simple polygon (d) and a simple polygon with a hole (e)
The Abstract Specification specifies the centroid operation for allGM_Objects by the method
GM_DirectPosition getCentroid()
The centroid calculation ofPointsandMultiPointsis trivial: for a Point it is the position of the Point itself and for a MultiPoint it is the average of all contained points. The centroid of aCurveis computed by the average of the centroids of its straight CurveSegments, which are weighted by its length:
PN umOf LineSegments
i=1 CentroidOf LineSegmenti∗LineSegmentiLength
CurveLength
ARingand aMultiCurvewill be handled like a curve, splitting its curve elements into LineSegments. The centroid of aCurveBoundary will be the average of the start and end point of the boundary and the centroid of aSurfaceBoundarywill be
computed in the same manner the centroid of a Ring is computed, considering not only the LineSegments of the exterior ring, but also the LineSegments of all interior rings.
Figure 6.25:Centroid of a triangle (a) and centroid of a surface computed by the centroids of the surface triangulation
In contrast to the previous discussed geometric objects, the centroid computa- tion of aSurfaceis not that trivial. A simple approach is to divide the surface into triangles, compute the sum of the centroids of each triangle weighted by its area, and than normalize this sum by the total surface area (see(b)in figure 6.25). This procedure is similar to the computation of the centroid of a curve. The centroid of a triangle is simply the average of its three vertices (see(a)in figure 6.25):
centroid.x centroid.y = p1.x p1.y + p2.x p2.y + p3.x p3.y 3 The area of a triangle with verticesp1,p2andp3is:
AreaT riangle = (p2.x−p1.x)∗(p3.y−p1.y)−(p3.x−p1.x)∗(p2.y−p1.y)
This procedure works, however, the running time costs of a surface triangula- tion may be high. Fortunately there is a simpler method which is based on the fact that the triangulation does not have to be a partition of the surface. By building all triangles between two continuous points of the polygon vertices of the polygon
Figure 6.26:Triangulation by choosing a fixed point instead of partitioning the surface
Figure 6.27:Triangulation of a hole within a surface
and a fixed point, it is possible to calculate the centroid by weighting each of the triangles’ area positively and negatively. In the example in figure 6.26 we chose pointp1 asbase pointfor the triangulation. Each consecutive two vertices build a
triangle with the base point, i.e. (p1, p2, p3),(p1, p3, p4),(p1, p4, p5)and(p1, p5, p6).
As the example shows, triangles can overlap (t1/t2 andt2/t3) and contain parts
which are not part of the original surface (t2andt3).
As in the first approach, the sum of the centroids of each triangle weighted by the area of each triangle is computed. The key observation of the algorithm is that we weigh clockwise oriented triangles positively and counter clockwise oriented triangles negatively with its area. Therefore, counter clockwise oriented triangles are subtracted from the sum. In the example, the trianglest1, t3 andt4
are clockwise oriented and hence added to the centroid sum. The area of triangle t2 will be subtracted as it is counter clockwise oriented. It will subtract exactly
the area which is added twice by the overlapping oft1andt3and the fragment of
t3 which has been added but is not part of the surface. Holes will be handled in
the same manner, however they must always be added with the opposite sign, i.e. triangles which are generated by points of interior rings of the surface boundary will be added to the sum if they are counter clockwise oriented and subtracted from the sum if they are clockwise oriented. Figure 6.27 shows the triangulation of a hole within a surface. The triangulation with the same base point as before generates the three triangles(p1, p7, p8),(p1, p8, p9)and(p1, p9, p7). Ast5 is clock-
wise oriented, it will be subtracted from the sum. The fragment which has been subtracted from the sum, but forms part of the surface, will be compensated by the addition of the counter clockwise oriented trianglest6andt7.
The computation of a centroid has an asymptotic running time ofO(n)wheren is
• the number of points in case of a point or point set (that is Point, MultiPoint, CurveBoundary, CompositePoint)
• the number of line segments in case of a Curve, Ring, Multicurve or Surface- Boundary
• the number of control points in case of a Surface or MultiSurface
The algorithm is an extension of the approach that is described in [wwwa]. However, it does not consider holes. As most of the implemented operations, the actual configuration of the centroid implementation uses the floating-point arithmetic class for the elementary arithmetic operations in order to compute the centroid coordinates. Hence, floating-point rounding errors may occur, which may influence the accuracy of the result. However, the algorithm is still robust.
Given that the centroid computation of points and lines is simply based on the average of all components, the algorithm works in 2D, 2.5D and 3D for Points, MultiPoints, Curves, MultiCurves, Rings, CurveBoundaries and SurfaceBound- aries. Geometric objects which represent an area such as Surface, MultiSurface and CompositeSurface are only supported in two dimensional manner without elevation.
6.5.3 Convex Hull
Theconvex hullof a set of pointsS, also known as theconvex envelope, is the mini- mal convex set containingS. In the plane it may be easily visualized by imagining an elastic band stretched open to encompass the geometric object. Figure 6.28 shows examples of convex hulls for a point set, curves and surfaces. The convex hull is used, for example, in the collision detection specially in computer games. The collision between two convex objects can be computed much faster than between two concave objects. Only in case of collision between the convex hulls the real costly collision between the original objects will be calculated.
Figure 6.28:Examples of convex hulls: Surface (a), MultiSurface (b), MultiPoint (c), straight Curve (d), Curve(e) and MultiCurve(f)
There are several ways to compute the convex hull of a geometric object rep- resented by a point set. One of the most used optimal algorithms is theGraham’s scanwhich is based on [And79] and the first algorithms of Graham [Gra72]. The Graham’s scan is an incremental algorithm. This means that it adds the points in Sone by one, updating the solution after each addition. The points will be added from left to right in lexicographic order (seeLexicographic Comparison of two Points in 6.2). As it is convenient that the later convex hull vertices are ordered from left to right as well, i.e. in clockwise order, the algorithm first calculates the upper part
Figure 6.29:The Graham’s scan algorithm computes the upper and lower hull separately from left to right and deletes points which do not result in a right turn
of the hull which begins atp1and ends at apnand then, in a second scan, the lower
part of the hull which begins atpnand ends atp1(see illustration(b)in figure 6.29).
The basic step in the algorithm is the update of the actual hull after each addition. We verify the last three vertices in order to determine whether the new hull is still convex. If the last three vertices describe a right turn, we can proceed to the next point. If the three vertices describe a left turn we delete the middle point of the three points from the result list because it lies within the convex hull and is not a convex hull vertex. As the previous points may still describe a left turn, we loop this verification for each three last points until the last three points make a right turn or there are only two points left. Figure 6.29(a)shows this proceeding. The pointsp1,p2,p3andp4 were added. Now we addpi. The last three verticesp3,p4
andpimake a left turn so that the middle pointp4will be deleted. Asp2,p3andpi
still make a left turn, the middle pointp3 will be deleted as well. Afterwards the
last three points p1, p2 andpi describe a convex curve so that the algorithm can
proceed with the next point afterpi. In case of collinearity of the last three points,
the algorithm behaves in the same way as in case of a left turn. After the upper hull is calculated, the algorithm calculates the lower hull by adding the points from right to left. The result of the algorithm is a clockwise ordered list of points that represents the convex hull ofS.
The Abstract Specification defines the convex hull operation for all GM_- Objects:
GM_Object getConvexHull() The implemented operation returns
• a Point for the convex hull represented by a single point. This is always the convex hull of a Point or CompositePoint.
• a straight Curve (see(d)in figure 6.29) for a convex hull operation on a topo- logical equally straight curve (that can be a Curve, MultiCurve or Compos- iteCurve) or a MultiPoint with only two elements (or more, but collinear) • a Surface for all other geometric objects with three or more non-collinear
points
In a set ofn points in the plane the Graham’s scan computes the convex hull in O(nlog(n)) time. The implementation adopted from the JTS uses a previous coordinate filter to eliminate redundant points, and a special heuristic to reduce the number of points, if there are many points. The heuristic searches for an octa- hedron lying within or on the convex hull and can then delete all points which lie within the octahedron, as they are not candidates for vertices of the convex hull. The octahedron is calculated by finding the eight extreme points with the follow- ing attributes: lowest x value, lowest y value, lowest x+y value, lowest x-y value, highest x value, highest y value, highest x+y value and highest x-y value. The cal- culation of this additional filter needs linear time. Thus it does not influence the asymptotic running time of the complete operation. However, it is only recom- mended for large coordinate sets as it contains a certain overhead. The JTS default value is 50, which is an appropriate limit where the Graham’s scan will perform slower than the optimized procedure for large data sets.
6.6 Metric Operations
6.6.1 Distance
One of the most important attributes in the relationship between two geometric objects is the shortest distance between them. For many higher algorithms, this is one of the essential basic functions to support them. The method is specified as follows:
double getDistance(Geometry geometry)
The shortest distance between two geoemtric objects is the distance between their two closest points. This search of those points a typical problem in com- putational geometry. Due to the time limit, the distance operation has not been implemented in this work. A simple approach to find the two closest points in
two sets is the comparison of all segments of the two sets. This needs quadratic running time. The JTS’s distance operation follows such an approach and could be adapted in our implementation. Its performance can be bettered by implementing special filter to perform less comparisons.
7 Testing Suite
7.1 Test Environment
Software development is subject to the developer’s creation. Standards and cod- ing conventions may help unify source code and increase its quality, but do not guarantee its correctness. Testing helps identify the correctness, completeness, security, and quality of software. It is an instrument to assure that the developed software behaves as it is supposed to. Testing may be viewed as a sub-field of software quality assurance, but it is often seen as a separate field.
There are many ways and instruments to test a software. In Java software devel- opment, the most common testing tool isJUnit. It is one of the most successful testing frameworks which providesTest-Driven development, a development tech- nique where, first, a test case is written and, then, the code necessary to pass the test is implemented. JUnit is flexible and scalable and is not limited to any kind of software. A complex enterprise application can be tested just as an abstract software component such as this geometry implementation.
JUnit is based on the assertion of assumptions. The assertions are provided by a large number of classes and operations. The classAssertcontains many meth- ods such asassertEquals,assertNull,assertNotNull,assertNotSame, assertTrueorassertFalseto verify an assertion. For example
assertTrue(result1 == 10); assertNotNull(result2);
will verify thatresult1’s value is10and result2is an initialized object and notnull.
Most of the important Java IDEs (such as Eclipse) integrate JUnit as their stan- dard testing tool and provide GUIs to process and evaluate their tests accordingly. JUnit consists ofTestCases. TestCases contain the real tests, i.e. the verification of assumptions through methods provided by JUnit. A TestCase can be run individ-
Figure 7.1:Hierarchy of TestSuites and TestCases
ually. However, the number of TestCases increases with the complexity of the soft- ware. JUnit solves this problem throughTestSuites, which calls certain TestCases. A TestCase can be called by different TestSuites and a TestSuite itself can also be called by other Testsuites. This feature enables JUnit to represent complex hierar- chies by modular and flexible test components. Figure 7.1 examples the hierarchy of the test suites and cases in this implementation.
7.2 Test Methodology
In general, TestCases are divided between each data type. Some data types, such as the different boundary types, are summarized into one TestCase. The tests include the verification of correctness of:
• The constructors of the data types, tested by direct instantiation.
• The methods of the factory classes in order to instantiate objects. Depend- ing on the definition of the factory method, in some cases, it must be tested whether the new instance’s components are really new objects instead of ref- erences to existing objects.
• Characteristics of geometric objects. This includes the MbRegion, Represen-