Repast NetworkBuilder 可以用于地理和 GIS 显示吗?

Can the Repast NetworkBuilder be used in Geography and GIS Displays?

使用 java 的流行 Repast 僵尸教程使用了一个 NetworkBuilder,可以让您可视化感染网络。我想知道是否有任何类似的东西可以与 Geography/GIS 上下文一起使用。或者,关于如何构建自己的想法有什么想法吗?例如,如果我的智能体从 A 点移动到 B 点,我可以编写一个函数来绘制连接两者的向量吗?

我编写了一个投影侦听器 class,它将管理地理投影中的 Repast 网络对象,该投影可以在 GIS 显示中可视化。附加的侦听器 class 可以放置在您的项目中,并在 ContextBuilder 中用于 link 地理和网络投影,如下所示:

GeographyParameters geoParams = new GeographyParameters(); 
Geography geography = GeographyFactoryFinder.createGeographyFactory(null).createGeography("Geography", context, geoParams);

NetworkBuilder<Object> netBuilder = new NetworkBuilder<Object>("Network", context, true);
Network net = netBuilder.buildNetwork();

GISNetworkListener netListener = new GISNetworkListener(context, geography, net);

GIS NetworkListener 将地理和网络绑定到指定的上下文中,这样一个中的更改将反映到另一个中。这处理代理移动、添加和从地理中删除以及网络 add/remove 边缘事件。如果您有多个网络,您可以为每个网络创建单独的侦听器实例。只要在您的代码中正常使用 Repast 网络和地理投影,就不需要额外的代码来更新投影之间的事件。

要在 GIS 显示中可视化网络边缘,您需要创建一个简单的边缘 class 来扩展 RepastEdge,例如附加的 MyNetworkEdge class。这只是因为显示向导需要用户 class 来设置样式。在显示中,您可以 select 代理类型对话框中的 MyNetworkEdge class 并指定线路类型或样式 class,如附加的 MyNetworkStyle class。要在 Repast 网络中创建 links,您需要使用 MyNetworkEdge 的添加和删除边缘方法,例如

net.addEdge(new MyNetworkEdge(source, target));

您当然可以根据需要向 MyNetworkEdge class 添加更多功能。

ProjectionListener class:

package geography;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;

import repast.simphony.context.Context;
import repast.simphony.space.gis.Geography;
import repast.simphony.space.graph.Network;
import repast.simphony.space.graph.RepastEdge;
import repast.simphony.space.projection.ProjectionEvent;
import repast.simphony.space.projection.ProjectionListener;

/**
 * A ProjectionListener implementation for managing Repast network edges in a
 * Repast geography projection.  This listener responds to both geography event
 * and network events.
 * 
 * @author Eric Tatara
 *
 */
public class GISNetworkListener implements ProjectionListener {

    Context context;
    Network network;
    Geography geography;
    GeometryFactory fac = new GeometryFactory();

    public GISNetworkListener(Context c, Geography g, Network n) {
        context = c;
        network = n;
        geography = g;

        network.addProjectionListener(this);
        geography.addProjectionListener(this);
    }

    @Override
    public void projectionEventOccurred(ProjectionEvent evt) {

        // When an object is moved in the geography, its network edges positions 
        // should be updated if the object has edges.
        if (evt.getType() == ProjectionEvent.OBJECT_MOVED){
            Iterable<RepastEdge> edges = network.getEdges(evt.getSubject());

            if (edges != null){
                for (RepastEdge e : edges){
                    // Get the existing geometry for this edge
                    MultiLineString lineFeature = (MultiLineString)geography.getGeometry(e);

                    Coordinate sourceCoord = geography.getGeometry(e.getSource()).getCoordinate();
                    Coordinate targetCoord = geography.getGeometry(e.getTarget()).getCoordinate();

                    Coordinate coords[] = lineFeature.getCoordinates();

                    // Update the edge coordinates based on the source and target object 
                    // (agent) coordinates.
                    coords[0].setCoordinate(sourceCoord);
                    coords[1].setCoordinate(targetCoord);
                }
            }
        }

        // When a Repast network edge is added, create a new MultiLineString geometry
        // to represent the edge in the geography.
        else if (evt.getType() == ProjectionEvent.EDGE_ADDED){  
            RepastEdge e = (RepastEdge)evt.getSubject();

            Coordinate sourceCoord = geography.getGeometry(e.getSource()).getCoordinate();
            Coordinate targetCoord = geography.getGeometry(e.getTarget()).getCoordinate();

            LineString lineString = fac.createLineString(new Coordinate[]{sourceCoord, 
                    targetCoord});

            MultiLineString mls = fac.createMultiLineString(new LineString[]{lineString});

            context.add(e);
            geography.move(e, mls);
        }

        // When a Repast edge remove event occurs, remove the edge geometry from the 
        // geography and the context.  This should also occur automatically when agents
        // are removed from a context or network.
        else if (evt.getType() == ProjectionEvent.EDGE_REMOVED){
            RepastEdge e = (RepastEdge)evt.getSubject();

            geography.move(e, null);
            context.remove(e);          
        }
    }
}

RepastEdge class:

package geography;

import repast.simphony.space.graph.RepastEdge;

public class MyNetworkEdge extends RepastEdge {

    public MyNetworkEdge(Object source, Object target){
        super(source, target, false);
    }

}

网络风格class:

package geography;

import gov.nasa.worldwind.render.SurfacePolyline;
import gov.nasa.worldwind.render.SurfaceShape;

import java.awt.Color;

import repast.simphony.visualization.gis3D.style.SurfaceShapeStyle;

/**
 * Style for MyNetworkEdges.
 * 
 * @author Eric Tatara
 *
 */
public class MyNetworkStyle implements SurfaceShapeStyle<MyNetworkEdge>{

    @Override
    public SurfaceShape getSurfaceShape(MyNetworkEdge object, SurfaceShape shape) {
      return new SurfacePolyline();
    }

    @Override
    public Color getFillColor(MyNetworkEdge obj) {
        return null;
    }

    @Override
    public double getFillOpacity(MyNetworkEdge obj) {
        return 0;
    }

    @Override
    public Color getLineColor(MyNetworkEdge obj) {
        return Color.BLUE;
    }

    @Override
    public double getLineOpacity(MyNetworkEdge obj) {
        return 1.0;
    }

    @Override
    public double getLineWidth(MyNetworkEdge obj) {
        return 2;
    }
}