/* AWE - Amanzi Wireless Explorer
* http://awe.amanzi.org
* (C) 2008-2009, AmanziTel AB
*
* This library is provided under the terms of the Eclipse Public License
* as described at http://www.eclipse.org/legal/epl-v10.html. Any use,
* reproduction or distribution of the library constitutes recipient's
* acceptance of this agreement.
*
* This library is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
package org.amanzi.neo.models.render.impl;
import org.amanzi.neo.dto.IDataElement;
import org.amanzi.neo.models.exceptions.ModelException;
import org.amanzi.neo.models.impl.internal.AbstractNamedModel;
import org.amanzi.neo.models.impl.internal.util.CRSWrapper;
import org.amanzi.neo.models.render.IGISModel;
import org.amanzi.neo.models.render.IRenderableModel;
import org.amanzi.neo.nodeproperties.IGeneralNodeProperties;
import org.amanzi.neo.nodeproperties.IGeoNodeProperties;
import org.amanzi.neo.nodetypes.INodeType;
import org.amanzi.neo.services.INodeService;
import org.amanzi.neo.services.exceptions.ServiceException;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.neo4j.graphdb.Node;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Envelope;
/**
* TODO Purpose of
* <p>
* </p>
*
* @author Nikolay Lagutko (nikolay.lagutko@amanzitel.com)
* @since 1.0.0
*/
public class GISModel extends AbstractNamedModel implements IGISModel {
private static final Logger LOGGER = Logger.getLogger(GISModel.class);
private double minLatitude = Double.MAX_VALUE;;
private double maxLatitude = -Double.MAX_VALUE;
private double minLongitude = Double.MAX_VALUE;
private double maxLongitude = -Double.MAX_VALUE;
private final IGeoNodeProperties geoNodeProperties;
private IRenderableModel sourceModel;
private CoordinateReferenceSystem crs;
private String crsCode;
private boolean updateCoordinates = false;
/**
* @param nodeService
* @param generalNodeProperties
*/
public GISModel(final INodeService nodeService, final IGeneralNodeProperties generalNodeProperties,
final IGeoNodeProperties geoNodeProperites) {
super(nodeService, generalNodeProperties);
geoNodeProperties = geoNodeProperites;
}
@Override
public boolean canRender() {
return sourceModel.getRenderableElementCount() > 0;
}
@Override
public boolean canResolve(final Class< ? > clazz) {
return clazz.isAssignableFrom(sourceModel.getClass());
}
@Override
protected Node createNode(final Node parentNode, final INodeType nodeType, final String name) throws ServiceException {
return getNodeService().createNode(parentNode, nodeType, GISRelationType.GIS, name);
}
@Override
public void finishUp() throws ModelException {
LOGGER.info("Finishing up model <" + getName() + ">");
try {
if (updateCoordinates) {
getNodeService().updateProperty(getRootNode(), geoNodeProperties.getMaxLatitudeProperty(), maxLatitude);
getNodeService().updateProperty(getRootNode(), geoNodeProperties.getMaxLongitudeProperty(), maxLongitude);
getNodeService().updateProperty(getRootNode(), geoNodeProperties.getMinLatitudeProperty(), minLatitude);
getNodeService().updateProperty(getRootNode(), geoNodeProperties.getMinLongitudeProperty(), minLongitude);
getNodeService().updateProperty(getRootNode(), geoNodeProperties.getCRSProperty(), getCRSCode());
}
} catch (final ServiceException e) {
processException("Error on updating GIS Model", e);
}
}
@Override
public Iterable<IDataElement> getAllElementsByType(final INodeType nodeType) throws ModelException {
// TODO Auto-generated method stub
return null;
}
@Override
public ReferencedEnvelope getBounds() {
final double updatedMinLongitude = minLongitude - (maxLongitude - minLongitude) * 0.05;
final double updatedMaxLongitude = maxLongitude + (maxLongitude - minLongitude) * 0.05;
final double updatedMinLatitude = minLatitude - (maxLatitude - minLatitude) * 0.05;
final double updatedMaxLatitude = maxLatitude + (maxLatitude - minLatitude) * 0.05;
return new ReferencedEnvelope(updatedMinLongitude, updatedMaxLongitude, updatedMinLatitude, updatedMaxLatitude, crs);
}
@Override
public int getCount() {
return sourceModel.getRenderableElementCount();
}
@Override
public CoordinateReferenceSystem getCRS() {
return crs;
}
protected String getCRSCode() {
return crsCode;
}
@Override
public Iterable<ILocationElement> getElements(final Envelope bound) throws ModelException {
return sourceModel.getElements(bound);
}
/**
* @return Returns the maxLatitude.
*/
@Override
public double getMaxLatitude() {
return maxLatitude;
}
/**
* @return Returns the maxLongitude.
*/
@Override
public double getMaxLongitude() {
return maxLongitude;
}
/**
* @return Returns the minLatitude.
*/
@Override
public double getMinLatitude() {
return minLatitude;
}
/**
* @return Returns the minLongitude.
*/
@Override
public double getMinLongitude() {
return minLongitude;
}
@Override
protected INodeType getModelType() {
return GISNodeType.GIS;
}
@Override
protected Node getParent(final Node rootNode) throws ServiceException {
return getNodeService().getParent(rootNode, GISRelationType.GIS);
}
@Override
public IRenderableModel getSourceModel() {
return sourceModel;
}
@Override
public INodeType getSourceType() {
return sourceModel.getType();
}
@Override
public INodeType getType() {
return GISNodeType.GIS;
}
@Override
public void initialize(final Node rootNode) throws ModelException {
super.initialize(rootNode);
try {
maxLatitude = getNodeService().getNodeProperty(rootNode, geoNodeProperties.getMaxLatitudeProperty(), -Double.MAX_VALUE,
false);
minLatitude = getNodeService().getNodeProperty(rootNode, geoNodeProperties.getMinLatitudeProperty(), Double.MAX_VALUE,
false);
maxLongitude = getNodeService().getNodeProperty(rootNode, geoNodeProperties.getMaxLongitudeProperty(),
-Double.MAX_VALUE, false);
minLongitude = getNodeService().getNodeProperty(rootNode, geoNodeProperties.getMinLongitudeProperty(),
Double.MAX_VALUE, false);
final String crsCodeValue = getNodeService().getNodeProperty(rootNode, geoNodeProperties.getCRSProperty(),
StringUtils.EMPTY, false);
setCRS(crsCodeValue);
updateCoordinates = false;
} catch (final ServiceException e) {
processException("Cannot get GIS-related properties from Node", e);
}
}
/**
* @param crsCode The crsCode to set.
*/
public void setCRS(final CoordinateReferenceSystem crs) {
this.crs = crs;
this.crsCode = CRSWrapper.fromCRS(crs).getEpsg();
}
protected void setCRS(final String crsCode) {
if (!StringUtils.isEmpty(crsCode)) {
try {
this.crsCode = crsCode;
crs = CRS.decode(crsCode);
} catch (final FactoryException e) {
LOGGER.error("Cannot determinate CRS", e);
}
}
}
@Override
public void setSourceModel(final IRenderableModel sourceModel) {
this.sourceModel = sourceModel;
}
@Override
public void updateBounds(final double latitude, final double longitude) {
minLatitude = Math.min(latitude, minLatitude);
maxLatitude = Math.max(latitude, maxLatitude);
minLongitude = Math.min(longitude, minLongitude);
maxLongitude = Math.max(longitude, maxLongitude);
if (getCRS() == null) {
final CRSWrapper wrapper = CRSWrapper.fromLocation(latitude, longitude, getName());
setCRS(wrapper.getEpsg());
}
updateCoordinates = true;
}
}