/* * Copyright (c) 2013 by Roman Seidl - romanAeTgranul.at * * This Program uses code copyright (c) 2012 by David Shepard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package at.granul.gephi.shpexporter; import at.granul.gephi.shpexporter.ui.SHPExporterDialog; import com.hypercities.exporttoearth.GeoAttributeFinder; import java.awt.Color; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; import org.gephi.data.attributes.api.AttributeColumn; import org.gephi.data.attributes.api.AttributeController; import org.gephi.data.attributes.api.AttributeModel; import org.gephi.data.attributes.api.AttributeRow; import org.gephi.graph.api.Node; import org.gephi.preview.api.Item; import org.gephi.preview.api.PreviewController; import org.gephi.preview.api.PreviewModel; import org.gephi.preview.plugin.items.NodeItem; import org.gephi.data.attributes.api.AttributeType; import org.gephi.graph.api.Edge; import org.gephi.preview.plugin.items.EdgeItem; import org.openide.util.Lookup; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Point; import org.geotools.data.DefaultTransaction; import org.geotools.data.Transaction; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.shapefile.ShapefileDataStoreFactory; import org.geotools.data.simple.SimpleFeatureCollection; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.feature.FeatureCollections; import org.geotools.geometry.jts.JTSFactoryFinder; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; /** * * @author SeidlR */ public class SHPExporter { private static final String LOCATION_FIELD = "location"; private static final String SIZE_FIELD = "gSize"; private static final String COLOR_FIELD = "gColor"; public boolean execute() { try { PreviewModel previewModel; final PreviewController previewController = Lookup.getDefault().lookup(PreviewController.class); //there seems to be a bug in gephi or in gephi & eclipse that needs a refresh of the preview - else the model is empty previewController.refreshPreview(); previewModel = previewController.getModel(); AttributeModel model = Lookup.getDefault().lookup(AttributeController.class).getModel(); AttributeColumn[] nodeColums = model.getNodeTable().getColumns(); //try to find the GeoFields AttributeColumn[] geoFields; GeoAttributeFinder gaf = new GeoAttributeFinder(); geoFields = gaf.findGeoFields(nodeColums); SHPExporterDialog exporterDialog; exporterDialog = new SHPExporterDialog(nodeColums, geoFields); exporterDialog.setTitle("SHP Export Options"); if (exporterDialog.showDialog()) { geoFields = exporterDialog.getGeoFields(); File exportFile = exporterDialog.getFile(); //Construct Export Filenames String baseName = exportFile.getName(); baseName = baseName.substring(0, baseName.lastIndexOf(".")); File pointFile = new File(exportFile.getParentFile(), baseName + ".node.shp"); File edgeFile = new File(exportFile.getParentFile(), baseName + ".edge.shp"); //convert data to pointFeatureSource SimpleFeatureType pointFeatureType = getFeatureTypeForAttributes(Point.class, nodeColums); SimpleFeatureCollection pointFeatureSource; pointFeatureSource = getPointFeatureSource(previewModel, pointFeatureType, geoFields); //convert data to edgeFeatureSource AttributeColumn[] edgeColums = model.getEdgeTable().getColumns(); SimpleFeatureType edgeFeatureType = getFeatureTypeForAttributes(LineString.class, edgeColums); SimpleFeatureCollection edgeFeatureSource; edgeFeatureSource = getFeatureSource(false, previewModel, edgeFeatureType, geoFields); //Create Shapefile //Netbean securit-manager ist running wild - dunno what to do but cathc the exception writeSHP(pointFile.toURL(), pointFeatureType, pointFeatureSource); writeSHP(edgeFile.toURL(), edgeFeatureType, edgeFeatureSource); return true; } } catch (IOException ex) { Logger.getLogger(SHPExporter.class.getName()).log(Level.SEVERE, null, ex); } return true; } //Builds a SimpleFeatureType from all exportable Columns plus location, color and size private SimpleFeatureType getFeatureTypeForAttributes(Class geometryClass, AttributeColumn[] nodeColums) { SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); builder.setName(geometryClass.getName()); //Add a geometry builder.add(LOCATION_FIELD, geometryClass); for (AttributeColumn col : nodeColums) { String name = col.getTitle(); AttributeType typ = col.getType(); //ignore Lists? if (!typ.isListType()) { builder.add(name, typ.getType()); } } //add size and color attributes builder.add(SIZE_FIELD, Float.class); builder.add(COLOR_FIELD, String.class); //build the type SimpleFeatureType featureType = builder.buildFeatureType(); return featureType; } //Converts via parsing a String - might be risky as for localisation? private double getDoubleForCoordinateFieldObject(Object value) { return Double.parseDouble(value.toString()); } //Produce a geotools Point FeatureCollection from the Graph private SimpleFeatureCollection getPointFeatureSource(PreviewModel previewModel, SimpleFeatureType featureType, AttributeColumn[] geoFields) { boolean isPoints = true; SimpleFeatureCollection collection = getFeatureSource(isPoints, previewModel, featureType, geoFields); return collection; } //Produce a geotools FeatureCollection from the Graph private SimpleFeatureCollection getFeatureSource(boolean isPoints, PreviewModel previewModel, SimpleFeatureType featureType, AttributeColumn[] geoFields) { String sizeField = isPoints ? NodeItem.SIZE : EdgeItem.WEIGHT; String itemType = isPoints ? Item.NODE : Item.EDGE; String colorType = isPoints ? NodeItem.COLOR : EdgeItem.COLOR; //Helper to create the Point GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); SimpleFeatureCollection collection = FeatureCollections.newCollection(); SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType); //Iterate through Nodes for (org.gephi.preview.api.Item ni : previewModel.getItems(itemType)) { AttributeRow row = isPoints ? (AttributeRow) ((Node) ni.getSource()).getNodeData().getAttributes() : (AttributeRow) ((Edge) ni.getSource()).getEdgeData().getAttributes(); //Iterate over the columns to fill for (org.opengis.feature.type.AttributeType at : featureType.getTypes()) { String name = at.getName().getLocalPart(); if (name.equals(LOCATION_FIELD)) { if (isPoints) { Coordinate coordinate = getCoordinateForNode((Node) ni.getSource(), geoFields); Point point = geometryFactory.createPoint(coordinate); featureBuilder.add(point); } else { final Edge e = (Edge) ni.getSource(); Coordinate[] coordinates = {getCoordinateForNode(e.getSource(), geoFields), getCoordinateForNode(e.getTarget(), geoFields)}; LineString line = geometryFactory.createLineString(coordinates); featureBuilder.add(line); }; } else if (name.equals(SIZE_FIELD)) { Float size = (Float) ni.getData(sizeField); size = new Float(size.floatValue() * 0.05); //Scale down as it is a bit large in qgis featureBuilder.add(size); } else if (name.equals(COLOR_FIELD)) { String rgb = ""; Color color = (Color) ni.getData(colorType); if (color != null) { rgb = Integer.toHexString(color.getRGB()); rgb = rgb.substring(2, rgb.length()); } featureBuilder.add(rgb); } else { featureBuilder.add(row.getValue(name)); } } SimpleFeature feature = featureBuilder.buildFeature(null); collection.add(feature); } return collection; } private void writeSHP(URL url, SimpleFeatureType pointFeatureType, SimpleFeatureCollection pointFeatureSource) throws IOException { ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory(); ShapefileDataStore newDataStore; newDataStore = (ShapefileDataStore) dataStoreFactory.createDataStore(url); newDataStore.createSchema(pointFeatureType); //Write to the Shapefile Transaction transaction = new DefaultTransaction("create"); String typeName = newDataStore.getTypeNames()[0]; SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName); if (featureSource instanceof SimpleFeatureStore) { SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource; featureStore.setTransaction(transaction); try { featureStore.addFeatures(pointFeatureSource); transaction.commit(); } catch (Exception problem) { Logger.getLogger(SHPExporter.class.getName()).log(Level.SEVERE, null, problem); transaction.rollback(); } finally { transaction.close(); } } else { Logger.getLogger(SHPExporter.class.getName()).log(Level.SEVERE, null, typeName + " does not support read/write access"); } } private Coordinate getCoordinateForNode(Node node, AttributeColumn[] geoFields) { double latitude, longitude; //is there a location set? else use pseudo-coordinates... if (geoFields[0] != null) { final AttributeRow row = (AttributeRow) (node).getNodeData().getAttributes(); latitude = getDoubleForCoordinateFieldObject(row.getValue(geoFields[0])); longitude = getDoubleForCoordinateFieldObject(row.getValue(geoFields[1])); } else { latitude = node.getNodeData().x(); longitude = node.getNodeData().y(); } Coordinate coordinate = new Coordinate(latitude, longitude); return coordinate; } }