← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 14889: Renamed organisation unit find by coordinate related methods and created a service to check if a ...

 

------------------------------------------------------------
revno: 14889
committer: James Chang <jamesbchang@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2014-04-17 23:52:45 +0800
message:
  Renamed organisation unit find by coordinate related methods and created a service to check if a coordinate falls within a org unit boundary
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java
  dhis-2/dhis-support/dhis-support-system/pom.xml
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/GeoUtils.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitController.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java	2014-03-24 09:51:04 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java	2014-04-17 15:52:45 +0000
@@ -390,10 +390,37 @@
      * 
      * @return collection of objects.
      */
-    Collection<OrganisationUnit> getWithinCoordinateArea( double longitude, double latitude, double distance );
-    
-    boolean isInUserHierarchy( OrganisationUnit organisationUnit );
-    
+    Collection<OrganisationUnit> getOrganisationUnitWithinDistance( double longitude, double latitude, double distance );
+
+    /**
+     * Retrieves the orgunit(s) by coordinate.
+     * 
+     * @param longitude The longitude of the location.
+     * @param latitude The latitude of the location.
+     * @param topOrgUnitUid Optional. Uid of the search top level org unit (ex.
+     *        Country level orgunit)
+     * @param targetLevel Optional. The level being searched.
+     * 
+     * @return collection of objects.
+     */
+    Collection<OrganisationUnit> getOrganisationUnitByCoordinate( double longitude, double latitude, String topOrgUnitUid,
+        Integer targetLevel );
+
+    
+    /**
+     * find the orgunit(s) that contains the coordinate.
+     * 
+     * @param source orgunits to search for.
+     * @param longitude The longitude of the location.
+     * @param latitude The latitude of the location.
+     * 
+     * @return collection of objects.
+     */
+    Collection<OrganisationUnit> filterOrganisationUnitsByCoordinate( Collection<OrganisationUnit> orgUnits_source,
+        double longitude, double latitude );
+    
+	boolean isInUserHierarchy( OrganisationUnit organisationUnit );
+
     // -------------------------------------------------------------------------
     // OrganisationUnitHierarchy
     // -------------------------------------------------------------------------

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java	2014-04-17 04:48:57 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java	2014-04-17 15:52:45 +0000
@@ -846,12 +846,12 @@
         return organisationUnitLevelStore.getMaxLevels();
     }
 
-    public Collection<OrganisationUnit> getWithinCoordinateArea( double longitude, double latitude, double distance )
+
+    public Collection<OrganisationUnit> getOrganisationUnitWithinDistance( double longitude, double latitude, double distance )
     {
         Collection<OrganisationUnit> objects = organisationUnitStore.getWithinCoordinateArea( GeoUtils.getBoxShape( longitude, latitude, distance ) );
 
-        // Go through the list and remove the ones located outside radius
-        
+        // Go through the list and remove the ones located farther than the distance.
         if ( objects != null && objects.size() > 0 )
         {
             Iterator<OrganisationUnit> iter = objects.iterator();
@@ -867,6 +867,8 @@
 
                 if ( distancebetween > distance )
                 {
+                    // Remove the orgUnits that is outside of the distance range 
+                    // - due to the 'getWithinCoordinateArea' looking at square area instead of circle.
                     iter.remove();
                 }
             }
@@ -875,6 +877,158 @@
         return objects;
     }
 
+
+    public Collection<OrganisationUnit> getOrganisationUnitByCoordinate( double longitude, double latitude, String topOrgUnitUid,
+        Integer targetLevel )
+    {
+        Collection<OrganisationUnit> orgUnits = new ArrayList<OrganisationUnit>();
+
+        if ( GeoUtils.checkGeoJsonPointValid( longitude, latitude ) )
+        {
+
+            OrganisationUnit topOrgUnit = null;
+
+            // 1. Get top org unit of search.
+            if ( topOrgUnitUid != null && topOrgUnitUid != "" )
+            {
+                topOrgUnit = getOrganisationUnit( topOrgUnitUid );
+            }
+            else
+            {
+                // Get top orgunit that contains the coordinate - to get a top
+                // search point.
+                Collection<OrganisationUnit> orgUnits_TopLevel = getTopLevelOrgUnitWithPoint( longitude, latitude, 1,
+                    getNumberOfOrganisationalLevels() - 1 );
+
+                if ( orgUnits_TopLevel.size() == 1 )
+                {
+                    topOrgUnit = orgUnits_TopLevel.iterator().next();
+                }
+                else
+                {
+                    System.out.print( "Multiple Top Level Org Unit found with the coordinate: " );
+
+                    for ( OrganisationUnit ou : orgUnits_TopLevel )
+                    {
+                        System.out.print( " [" + ou.getLevel() + "] " + ou.getName() + " " + ou.getUid() + " " );
+                    }
+
+                    System.out.println( "" );
+                }
+
+            }
+
+            // 2. From the found top level orgunit, search children orgunits to
+            // get the lowest level orgunit that contains the coordinate
+            if ( topOrgUnit == null )
+            {
+                System.out.println( "Could not retrieve a top org Unit." );
+            }
+            else
+            {
+                Collection<OrganisationUnit> orgUnits_childrens = new ArrayList<OrganisationUnit>();
+
+                if ( targetLevel != null )
+                {
+                    orgUnits_childrens = getOrganisationUnitsAtLevel( targetLevel, topOrgUnit );
+                }
+                else
+                {
+                    orgUnits_childrens = getOrganisationUnitWithChildren( topOrgUnit.getId() );
+                }
+
+                Collection<OrganisationUnit> orgUnits_found = filterOrganisationUnitsByCoordinate( orgUnits_childrens,
+                    longitude, latitude );
+
+                // 3. for all the org units with polygon containing the coordinate
+                // , get polygon with highest level
+
+                int bottomLvl = topOrgUnit.getLevel();
+
+                for ( OrganisationUnit ou : orgUnits_found )
+                {
+
+                    if ( ou.getLevel() > bottomLvl )
+                    {
+                        bottomLvl = ou.getLevel();
+                    }
+                }
+
+                for ( OrganisationUnit ou : orgUnits_found )
+                {
+                    if ( ou.getLevel() == bottomLvl )
+                    {
+                        System.out.println( "Bottom Lvl OU Found: [" + ou.getLevel() + "], " + ou.getName() + ", "
+                            + ou.getUid() );
+
+                        orgUnits.add( ou );
+                    }
+                }
+            }
+
+        }
+        else
+        {
+            System.out.println( "Could not create a valid GeoJson Point from coordinate.  Longitude: " + longitude
+                + ", latitude: " + latitude );
+        }
+
+        return orgUnits;
+    }
+
+    
+    public Collection<OrganisationUnit> filterOrganisationUnitsByCoordinate( Collection<OrganisationUnit> orgUnits_source,
+        double longitude, double latitude )
+    {
+        Collection<OrganisationUnit> orgUnits = new ArrayList<OrganisationUnit>();
+        
+        for ( OrganisationUnit ou : orgUnits_source )
+        {
+            String ou_featureType = ou.getFeatureType();
+            String ou_coordinate = ou.getCoordinates();
+
+            if ( ou_featureType != null
+                && ou_coordinate != null
+                && !ou_coordinate.isEmpty()
+                && (ou_featureType.compareTo( OrganisationUnit.FEATURETYPE_POLYGON ) == 0 || ou_featureType
+                    .compareTo( OrganisationUnit.FEATURETYPE_MULTIPOLYGON ) == 0) )
+            {
+                if ( GeoUtils.checkPointWithMultiPolygon( longitude, latitude, ou.getCoordinates(), ou_featureType ) )
+                {
+                    orgUnits.add( ou );
+                    System.out.println( "Location Match OU: [" + ou.getLevel() + "], " + ou.getName() + ", "
+                        + ou.getUid() );
+                }
+            }
+        }
+
+        return orgUnits;
+    }
+
+    private Collection<OrganisationUnit> getTopLevelOrgUnitWithPoint( double longitude, double latitude, int searchLvl,
+        int stopLvl )
+    {
+        Collection<OrganisationUnit> orgUnits = new ArrayList<OrganisationUnit>();
+
+        // Search down the level until it finds a orgunit with
+        // polygon/multipolygon that contains the point
+
+        for ( int i = searchLvl; i <= stopLvl; i++ )
+        {
+            Collection<OrganisationUnit> orgUnits_onLevel = filterOrganisationUnitsByCoordinate(
+                getOrganisationUnitsAtLevel( i ), longitude, latitude );
+
+            if ( orgUnits_onLevel.size() > 0 )
+            {
+                orgUnits = orgUnits_onLevel;
+                break;
+            }
+        }
+
+        return orgUnits;
+    }
+
+   
     // -------------------------------------------------------------------------
     // Version
     // -------------------------------------------------------------------------

=== modified file 'dhis-2/dhis-support/dhis-support-system/pom.xml'
--- dhis-2/dhis-support/dhis-support-system/pom.xml	2014-03-24 09:51:04 +0000
+++ dhis-2/dhis-support/dhis-support-system/pom.xml	2014-04-17 15:52:45 +0000
@@ -59,6 +59,11 @@
       <groupId>org.geotools</groupId>
       <artifactId>gt-referencing</artifactId>
     </dependency>
+	<dependency>
+	  <groupId>org.geotools</groupId>
+	  <artifactId>gt-geojson</artifactId>
+	  <version>10.4</version>
+	</dependency>    
     
     <!-- Other -->
     

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/GeoUtils.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/GeoUtils.java	2014-03-24 09:51:04 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/GeoUtils.java	2014-04-17 15:52:45 +0000
@@ -29,8 +29,15 @@
  */
 
 import java.awt.geom.Point2D;
+import java.io.StringReader;
 
+import org.geotools.geojson.geom.GeometryJSON;
 import org.geotools.referencing.GeodeticCalculator;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+
+import com.vividsolutions.jts.geom.MultiPolygon;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Polygon;
 
 /**
  * @author Lars Helge Overland
@@ -93,5 +100,77 @@
         calc.setDestinationGeographicPoint( to);
         
         return calc.getOrthodromicDistance();
-    }    
+    }
+
+    private static Point getGeoJsonPoint( double longitude, double latitude )
+    {
+        Point point = null;
+
+        try
+        {
+            GeometryJSON gtjson = new GeometryJSON();
+
+            point = gtjson.readPoint( new StringReader( "{\"type\":\"Point\", \"coordinates\":[" + longitude + ","
+                + latitude + "]}" ) );
+        }
+        catch ( Exception ex )
+        {
+            System.out.println( "Error during GeoJson point create - " + ex.getMessage() );
+        }
+
+        return point;
+    }
+
+    public static boolean checkGeoJsonPointValid( double longitude, double latitude )
+    {
+        return getGeoJsonPoint( longitude, latitude ).isValid();
+    }
+
+    // Check if the point is within the polygon/multiPolygon
+    public static boolean checkPointWithMultiPolygon( double longitude, double latitude, String multiPolygonJson,
+        String featureType )
+    {
+        boolean contains = false;
+
+        GeometryJSON gtjson = new GeometryJSON();
+
+        // Note: Could create this point once from calling package and reuse it
+        // , but then, each calling package need to reference
+        // 'com.vividsolutions.jts.geom.Point'
+        Point point = getGeoJsonPoint( longitude, latitude );
+
+        if ( point != null && point.isValid() )
+        {
+            try
+            {
+                if ( featureType.compareTo( OrganisationUnit.FEATURETYPE_POLYGON ) == 0 )
+                {
+                    Polygon polygon = gtjson.readPolygon( new StringReader( "{\"type\":\"Polygon\", \"coordinates\":"
+                        + multiPolygonJson + "}" ) );
+
+                    contains = polygon.contains( point );
+                }
+                else if ( featureType.compareTo( OrganisationUnit.FEATURETYPE_MULTIPOLYGON ) == 0 )
+                {
+                    MultiPolygon multiPolygon = gtjson.readMultiPolygon( new StringReader(
+                        "{\"type\":\"MultiPolygon\", \"coordinates\":" + multiPolygonJson + "}" ) );
+
+                    contains = multiPolygon.contains( point );
+                }
+
+            }
+            catch ( Exception exception )
+            {
+                System.out.println( "Error during GeoJson MultiPolygon create - " + exception.toString() );
+            }
+
+        }
+        else
+        {
+            System.out.println( "Point coordinate is not valid. Longitude: " + longitude + ", latitude: " + latitude );
+        }
+
+        return contains;
+    }
+
 }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitController.java	2014-03-26 12:33:30 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitController.java	2014-04-17 15:52:45 +0000
@@ -58,6 +58,7 @@
 import javax.servlet.http.HttpServletResponse;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -270,12 +271,12 @@
     }
 
     @RequestMapping(value = "/withinRange", method = RequestMethod.GET, produces = { "*/*", "application/json" })
-    public void getEntitiesWithinRange( @RequestParam Double longitude, @RequestParam Double latitude,
+    public void getEntitiesWithinRange( @RequestParam Double longitude, @RequestParam Double latitude, 
         @RequestParam Double distance, @RequestParam(required = false) String orgUnitGroupSetId,
         Model model, HttpServletRequest request, HttpServletResponse response ) throws Exception
     {
-        List<OrganisationUnit> entityList = new ArrayList<OrganisationUnit>( organisationUnitService.getWithinCoordinateArea( longitude, latitude, distance ) );
-
+        List<OrganisationUnit> entityList = new ArrayList<OrganisationUnit>( organisationUnitService.getOrganisationUnitWithinDistance( longitude, latitude, distance ) );
+                 
         for ( OrganisationUnit orgunit : entityList )
         {
             Set<AttributeValue> attributeValues = orgunit.getAttributeValues();
@@ -311,4 +312,81 @@
 
         JacksonUtils.toJson( response.getOutputStream(), entityList );
     }
+
+    @RequestMapping( value = "/orgUnitByLocation", method = RequestMethod.GET, produces = { "*/*", "application/json" } )
+    public void getParentByLocation( @RequestParam
+    Double longitude, @RequestParam
+    Double latitude, @RequestParam
+    Map<String, String> parameters, Model model, HttpServletRequest request, HttpServletResponse response )
+        throws Exception
+    {
+
+        // 1. Get parameters
+        WebOptions options = new WebOptions( parameters );
+
+        String topOrgUnit = null;
+        Integer targetLevel = null;
+
+        topOrgUnit = options.getOptions().get( "topOrgUnit" );
+
+        if ( options.getOptions().containsKey( "targetLevel" ) )
+        {
+            try
+            {
+                targetLevel = Integer.parseInt( options.getOptions().get( "targetLevel" ) );
+            }
+            catch ( NumberFormatException ignored )
+            {
+            }
+        }
+
+        // 2. Retrieve list - lowest level orgunit(s) containing the coordinate.
+        List<OrganisationUnit> entityList = new ArrayList<OrganisationUnit>(
+            organisationUnitService.getOrganisationUnitByCoordinate( longitude, latitude, topOrgUnit, targetLevel ) );
+
+        // 3. Remove unrelated details and output in JSON format.
+        for ( OrganisationUnit orgunit : entityList )
+        {
+            Set<AttributeValue> attributeValues = orgunit.getAttributeValues();
+            attributeValues.clear();
+
+            // Clear out all data not needed for this task
+            orgunit.removeAllDataSets();
+            orgunit.removeAllUsers();
+            orgunit.removeAllOrganisationUnitGroups();
+        }
+
+        JacksonUtils.toJson( response.getOutputStream(), entityList );
+    }
+
+    @RequestMapping( value = "/locationWithinOrgUnitBoundary", method = RequestMethod.GET, produces = { "*/*", "application/json" } )
+    public void checkLocationWithinOrgUnit( @RequestParam String orgUnitUid
+        , @RequestParam Double longitude, @RequestParam Double latitude
+        , Model model, HttpServletRequest request, HttpServletResponse response )
+        throws Exception
+    {
+
+        boolean withinOrgUnit = false;
+        
+        Collection<OrganisationUnit> orgUnits = new ArrayList<OrganisationUnit>();
+       
+        // Reuse 'filterOrganisationUnitsByCoordinate' Method for this.
+        // Send orgUnit collection with one orgUnit to 'getOrganisationUnitByLocation'.
+        // If it returns orgUnit collection with one orgUnit, it means the orgUnit sent as collection
+        // has the coordinate within that orgUnit.
+        
+        orgUnits.add( organisationUnitService.getOrganisationUnit( orgUnitUid ) );
+
+        Collection<OrganisationUnit> orgUnits_found = organisationUnitService.filterOrganisationUnitsByCoordinate( orgUnits, longitude, latitude );
+        
+        if ( orgUnits_found.size() == 1 )
+        {
+            withinOrgUnit = true;
+        }
+                
+        JacksonUtils.toJson( response.getOutputStream(), withinOrgUnit );
+    }
+    
+    
+    
 }