package com.esri.geoevent.solutions.processor.line2pt; /* * #%L * Esri :: AGES :: Solutions :: Processor :: Geometry * $Id:$ * $HeadURL:$ * %% * Copyright (C) 2013 - 2014 Esri * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import java.util.ArrayList; import java.util.Date; import java.util.List; import com.esri.core.geometry.Envelope; import com.esri.core.geometry.Geometry; import com.esri.core.geometry.GeometryEngine; import com.esri.core.geometry.LinearUnit; import com.esri.core.geometry.MapGeometry; import com.esri.core.geometry.Point; import com.esri.core.geometry.Polyline; import com.esri.core.geometry.SpatialReference; import com.esri.core.geometry.Unit; import com.esri.ges.core.ConfigurationException; import com.esri.ges.core.component.ComponentException; import com.esri.ges.core.geoevent.DefaultFieldDefinition; import com.esri.ges.core.geoevent.DefaultGeoEventDefinition; import com.esri.ges.core.geoevent.FieldDefinition; import com.esri.ges.core.geoevent.FieldException; import com.esri.ges.core.geoevent.FieldType; import com.esri.ges.core.geoevent.GeoEvent; import com.esri.ges.core.geoevent.GeoEventDefinition; import com.esri.ges.core.validation.ValidationException; import com.esri.ges.framework.i18n.BundleLogger; import com.esri.ges.framework.i18n.BundleLoggerFactory; import com.esri.ges.manager.geoeventdefinition.GeoEventDefinitionManager; import com.esri.ges.manager.geoeventdefinition.GeoEventDefinitionManagerException; import com.esri.ges.messaging.GeoEventCreator; import com.esri.ges.messaging.Messaging; import com.esri.ges.messaging.MessagingException; import com.esri.ges.processor.GeoEventProcessorBase; import com.esri.ges.processor.GeoEventProcessorDefinition; public class Line2PtProcessor extends GeoEventProcessorBase { private String pointType; private int processWkid; private String outDef; private List<FieldDefinition> fds; private Boolean createDef = false; private GeoEventDefinition ged; private GeoEventDefinitionManager manager; private Messaging messaging; private static final BundleLogger LOGGER = BundleLoggerFactory .getLogger(Line2PtProcessor.class); public Line2PtProcessor(GeoEventProcessorDefinition definition) throws ComponentException { super(definition); //spatial = s; geoEventMutator = true; } @Override public void afterPropertiesSet() { pointType = properties.get("pointType").getValueAsString(); processWkid = (Integer)properties.get("wkid").getValue(); outDef = properties.get("outdefname").getValueAsString(); fds = new ArrayList<FieldDefinition>(); try { //fds.add(new DefaultFieldDefinition("trackId", FieldType.String, //"TRACK_ID")); fds.add(new DefaultFieldDefinition("LocationTimeStamp", FieldType.Date, "TIMESTAMP")); //fds.add(new DefaultFieldDefinition("geometry", FieldType.Geometry)); if ((ged = manager.searchGeoEventDefinition(outDef, definition.getUri().toString())) == null) { createDef = true; } } catch(ConfigurationException e) { LOGGER.error(e.getMessage()); } } @Override public synchronized void validate() throws ValidationException { // Validation Phase ... super.validate(); } @Override public GeoEvent process(GeoEvent ge) throws Exception { if (createDef) { createGeoEventDefinition(ge); createDef=false; } Date timeStart = (Date)ge.getField("TIME_START"); Date timeEnd = (Date)ge.getField("TIME_END"); if(timeStart== null) return null; if(timeEnd==null) return null; MapGeometry mapGeo = ge.getGeometry(); Geometry geo = mapGeo.getGeometry(); if(geo.getType()!=Geometry.Type.Polyline) return null; Polyline polyln = (Polyline)geo; Geometry outGeo = null; Date ts = null; if(pointType.equals("start")) { ts = (Date)ge.getField("TIME_START"); outGeo = getStartPoint(polyln); } else if(pointType.equals("end")) { ts = (Date)ge.getField("TIME_END"); outGeo = getEndPoint(polyln); } else if(pointType.equals("mid")) { outGeo = getMiddlePoint(mapGeo); long midTime = timeStart.getTime() + ((timeEnd.getTime() - timeStart.getTime())/2); ts = new Date(midTime); } MapGeometry outMapGeo = new MapGeometry(outGeo, mapGeo.getSpatialReference()); GeoEvent msg = createLine2PtGeoevent(ge, outMapGeo, ts); return msg; } private GeoEvent createLine2PtGeoevent(GeoEvent event, MapGeometry outGeo, Date ts) throws MessagingException, FieldException { GeoEventCreator creator = messaging.createGeoEventCreator(); GeoEvent msg = creator.create(outDef, definition.getUri().toString()); for(FieldDefinition fd: event.getGeoEventDefinition().getFieldDefinitions()) { if(fd.getTags().contains("GEOMETRY")) { msg.setGeometry(outGeo); } else { msg.setField(fd.getName(), event.getField(fd.getName())); } msg.setField("TIMESTAMP", ts); } return msg; } private void createGeoEventDefinition(GeoEvent event) { GeoEventDefinition eventDef = event.getGeoEventDefinition(); try { ged = eventDef.augment(fds); } catch (ConfigurationException e) { LOGGER.error(e.getLocalizedMessage()); } ged.setName(outDef); ged.setOwner(definition.getUri().toString()); try { manager.addGeoEventDefinition(ged); } catch (GeoEventDefinitionManagerException e) { LOGGER.error(e.getMessage()); } } @Override public void shutdown() { // Destruction Phase super.shutdown(); } @Override public boolean isGeoEventMutator() { return true; } public void onServiceStart() { // Service Start Phase } public void onServiceStop() { // Service Stop Phase } private Point getStartPoint(Polyline polyln) { int startIndex = polyln.getPathStart(0); return polyln.getPoint(startIndex); } private Point getEndPoint(Polyline polyln) { try { int pathCount = polyln.getPathCount(); int endIndex = polyln.getPathEnd(pathCount - 1); return polyln.getPoint(endIndex-1); } catch (Exception e) { LOGGER.error(e.getMessage()); throw (e); } } private Geometry getMiddlePoint(MapGeometry mg) { try { Unit unit = LinearUnit.create(9001); LinearUnit lu = (LinearUnit) unit; MapGeometry mapgeo = null; Boolean inputProjected = true; SpatialReference outSr = null; SpatialReference inSr = mg.getSpatialReference(); if (processWkid != mg.getSpatialReference().getID()) { outSr = SpatialReference.create(processWkid); Geometry g = GeometryEngine.project(mg.getGeometry(), inSr, outSr); mapgeo = new MapGeometry(g, outSr); inputProjected = false; } else { mapgeo = mg; outSr = mapgeo.getSpatialReference(); } Double midptLen = GeometryEngine.geodesicLength( mapgeo.getGeometry(), mapgeo.getSpatialReference(), lu) / 2; Point midPt = null; Polyline polyln = (Polyline) mapgeo.getGeometry(); int pathCount = polyln.getPathCount(); Double currentLen = 0.0; for (int i = 0; i < pathCount; ++i) { int start = polyln.getPathStart(i); int end = polyln.getPathEnd(i); int hops = end - start; for (int j = start + 1; j < start + hops; ++j) { Point startPt = polyln.getPoint(j - 1); Point endPt = polyln.getPoint(j); Double distance = GeometryEngine.distance(startPt, endPt, outSr); // currentLn + distance if (currentLen + distance >= midptLen) { currentLen += distance; Double distanceOnSeg = midptLen-(currentLen-distance); midPt = findPtOnSegment(startPt, endPt, distanceOnSeg); Geometry outGeo = null; if (!inputProjected) { outGeo = GeometryEngine.project(midPt, outSr, inSr); } else { outGeo = midPt; } return outGeo; } else { currentLen += distance; } } } return null; } catch (Exception e) { LOGGER.error(e.getStackTrace().toString()); LOGGER.error(e.getMessage()); throw (e); } } private Point findPtOnSegment(Point segStart, Point segEnd, Double d) { Point pt = null; Double x1, y1, x2, y2; x1 = segStart.getX(); y1 = segStart.getY(); x2 = segEnd.getX(); y2 = segEnd.getY(); Double diffXsquare = Math.pow((x2-x1), 2); Double diffYsquare = Math.pow((y2-y1), 2); Double x = x1 + d*(x2-x1)/Math.sqrt(diffXsquare+diffYsquare); Double y = y1 + d*(y2-y1)/Math.sqrt(diffXsquare + diffYsquare); pt = new Point(x,y); return pt; } private Point findPtOnSegment(Point segStart, Point segEnd, Double h, Double h2) { Point pt = null; Double x1, y1, x2, y2; x1 = segStart.getX(); y1 = segStart.getY(); x2 = segEnd.getX(); y2 = segEnd.getY(); Double a = null; Double o = null; Double cosTheta = null; Double sinTheta = null; Double xMultiplier = null; Double yMultiplier = null; Double xlen = null; Double ylen = null; if(x1 > x2 && y1 > y2) { xMultiplier = 1.0; yMultiplier = -1.0; a = Math.abs(y2 - y1); o = Math.abs(x2 - x1); cosTheta = a/h; sinTheta = o/h; xlen = h2*sinTheta*xMultiplier; ylen=h2*cosTheta*yMultiplier; } else if(x1 < x2 && y1 < y2) { xMultiplier = -1.0; yMultiplier = 1.0; a = Math.abs(x2 - x1); o = Math.abs(y2 - y1); cosTheta = a/h; sinTheta = o/h; xlen = h2*cosTheta*xMultiplier; ylen=h2*sinTheta*yMultiplier; } else if(x1 < x2 && y1 > y2) { xMultiplier = 1.0; yMultiplier = -1.0; a = Math.abs(y2 - y1); o = Math.abs(x2 - x1); cosTheta = a/h; sinTheta = o/h; xlen = h2*sinTheta*xMultiplier; ylen=h2*cosTheta*yMultiplier; } else if(x1 > x2 && y1 < y2) { xMultiplier = -1.0; yMultiplier = 1.0; a = Math.abs(x2 - x1); o = Math.abs(y2 - y1); cosTheta = a/h; sinTheta = o/h; xlen = h2*cosTheta*xMultiplier; ylen=h2*sinTheta*yMultiplier; } Double newX= segStart.getX() + xlen; Double newY = segStart.getY() + ylen; pt = new Point(newX, newY); return pt; } public void setManager(GeoEventDefinitionManager manager) { this.manager = manager; } public void setMessaging(Messaging messaging) { this.messaging = messaging; } }