Previous chapters used Apache SIS static methods for convenience. In some cases, usage of those convenience methods can be replaced by Java code using only GeoAPI methods. @@ 206,420 +204,6 @@ public class MyApplication { The advantage of using these interfaces is to provide a unified model to operate two very different APIs, while retaining the ability to switch easily to another library if desired.
    In addition to its own tests, Apache SIS uses tests defined by GeoAPI.  One advantages is that those tests provide an external source for the definition of expected results  (for example the numerical values of coordinates obtained after a map projection).  Such external source reduce the risk that some tests are actually antiregression tests  instead of correctness tests.  Those tests can also be used by projects other than Apache SIS. 

 The geoapiconformance
module provides validators, a JUnit test suite, and report generators
 in the form of HTML pages.
 This module may be used with any GeoAPI implementation.
 For developers of a geospatial library, it offers the following advantages:

geoapiconformance
has its own test suite and is applied to other implementations. GeoAPI can validate an instance of its interfaces by checking that certain constraints are observed.  Many constraints can not be expressed in the method signature. Those constraints  are usually described textually in the abstract specifications or in the javadoc. 
Example:
 A coordinate conversion or transformation (CC_CoordinateOperation
) may require a sequence of several steps.
 In such a sequence of operations (CC_ConcatenatedOperation
), for each step (CC_SingleOperation
)
 the number of output dimensions must equal the number of input dimensions in the next operation.
 Expressed in Java, this constraint stipulates that for the entire index 0 < i < n where n
 is the number of operations, we have coordOperation[i].targetDimensions == coordOperation[i1].sourceDimensions
.

 The easiest way to perform these verifications is to call the static methods validate(…)
 of the org.opengis.test.Validators
class.
 As all of Validators
methods bear the same name, it is enough to write “validate(value)
”
 and then let the compiler choose the most appropriate method for the type of object given in argument.
 If the object type is not known at the time of compilation,
 the dispatch(Object)
method can be invoked for redirecting the work to the most appropriate validate(…)
method.

 All validate(…)
functions follow a chain of dependencies,
 meaning that they will also validate each component of the object to be validated.
 For example, the validation of a GeographicCRS
implies the validation of its component
 GeodeticDatum
, which itself implies the validation of its component Ellipsoid
, and so on.
 Thus it is unnecessary to validate the components explicitely, unless the developer wishes to isolate the test for a particular item known to cause problems.

 By default, validations are as strict as possible. It is always possible to relax certain rules.  The most common is to tolerate the absence of attributes that would normally be mandatory.  This rule and a few others may be modified globally for all tests executed by the currently running JVM,  as in the following example: 
 import org.opengis.metadata.Metadata; import org.opengis.test.Validators; import org.junit.Test;  public class MyTest {  /*  * Tolerate the absence of mandatory attributes in metadata and citation packages.  * This modification applies to all tests executed by the currently running JVM.  * If there are multiple test classes, this initialization may be performed  * in a parent class to all test classes.  */  static {  Validators. DEFAULT.metadata.requireMandatoryAttributes
= false;  Validators.DEFAULT.citation.requireMandatoryAttributes
= false;  }   @Test  public void testMyMetadata() {  Metadata myObject = …; // Create an object here.  Validators.validate
(myObject);  } }
 Rules may also be modified for a particular test suite without affecting the default configuration of the standard JVM.  This approach requires the creation of a new instance of the validator that we wish to modify the configuration. 
 import org.opengis.metadata.Metadata; import org.opengis.test.ValidatorContainer; import org.junit.Test;  public class MyTest {  private final ValidatorContainer validators;   public MyTest() {  validators = new ValidatorContainer();  validators.   metadata.requireMandatoryAttributes
= false;  validators.citation.requireMandatoryAttributes
= false;  }   @Test  public void testMyMetadata() {  Metadata myObject = …; // Create an object here.  validators.validate
(myObject);  } }
 JUnit tests are defined in the org.opengis.test
subpackages.
 All test classes bear a name ending in "Test
".
 GeoAPI also provides an org.opengis.test.TestSuite
class including all test classes defined in the
 geoapiconformance
module, but Apache SIS does not use it.
 Instead, Apache SIS inherits GeoAPI’s *Test
classes on a casebycase basis,
 in the appropriate modules.
 The example below gives an example of a customized GeoAPI test:
 The parent test javadoc
 documents the tests performed in detail.
 In this example, only one test is modified and all the others are inherited as they are (it is not necessary to repeat them in the subclass).
 However, this example adds a supplemental verification, annotated with @After
, which will be executed after each test.

import org.junit.*; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.opengis.test.referencing.ParameterizedTransformTest; import static org.junit.Assert.*;  @RunWith(JUnit4.class) public class MyTest extends ParameterizedTransformTest {  /**  * Specify our own coordinate transformation factory for the GeoAPI tests.  * GeoAPI will test the objects created by this factory.  */  public MyTest() {  super(new MyMathTransformFactory());  }   /**  * Changes the behaviour of a test. This example relaxes the requirements of this test a little,  * by accepting errors of up to 10 centimetres, rather than the default value of 1 cm.  * This change only applies to this method, and does not affect the other inherited tests.  */  @Test  @Override  public void testLambertAzimuthalEqualArea() throws FactoryException, TransformException {    tolerance
= 0.1; // 10 cm tolerance.  super.testLambertAzimuthalEqualArea()
;  }   /**  * Supplemental verification performed after each test, inherited or not.  * In this example, we are verifying that the transformation tested  * works correctly in twodimensional spaces.  */  @After  public void ensureAllTransformAreMath2D() {  assertTrue(transform
instanceof MathTransform2D);  } }
Following chapters explain the rational behind some implementation choices done in Apache SIS.
   Among the many kinds of operations performed by GIS softwares on spatial coordinates,  affine transforms are both relatively simple and very common.  Affine transforms can represent any combination of scales, shears, flips, rotations and translations,  which are linear operations.  Affine transforms can not handle nonlinear operations like map projections,  but the affine transform capabilities nevertheless cover many other cases: 
.tfw
files associated to some TIFF images. Affine transforms can be concatenated efficiently.  No matter how many affine transforms are chained, the result can be represented by a single affine transform.  This property is more easily seen when affine transforms are represented by matrices:  in order to concatenate those operations, we only need to multiply those matrices.  The “pixel to geographic coordinate conversions” case below gives an example. 
 Example:  given an image with pixel coordinates represented by (x,y) tuples  and given the following assumptions: 
Then conversions from pixel coordinates (x,y)  to geographic coordinates (λ,φ) can be represented by the following equations,  where N_{x} is the image width and  N_{y} the image height in number of pixels: 

 Above equations can be represented in matrix form as below: 

 In this particular case, scale factors S are the pixel size in degrees  and translation terms T are the geographic coordinate of an image corner  (not necessarily the lowerleft corner if some axes have been flipped).  This straightforward interpretation holds because of abovecited assumptions, but  matrix coefficients become more complex if the image has shear or rotation  or if pixel coordinates do not start at (0,0).  However it is not necessary to use more complex equations for supporting more generic cases.  The following example starts with an “initial conversion” matrix  where the S and T terms are set to the most straightforward values.  Then the y axis direction is reversed for matching the most common convention in image coordinate systems (change 1),  and axis are swapped resulting in latitude before longitude (change 2).  Note that when affine transform concatenations are written as matrix multiplications, operations are ordered from right to left:  A×B×C is equivalent to first applying operation C,  then operation B and finally operation A. 
             Change 2  Change 1  Initial conversion  Concatenated operation  

×  ×  = 
 A key principle is that there is no need to write Java code dedicated to above kinds of axis changes.  Those operations, and many other, can be handled by matrix algebra.  This approach makes easier to write generic code and improves performance.  Apache SIS follows this principle by using affine transforms for every operations  that can be performed by such transform.  For instance there is no code dedicated to changing order of ordinate values in a coordinate. 
 About all graphical libraries support some kind of coordinate operations, usually as affine transforms  or a slight generalization like perspective transforms.  Each library defines its own API. Some examples are listed below: 
        Library  Transform implementation  Dimensions 

Java2D  java.awt.geom.AffineTransform  2 
Java3D  javax.media.j3d.Transform3D  3 
JavaFX  javafx.scene.transform.Affine  2 or 3 
Java Advanced Imaging (JAI)  javax.media.jai.PerspectiveTransform  2 
Android  android.graphics.Matrix  2 
 However in many cases, affine or perspective transforms are the only kind of coordinate operations supported by the graphical library.
 Apache SIS needs to handle a wider range of operations, in which affine transforms are only special cases.
 In particular most map projections and datum shifts can not be represented by affine transforms.
 SIS also needs to support arbitrary number of dimensions,
 while abovecited API restrict the use to a fixed number of dimensions.
 For those reasons SIS can not use directly the abovecited API.
 Instead, SIS uses the more abstract org.opengis.referencing.transform.MathTransform
interface.
 But in the special case where the transform is actually affine, SIS may try to use an existing implementation,
 in particular Java2D. The following Java code can be used in situations where the Java2D object is desired:

MathTransform mt = ...; // Any math transform created by Apache SIS. if (mt instanceof AffineTransform) {  AffineTransform at = (AffineTransform) mt;  // Use Java2D API from here. } 
 Apache SIS uses Java2D on a best effort basis only.
 The above cast is not guaranteed to succeed,
 even when the MathTransform
meets the requirements allowing Java2D usage.

 GIS make an extensive usage of matrices for displaying maps or for transforming coordinates.  There is many excellent open source or commercial matrix libraries available.  However, GIS have some specific needs that differ a little bit from the goals of many existent libraries.  Matrix operations like those described in the affine transform chapter  appear in almost all coordinate operations applied by Apache SIS.  But the analysis of those operations reveal some patterns: 
Those matrices are almost always of small size, rarely more than 5 rows and 5 columns.
“Heavy” matrix operations (matrix inversions or multiplications) do not happen in performancecritical code.  In almost every cases, those heavy operations are executed only once, for example when a data file is read  or in preparation steps before to transform coordinates.  Those heavy operations rarely happen in the loop that apply the coordinate operation  after we finished to prepare it.
In a sequence of matrix multiplications or inversions, rounding errors accumulate and grow fast.  If the sequence of matrix operations is long enough,  rounding errors can become indistinguishable from real operations like datum shifts.  This ambiguity can happen because the matrix representation of some datum shifts has small values,  with scale factors of a few parts per million and rotation terms of a few arcseconds.
It is quite common that two affine transforms cancel each other when they are concatenated, i.e.  that matrix multiplications result in some or all scale factors equal to 1 and some or all translation terms equal to 0.  However because of rounding errors the results are rarely exact, but are rather some values like 0,9999…97 instead of 1.  The usual workaround is to compare floating point numbers with some tolerance threshold.  Unfortunately it is difficult to choose a threshold that catch a wide range of rounding errors  without wrongly considering legitimate datum shifts as rounding errors (see previous point).
 As a consequence of above points, accuracy of a matrix library is more important than performance for a GIS like Apache SIS.  Paradoxically, a good way to improve performance is to invest more CPU time for more accurate matrix operations  when preparing (not executing) the coordinate operation,  because it increases the chances to correctly detect which operations cancel each other.  This investment can save execution time at the place where it matters most:  in the code looping over millions of coordinates to transform. 
 However matrix libraries are often designed for high performances with large matrices, sometime containing thousands of rows and columns.  Those libraries can efficiently resolve systems of linear equations with hundreds of unknown variables.  Those libraries resolve difficult problems, but not of the same kind than the problems that Apache SIS needs to solve.  For that reason, and also for another reason described in next paragraphs, Apache SIS uses its own matrix implementation.  This implementation addresses the accuracy issue by using “doubledouble” arithmetic  (a technic for simulating the accuracy of approximatively 120 bits wide floating point numbers)  at the cost of performance in a phase (transform preparation) where performance is not considered critical. 
  Apache SIS often needs to inverse matrices, in order to perform a coordinate operation in reverse direction.  Matrix inversions are typically performed on square matrices, but SIS also needs to inverse nonsquare matrices.  Depending on whether we have more lines than columns: 
 To illustrate the issues caused by direct use of libraries designed for linear algebra,  consider a (φ₁, λ₁, h) → (φ₂, λ₂) conversion  from threedimensional points to twodimensional points on a surface.  The φ terms are latitudes, the λ terms are longitudes and  (φ₂, λ₂) may be different than (φ₁, λ₁) if h axis is not perpendicular to the surface. 

 For linear algebra libraries, the above nonsquare matrix represents an underdetermined system of equations and may be considered unresolvable.  Indeed the above coordinate operation can not be inverted as a (φ₂, λ₂) → (φ₁, λ₁, h)  operation because we do not know which value to assign to h.  Ignoring h implies that we can not assign values to (φ₁, λ₁) neither since those values may depend on h.  However in GIS case, the ellipsoidal h axis is perpendicular to the ellipsoid surface  on which the geodetic latitudes and longitudes (φ, λ) are represented  (note that this statement is not true for geocentric latitudes and longitudes).  This perpendicularity makes φ₁ and λ₁ independent of h.  In such cases, we can can still do some processing. 
 Apache SIS proceeds by checking if h values are independent of φ and λ values.
 We identify such cases by checking which matrix coefficients are zero.
 If SIS can identify independent dimensions, it can temporarily exclude those dimensions
 and invert the matrix using only the remaining dimensions.
 If SIS does not found a sufficient amount of independent dimensions, an exception is thrown.
 But if a matrix inversion has been possible, then we need to decide which value to assign to the dimensions that SIS temporarily excluded.
 By default, SIS assigns the NaN
(NotaNumber) value to those dimensions.
 However in the particular case of ellipsoidal height h in a (φ₂, λ₂) → (φ₁, λ₁, h) operation,
 the zero value may also be appropriate on the assumption that the coordinates are usually close to the ellipsoid surface.
 In any case, the coefficients that Apache SIS sets to zero or NaN
is based on the assumption
 that the matrix represents a coordinate operation; this is not something that can be done with arbitrary matrices.

 The abovedescribed approach allows Apache SIS to resolve some underdetermined equation systems commonly found in GIS.
 In our example using NaN
as the default value, the h ordinate stay unknown – we do not create information from nothing –
 but at least the (φ, λ) coordinates are preserved.
 The opposite problem, those of overdetermined equation systems, is more subtile.
 An approach commonly applied by linear algebra libraries is to resolve overdetermined systems by the least squares method.
 Such method applied to our example would compute a (φ₂, λ₂, h) → (φ₁, λ₁) operation
 that seems the best compromise for various φ₂, λ₂ and h values,
 while being (except special cases) an exact solution for noone.
 Furthermore linear combinations between those three variables may be an issue because of heterogenous units of measurement,
 for instance with h in metres and (φ, λ) in degrees.
 Apache SIS rather proceeds in the same way than for underdetermined systems:
 by requiring that some dimensions are independent from other dimensions, otherwise the matrix is considered noninvertible.
 Consequently in overdetermined systems case, SIS may refuse to perform some matrix inversions that linear algebra libraries can do,
 but in case of success the resulting coordinate operation is guaranteed to be exact (ignoring rounding errors).

 In summary, Apache SIS provides its own matrix library for the following reasons: 

 This library is provided in the org.apache.sis.matrix
package of the sisreferencing
module.

 Previous chapters used Apache SIS static methods for convenience.  In some cases, usage of those convenience methods can be replaced by Java code using only GeoAPI methods.  Such replacements may be desirable for applications who want to reduce direct dependency toward Apache SIS,  for example in order to ease migrations between SIS and other GeoAPI implementations.  However this may require that applications write their own convenience methods.  The following sections provide some tip for easing this task. 
 @UML
annotations
 For each class, method and constant defined by an OGC or ISO standard,
 GeoAPI indicates its provenance using annotations defined in the org.opengis.annotation
package.
 This mapping is described in the chapter about GeoAPI.
 Java reflection methods allow access to this information during the execution of an application.
 Class org.apache.sis.util.iso.Types
provides static convenience methods like
 getStandardName(Class)
, but one can avoid those methods.
 The following example displays the standard name for the method getTitle()
from the Citation
interface:

Class<?> type = Citation.class;
Method method = type.getMethod("getTitle
", (Class<?>[]) null);
UML annot = method.getAnnotation(UML.class);
String id = annot.identifier();
System.out.println("The standard name for the " + method.getName() + " method is " + id);


 The reverse operation — getting the Java class and method from a standard name — is a bit more complicated.
 It requires reading the classindex.properties
file provided in the org.opengis.annotation
package.
 The following example reads the files just before searching for the name of the interface corresponding to CI_Citation
.
 Users are always encouraged to only read this file once and then save its contents in their application's cache.

Properties isoToGeoAPI = new Properties(); try (InputStream in = UML.class.getResourceAsStream(" classindex.properties
")) {  isoToGeoAPI.load(in); } String isoName = "CI_Citation
"; String geoName = getProperty(isoName); Class<?> type = Class.forName(geoName); System.out.println("The GeoAPI interface for ISO type " + isoName + " is " + type);
 The org.apache.sis.util.iso.Types
convenience method for above task is
 forStandardName(String)
.

 GeoAPI defines factories (Factory
) that can create implementations of interfaces.
 For example, DatumFactory
provides methods that can create instances which implement interfaces of the
 org.opengis.referencing.datum
package.
 A Factory
must be implemented by a geospatial library,
 and declared as a service as defined by the java.util.ServiceLoader
class.
 The ServiceLoader
javadoc explains this procedure.
 In brief, the library must create a file in the METAINF/services/
directory,
 with a name corresponding to the complete name of an interface in the factory
 (in the preceding example, org.opengis.referencing.datum.DatumFactory
).
 On one line, this text file must include the complete name of the class that implements this interface.
 This class may be hidden from users, as they do not need to know of its existence.

 If the library has correctly declared its factories as services,
 users may import them by using ServiceLoader
, as in the example below.
 This example only takes the first factory located; if there is more than one factory 
 for example when multiple libraries coexist — then the choice is left to the user.

import org.opengis.referencing.GeodeticDatum;
import org.opengis.referencing.DatumFactory;
import java.util.ServiceLoader;

public class MyApplication {
 public void createMyDatum() {
 ServiceLoader loader = ServiceLoader.load(DatumFactory.class);
 DatumFactory factory = loader.iterator().next();
 GeodeticDatum myDatum = factory.createGeodeticDatum
(…);
 }
}



  Implementing GeoAPI oneself in order to meet very specific needs is not difficult.  A developer might concentrate on a handful of interfaces among the hundreds available,  while keeping other interfaces as extension points to eventually implement as needed. 

 The conceptual model that the interfaces represent is complex. But this complexity may be reduced by combining certain interfaces.
 For example, many libraries, even wellknown ones, do not distinguish between a Coordinate System (CS)
 and a Coordinate Reference System (CRS).
 A developer that also wishes not to make this distinction may implement these two interfaces with the same class.
 The resulting implementation may have a simpler class hierarchy than that of GeoAPI interfaces.
 The geoapiexamples
module, discussed later, provides such combinations.
 The following table lists a few possible combinations:

Main Interface  Auxiliary Interface  Use 

CoordinateReferenceSystem  CoordinateSystem  Description of a spatial reference system (CRS). 
GeodeticDatum  Ellipsoid  Description of the geodetic datum. 
CoordinateOperation  MathTransform  Coordinate transformation operations. 
IdentifiedObject  ReferenceIdentifier  An objet (usually a CRS) that we can identify by a code. 
Citation  InternationalString  Bibliographic reference consisting of a simple title. 
GeographicBoundingBox  Extent  Spatial area in degrees of longitude and latitude. 
ParameterValue  ParameterDescriptor  Description of a parameter (name, type) associated with its value. 
ParameterValueGroup  ParameterDescriptorGroup  Description of a set of parameters associated with their values. 
 The geoapiexamples
module provides examples of simple implementations.
 Many of these classes implement more than one interface at a time in order to provide a simpler conceptual model.
 The javadoc for this module
 lists key packages and classes along with the combinations performed.
 This module illustrates not only how GeoAPI might be implemented,
 but also how the implementation might be tested using geoapiconformance
.

 Although its primary goal is to serve as a source of inspiration for implementors,
 geoapiexamples
was also designed so as to be usable by applications with very simple needs.
 As all the examples are in the public domain, developers are invited to freely adapt copies of these classes as necessary.
 However, if changes are made outside the framework of the GeoAPI project,
 fair use demands that modified copies be placed in a package with a different name than org.opengis
.

 For somewhat more involved needs, developers are invited to examine the
 geoapiproj4
and geoapinetcdf
modules.
 These two modules provide examples of adaptors that are allowed, via GeoAPI interfaces,
 to use some of the features of external libraries (Proj.4 and NetCDF).
 The advantage of using these interfaces is to provide a unified model to operate two very different APIs,
 while retaining the ability to switch easily to another library if desired.

In addition to its own tests, Apache SIS uses tests defined by GeoAPI.
One advantages is that those tests provide an external source for the definition of expected results
@@ 372,254 +197,6 @@ public class MyTest extends Parameterize
assertTrue(transform
instanceof MathTransform2D);
}
}




Following chapters explain the rational behind some implementation choices done in Apache SIS.
   Among the many kinds of operations performed by GIS softwares on spatial coordinates,  affine transforms are both relatively simple and very common.  Affine transforms can represent any combination of scales, shears, flips, rotations and translations,  which are linear operations.  Affine transforms can not handle nonlinear operations like map projections,  but the affine transform capabilities nevertheless cover many other cases: 
.tfw
files associated to some TIFF images. Affine transforms can be concatenated efficiently.  No matter how many affine transforms are chained, the result can be represented by a single affine transform.  This property is more easily seen when affine transforms are represented by matrices:  in order to concatenate those operations, we only need to multiply those matrices.  The “pixel to geographic coordinate conversions” case below gives an example. 
 Example:  given an image with pixel coordinates represented by (x,y) tuples  and given the following assumptions: 
Then conversions from pixel coordinates (x,y)  to geographic coordinates (λ,φ) can be represented by the following equations,  where N_{x} is the image width and  N_{y} the image height in number of pixels: 

 Above equations can be represented in matrix form as below: 

 In this particular case, scale factors S are the pixel size in degrees  and translation terms T are the geographic coordinate of an image corner  (not necessarily the lowerleft corner if some axes have been flipped).  This straightforward interpretation holds because of abovecited assumptions, but  matrix coefficients become more complex if the image has shear or rotation  or if pixel coordinates do not start at (0,0).  However it is not necessary to use more complex equations for supporting more generic cases.  The following example starts with an “initial conversion” matrix  where the S and T terms are set to the most straightforward values.  Then the y axis direction is reversed for matching the most common convention in image coordinate systems (change 1),  and axis are swapped resulting in latitude before longitude (change 2).  Note that when affine transform concatenations are written as matrix multiplications, operations are ordered from right to left:  A×B×C is equivalent to first applying operation C,  then operation B and finally operation A. 
             Change 2  Change 1  Initial conversion  Concatenated operation  

×  ×  = 
 A key principle is that there is no need to write Java code dedicated to above kinds of axis changes.  Those operations, and many other, can be handled by matrix algebra.  This approach makes easier to write generic code and improves performance.  Apache SIS follows this principle by using affine transforms for every operations  that can be performed by such transform.  For instance there is no code dedicated to changing order of ordinate values in a coordinate. 
 About all graphical libraries support some kind of coordinate operations, usually as affine transforms  or a slight generalization like perspective transforms.  Each library defines its own API. Some examples are listed below: 
        Library  Transform implementation  Dimensions 

Java2D  java.awt.geom.AffineTransform  2 
Java3D  javax.media.j3d.Transform3D  3 
JavaFX  javafx.scene.transform.Affine  2 or 3 
Java Advanced Imaging (JAI)  javax.media.jai.PerspectiveTransform  2 
Android  android.graphics.Matrix  2 
 However in many cases, affine or perspective transforms are the only kind of coordinate operations supported by the graphical library.
 Apache SIS needs to handle a wider range of operations, in which affine transforms are only special cases.
 In particular most map projections and datum shifts can not be represented by affine transforms.
 SIS also needs to support arbitrary number of dimensions,
 while abovecited API restrict the use to a fixed number of dimensions.
 For those reasons SIS can not use directly the abovecited API.
 Instead, SIS uses the more abstract org.opengis.referencing.transform.MathTransform
interface.
 But in the special case where the transform is actually affine, SIS may try to use an existing implementation,
 in particular Java2D. The following Java code can be used in situations where the Java2D object is desired:

MathTransform mt = ...; // Any math transform created by Apache SIS. if (mt instanceof AffineTransform) {  AffineTransform at = (AffineTransform) mt;  // Use Java2D API from here. } 
 Apache SIS uses Java2D on a best effort basis only.
 The above cast is not guaranteed to succeed,
 even when the MathTransform
meets the requirements allowing Java2D usage.

 GIS make an extensive usage of matrices for displaying maps or for transforming coordinates.  There is many excellent open source or commercial matrix libraries available.  However, GIS have some specific needs that differ a little bit from the goals of many existent libraries.  Matrix operations like those described in the affine transform chapter  appear in almost all coordinate operations applied by Apache SIS.  But the analysis of those operations reveal some patterns: 
Those matrices are almost always of small size, rarely more than 5 rows and 5 columns.
“Heavy” matrix operations (matrix inversions or multiplications) do not happen in performancecritical code.  In almost every cases, those heavy operations are executed only once, for example when a data file is read  or in preparation steps before to transform coordinates.  Those heavy operations rarely happen in the loop that apply the coordinate operation  after we finished to prepare it.
In a sequence of matrix multiplications or inversions, rounding errors accumulate and grow fast.  If the sequence of matrix operations is long enough,  rounding errors can become indistinguishable from real operations like datum shifts.  This ambiguity can happen because the matrix representation of some datum shifts has small values,  with scale factors of a few parts per million and rotation terms of a few arcseconds.
It is quite common that two affine transforms cancel each other when they are concatenated, i.e.  that matrix multiplications result in some or all scale factors equal to 1 and some or all translation terms equal to 0.  However because of rounding errors the results are rarely exact, but are rather some values like 0,9999…97 instead of 1.  The usual workaround is to compare floating point numbers with some tolerance threshold.  Unfortunately it is difficult to choose a threshold that catch a wide range of rounding errors  without wrongly considering legitimate datum shifts as rounding errors (see previous point).
 As a consequence of above points, accuracy of a matrix library is more important than performance for a GIS like Apache SIS.  Paradoxically, a good way to improve performance is to invest more CPU time for more accurate matrix operations  when preparing (not executing) the coordinate operation,  because it increases the chances to correctly detect which operations cancel each other.  This investment can save execution time at the place where it matters most:  in the code looping over millions of coordinates to transform. 
 However matrix libraries are often designed for high performances with large matrices, sometime containing thousands of rows and columns.  Those libraries can efficiently resolve systems of linear equations with hundreds of unknown variables.  Those libraries resolve difficult problems, but not of the same kind than the problems that Apache SIS needs to solve.  For that reason, and also for another reason described in next paragraphs, Apache SIS uses its own matrix implementation.  This implementation addresses the accuracy issue by using “doubledouble” arithmetic  (a technic for simulating the accuracy of approximatively 120 bits wide floating point numbers)  at the cost of performance in a phase (transform preparation) where performance is not considered critical. 
  Apache SIS often needs to inverse matrices, in order to perform a coordinate operation in reverse direction.  Matrix inversions are typically performed on square matrices, but SIS also needs to inverse nonsquare matrices.  Depending on whether we have more lines than columns: 
 To illustrate the issues caused by direct use of libraries designed for linear algebra,  consider a (φ₁, λ₁, h) → (φ₂, λ₂) conversion  from threedimensional points to twodimensional points on a surface.  The φ terms are latitudes, the λ terms are longitudes and  (φ₂, λ₂) may be different than (φ₁, λ₁) if h axis is not perpendicular to the surface. 

 For linear algebra libraries, the above nonsquare matrix represents an underdetermined system of equations and may be considered unresolvable.  Indeed the above coordinate operation can not be inverted as a (φ₂, λ₂) → (φ₁, λ₁, h)  operation because we do not know which value to assign to h.  Ignoring h implies that we can not assign values to (φ₁, λ₁) neither since those values may depend on h.  However in GIS case, the ellipsoidal h axis is perpendicular to the ellipsoid surface  on which the geodetic latitudes and longitudes (φ, λ) are represented  (note that this statement is not true for geocentric latitudes and longitudes).  This perpendicularity makes φ₁ and λ₁ independent of h.  In such cases, we can can still do some processing. 
 Apache SIS proceeds by checking if h values are independent of φ and λ values.
 We identify such cases by checking which matrix coefficients are zero.
 If SIS can identify independent dimensions, it can temporarily exclude those dimensions
 and invert the matrix using only the remaining dimensions.
 If SIS does not found a sufficient amount of independent dimensions, an exception is thrown.
 But if a matrix inversion has been possible, then we need to decide which value to assign to the dimensions that SIS temporarily excluded.
 By default, SIS assigns the NaN
(NotaNumber) value to those dimensions.
 However in the particular case of ellipsoidal height h in a (φ₂, λ₂) → (φ₁, λ₁, h) operation,
 the zero value may also be appropriate on the assumption that the coordinates are usually close to the ellipsoid surface.
 In any case, the coefficients that Apache SIS sets to zero or NaN
is based on the assumption
 that the matrix represents a coordinate operation; this is not something that can be done with arbitrary matrices.

 The abovedescribed approach allows Apache SIS to resolve some underdetermined equation systems commonly found in GIS.
 In our example using NaN
as the default value, the h ordinate stay unknown – we do not create information from nothing –
 but at least the (φ, λ) coordinates are preserved.
 The opposite problem, those of overdetermined equation systems, is more subtile.
 An approach commonly applied by linear algebra libraries is to resolve overdetermined systems by the least squares method.
 Such method applied to our example would compute a (φ₂, λ₂, h) → (φ₁, λ₁) operation
 that seems the best compromise for various φ₂, λ₂ and h values,
 while being (except special cases) an exact solution for noone.
 Furthermore linear combinations between those three variables may be an issue because of heterogenous units of measurement,
 for instance with h in metres and (φ, λ) in degrees.
 Apache SIS rather proceeds in the same way than for underdetermined systems:
 by requiring that some dimensions are independent from other dimensions, otherwise the matrix is considered noninvertible.
 Consequently in overdetermined systems case, SIS may refuse to perform some matrix inversions that linear algebra libraries can do,
 but in case of success the resulting coordinate operation is guaranteed to be exact (ignoring rounding errors).

 In summary, Apache SIS provides its own matrix library for the following reasons: 

 This library is provided in the org.apache.sis.matrix
package of the sisreferencing
module.

 This chapter introduces a few aspects of ISO 19107 standard (Spatial schema)  and the Apache SIS classes that implement them. 
   
Each geometric object is considered an infinite set of points.
As a set, their most fundamental operations are of the same nature as the standard operations of Java collections.
We may therefore see a geometry as a kind of java.util.Set
in which the elements are points,
Modified: sis/site/trunk/book/en/index.html
URL: http://svn.apache.org/viewvc/sis/site/trunk/book/en/index.html?rev=1794656&r1=1794655&r2=1794656&view=diff
==============================================================================
 sis/site/trunk/book/en/index.html [UTF8] (original)
+++ sis/site/trunk/book/en/index.html [UTF8] Tue May 9 23:04:35 2017
@@ 27,7 +27,7 @@
Introduction to Apache SIS®
@@ 43,13 +43,13 @@