rrenkert@41: package de.intevation.mxd.writer; rrenkert@41: rrenkert@41: import org.apache.log4j.Logger; rrenkert@41: rrenkert@41: import org.w3c.dom.Document; rrenkert@41: import org.w3c.dom.Element; rrenkert@41: import org.w3c.dom.NodeList; rrenkert@42: rrenkert@41: import javax.xml.xpath.XPathConstants; rrenkert@42: import java.awt.Color; rrenkert@41: rrenkert@41: import edu.umn.gis.mapscript.mapObj; rrenkert@41: import edu.umn.gis.mapscript.layerObj; rrenkert@42: import edu.umn.gis.mapscript.classObj; rrenkert@42: import edu.umn.gis.mapscript.styleObj; rrenkert@42: import edu.umn.gis.mapscript.colorObj; rrenkert@42: import edu.umn.gis.mapscript.symbolObj; rrenkert@42: import edu.umn.gis.mapscript.symbolSetObj; rrenkert@42: import edu.umn.gis.mapscript.lineObj; rrenkert@42: import edu.umn.gis.mapscript.pointObj; rrenkert@42: rrenkert@41: import edu.umn.gis.mapscript.MS_UNITS; rrenkert@42: import edu.umn.gis.mapscript.MS_LAYER_TYPE; rrenkert@42: import edu.umn.gis.mapscript.MS_SYMBOL_TYPE; rrenkert@41: rrenkert@41: import de.intevation.mxd.utils.XMLUtils; rrenkert@41: rrenkert@41: /** rrenkert@43: * The Mapfile Writer. rrenkert@43: * This Writer uses the MapScript Java API to create Mapfiles from a DOM. rrenkert@41: * rrenkert@41: * @author Raimund Renkert rrenkert@41: */ rrenkert@41: public class MapScriptWriter rrenkert@41: implements IWriter rrenkert@41: { rrenkert@43: /** rrenkert@43: * The Logger. rrenkert@43: */ rrenkert@43: private static final Logger logger = Logger.getLogger(MapScriptWriter.class); rrenkert@43: rrenkert@43: /** rrenkert@43: * Private member. rrenkert@43: */ rrenkert@41: private Document root; rrenkert@41: private mapObj map; rrenkert@55: private String mapFilename; rrenkert@41: rrenkert@41: public MapScriptWriter() { rrenkert@55: map = new mapObj(""); rrenkert@55: mapFilename = ""; rrenkert@41: } rrenkert@41: rrenkert@55: public MapScriptWriter(String templ, String filename) { rrenkert@55: map = new mapObj(templ); rrenkert@55: mapFilename = filename; rrenkert@41: } rrenkert@41: rrenkert@43: /** rrenkert@43: * Write the mapfile. rrenkert@43: * @param doc The root document containin the map attributes. rrenkert@43: * rrenkert@43: * @return Currently always true. rrenkert@43: */ rrenkert@41: public boolean write(Document doc) { rrenkert@41: logger.debug("write()"); rrenkert@41: this.root = doc; rrenkert@41: rrenkert@41: //Get the filename. rrenkert@41: Element fileNode = (Element)XMLUtils.xpath( rrenkert@41: root, rrenkert@41: "/mxd/file", rrenkert@41: XPathConstants.NODE); rrenkert@41: //Write the map attributes. rrenkert@41: writeMap(); rrenkert@42: //Write the layers. rrenkert@42: writeLayer(); rrenkert@41: //Save the map. rrenkert@42: mapObj cloneMap = map.cloneMap(); rrenkert@55: cloneMap.save(mapFilename); rrenkert@41: return true; rrenkert@41: } rrenkert@41: rrenkert@43: /** rrenkert@43: * Create the map object and set the attributes. rrenkert@43: */ rrenkert@41: private void writeMap() { rrenkert@41: logger.debug("writeMap()"); rrenkert@41: //Get the map. rrenkert@41: Element mapNode = (Element)XMLUtils.xpath( rrenkert@41: root, rrenkert@41: "/mxd/map", rrenkert@41: XPathConstants.NODE); rrenkert@41: rrenkert@41: //Set the name. rrenkert@41: map.setName(mapNode.getAttribute("name")); rrenkert@42: map.setMetaData("wms_title", mapNode.getAttribute("name")); rrenkert@41: //Set the extent. rrenkert@41: map.setExtent( rrenkert@41: Double.parseDouble(mapNode.getAttribute("extent_min_x")), rrenkert@41: Double.parseDouble(mapNode.getAttribute("extent_min_y")), rrenkert@41: Double.parseDouble(mapNode.getAttribute("extent_max_x")), rrenkert@41: Double.parseDouble(mapNode.getAttribute("extent_max_y"))); rrenkert@41: rrenkert@41: //Set the units. rrenkert@41: String units = mapNode.getAttribute("units"); rrenkert@41: MS_UNITS msu; rrenkert@41: if(units.equals("feet")) { rrenkert@41: msu = MS_UNITS.MS_FEET; rrenkert@41: } rrenkert@41: else if(units.equals("inches")) { rrenkert@41: msu = MS_UNITS.MS_INCHES; rrenkert@41: } rrenkert@41: else if(units.equals("kilometers")) { rrenkert@41: msu = MS_UNITS.MS_KILOMETERS; rrenkert@41: } rrenkert@41: else if(units.equals("meters")) { rrenkert@41: msu = MS_UNITS.MS_METERS; rrenkert@41: } rrenkert@41: else if(units.equals("miles")) { rrenkert@41: msu = MS_UNITS.MS_MILES; rrenkert@41: } rrenkert@41: else if(units.equals("nauticalmiles")) { rrenkert@41: msu = MS_UNITS.MS_NAUTICALMILES; rrenkert@41: } rrenkert@41: else if(units.equals("points")) { rrenkert@41: msu = MS_UNITS.MS_PIXELS; rrenkert@41: } rrenkert@41: else { rrenkert@57: msu = MS_UNITS.MS_METERS; rrenkert@41: } rrenkert@41: map.setUnits(msu); rrenkert@41: rrenkert@41: //TODO: Find out whats the correct scale value. rrenkert@41: //map.setScaledenom(Double.parseDouble(mapNode.getAttribute("scale"))); rrenkert@41: } rrenkert@41: rrenkert@43: /** rrenkert@43: * Create layer objects and set the attributes. rrenkert@43: */ rrenkert@41: private void writeLayer() { rrenkert@42: logger.debug("writeLayer()"); rrenkert@42: Element mapNode = (Element)XMLUtils.xpath( rrenkert@42: root, rrenkert@42: "/mxd/map", rrenkert@42: XPathConstants.NODE); rrenkert@42: NodeList list = mapNode.getElementsByTagName("layer"); rrenkert@42: for(int i = 0; i < list.getLength(); i++) { rrenkert@42: Element layerElement = (Element)list.item(i); rrenkert@42: layerObj layer = new layerObj(map); rrenkert@42: rrenkert@42: //The layer name. rrenkert@42: layer.setName(layerElement.getAttribute("name")); rrenkert@42: rrenkert@42: //The layer status. rrenkert@42: String stat = layerElement.getAttribute("status"); rrenkert@42: if (stat.equals("on")) { rrenkert@42: layer.setStatus(1); rrenkert@42: } rrenkert@42: else { rrenkert@42: layer.setStatus(0); rrenkert@42: } rrenkert@42: rrenkert@42: //The scale. rrenkert@42: double maxScale = rrenkert@42: Double.parseDouble(layerElement.getAttribute("max_scale")); rrenkert@42: double minScale = rrenkert@42: Double.parseDouble(layerElement.getAttribute("min_scale")); rrenkert@42: layer.setMaxscaledenom(maxScale); rrenkert@42: layer.setMinscaledenom(minScale); rrenkert@42: rrenkert@42: //The layer type. rrenkert@42: String type = layerElement.getAttribute("type"); rrenkert@42: if(type.equals("point")) { rrenkert@42: layer.setType(MS_LAYER_TYPE.MS_LAYER_POINT); rrenkert@42: } rrenkert@42: rrenkert@42: //The layer datasource. rrenkert@42: layer.setData(layerElement.getAttribute("data_source")); rrenkert@42: rrenkert@42: //Write classes. rrenkert@42: writeClass(layer, layerElement); rrenkert@42: } rrenkert@41: rrenkert@41: } rrenkert@41: rrenkert@42: /** rrenkert@42: * Adds the classes to the layer. rrenkert@42: * @param layer Mapscript layer object. rrenkert@42: * @param layerElement Dom element containing the class attributes. rrenkert@42: */ rrenkert@42: private void writeClass(layerObj layer, Element layerElement) { rrenkert@42: //Get all renderer elements (renderer in arcgis equals class in the rrenkert@42: //mapfile.) rrenkert@42: NodeList list = layerElement.getElementsByTagName("renderer"); rrenkert@41: rrenkert@42: //Create all found class objects and write the symbols and styles for rrenkert@42: //each class. rrenkert@42: for(int i = 0; i < list.getLength(); i++) { rrenkert@42: Element classElement = (Element)list.item(i); rrenkert@42: classObj co = new classObj(layer); rrenkert@42: co.setName(classElement.getAttribute("name")); rrenkert@44: if(classElement.hasAttribute("field_count")) { rrenkert@44: int count = rrenkert@44: Integer.parseInt(classElement.getAttribute("field_count")); rrenkert@44: String exp = ""; rrenkert@44: for(int j = 0; j < count; j++) { rrenkert@44: //TODO Find a way to create Expressions. rrenkert@44: exp = "([" + classElement.getAttribute("expression_field_" + j); rrenkert@46: exp += "] " + classElement.getAttribute("expression_operator"); rrenkert@46: exp += " " + classElement.getAttribute("value") + ")"; rrenkert@44: } rrenkert@44: co.setExpression(exp); rrenkert@44: } rrenkert@42: //Write symbols and styles. rrenkert@42: writeSymbol(co, classElement); rrenkert@42: } rrenkert@41: } rrenkert@41: rrenkert@42: /** rrenkert@43: * Adds the symbols and styles to the mapfile. rrenkert@42: * @param co Mapscript class object. rrenkert@42: * @param classElement Dom element containing the style and symbol rrenkert@42: * attributes. rrenkert@42: */ rrenkert@42: private void writeSymbol(classObj co, Element classElement) { rrenkert@42: //Get all symbol elements from dom. rrenkert@42: NodeList list = classElement.getElementsByTagName("symbol"); rrenkert@41: rrenkert@42: //Get the symbol set from the map object. rrenkert@42: symbolSetObj symbolSet = map.getSymbolset(); rrenkert@42: rrenkert@42: // rrenkert@42: for(int i = 0; i < list.getLength(); i++){ rrenkert@42: Element symbolElement = (Element) list.item(i); rrenkert@42: styleObj style = new styleObj(co); rrenkert@42: style.setAngle( rrenkert@42: Double.parseDouble(symbolElement.getAttribute("angle"))); rrenkert@55: if(symbolElement.hasAttribute("color")) { rrenkert@55: String c = symbolElement.getAttribute("color"); rrenkert@55: Color col = Color.decode(c); rrenkert@55: colorObj color = new colorObj( rrenkert@55: col.getRed(), rrenkert@55: col.getGreen(), rrenkert@55: col.getBlue(), rrenkert@55: -4); rrenkert@55: style.setColor(color); rrenkert@55: } rrenkert@43: style.setSize(Double.parseDouble( rrenkert@43: symbolElement.getAttribute("size"))); rrenkert@46: if(symbolElement.hasAttribute("outline_color")) { rrenkert@46: Color oCol = Color.decode( rrenkert@46: symbolElement.getAttribute("outline_color")); rrenkert@46: colorObj outlineColor = new colorObj( rrenkert@46: oCol.getRed(), rrenkert@46: oCol.getGreen(), rrenkert@46: oCol.getBlue(), rrenkert@46: -4); rrenkert@46: style.setOutlinecolor(outlineColor); rrenkert@46: style.setOutlinewidth(Double.parseDouble( rrenkert@46: symbolElement.getAttribute("outline_size"))); rrenkert@46: } rrenkert@43: String name = symbolElement.getAttribute("name"); rrenkert@43: style.setSymbolByName(map, name); rrenkert@43: symbolObj sym = symbolSet.getSymbolByName(name); rrenkert@43: rrenkert@42: String symType = symbolElement.getAttribute("style"); rrenkert@42: if(symType.equals("point")) { rrenkert@49: writePointSymbol(sym, symbolElement); rrenkert@42: } rrenkert@46: else if (symType.equals("arrow")) { rrenkert@49: writeArrowSymbol(sym, symbolElement); rrenkert@49: } rrenkert@49: else if (symType.equals("char")) { rrenkert@49: writeCharSymbol(sym, symbolElement); rrenkert@46: } rrenkert@42: } rrenkert@42: saveSymbolSet(symbolSet); rrenkert@41: } rrenkert@41: rrenkert@49: rrenkert@49: /** rrenkert@49: * Write point symbols to the map. rrenkert@49: * @param symbol The symbol object. rrenkert@49: * @param symbolElement The DOM object containing the attributes. rrenkert@49: */ rrenkert@49: private void writePointSymbol(symbolObj symbol, Element symbolElement) { rrenkert@49: lineObj points = new lineObj(); rrenkert@49: points.add(new pointObj(1,1,0)); rrenkert@49: symbol.setType(MS_SYMBOL_TYPE.MS_SYMBOL_ELLIPSE.swigValue()); rrenkert@49: symbol.setPoints(points); rrenkert@49: symbol.setFilled(1); rrenkert@49: } rrenkert@49: rrenkert@49: rrenkert@49: /** rrenkert@49: * Write arrow symbol to the map. rrenkert@49: * @param symbol The symbol object. rrenkert@49: * @param symbolElement The DOM object containig the attributes. rrenkert@49: */ rrenkert@49: private void writeArrowSymbol(symbolObj symbol, Element symbolElement) { rrenkert@49: double len = Double.parseDouble(symbolElement.getAttribute("length")); rrenkert@49: double width = Double.parseDouble(symbolElement.getAttribute("width")); rrenkert@49: double ratio = len/width; rrenkert@49: lineObj points = new lineObj(); rrenkert@49: rrenkert@49: points.add(new pointObj(0, 0, 0)); rrenkert@49: points.add(new pointObj((1*ratio), 0.5, 0)); rrenkert@49: points.add(new pointObj(0, 1, 0)); rrenkert@49: points.add(new pointObj(0, 0, 0)); rrenkert@49: symbol.setType(MS_SYMBOL_TYPE.MS_SYMBOL_VECTOR.swigValue()); rrenkert@49: symbol.setPoints(points); rrenkert@49: symbol.setFilled(1); rrenkert@49: } rrenkert@49: rrenkert@49: rrenkert@49: /** rrenkert@49: * Write font symbols to the map. rrenkert@49: * @param symbol The symbol object. rrenkert@49: * @param symbolElement The DOM object containing the attributes. rrenkert@49: */ rrenkert@49: private void writeCharSymbol(symbolObj symbol, Element symbolElement) { rrenkert@59: //TODO Write the symbol correctly. See Issue 3885 on trac.osgeo.org rrenkert@49: symbol.setFont(symbolElement.getAttribute("font")); rrenkert@49: symbol.setType(MS_SYMBOL_TYPE.MS_SYMBOL_TRUETYPE.swigValue()); rrenkert@49: symbol.setAntialias(1); rrenkert@49: symbol.setCharacter("#&" + symbolElement.getAttribute("char") + ";"); rrenkert@49: } rrenkert@49: rrenkert@49: rrenkert@42: /** rrenkert@42: * Save the symbol set. rrenkert@43: * @param symbols The symbol set. rrenkert@42: */ rrenkert@42: private void saveSymbolSet(symbolSetObj symbols) { rrenkert@42: Element fileNode = (Element)XMLUtils.xpath( rrenkert@42: root, rrenkert@42: "/mxd/file", rrenkert@42: XPathConstants.NODE); rrenkert@59: String mapFilename = fileNode.getAttribute("name"); rrenkert@42: String path = ""; rrenkert@59: if(mapFilename.contains("/")) { rrenkert@59: path = mapFilename.substring(0, mapFilename.lastIndexOf("/")); rrenkert@42: } rrenkert@59: else if(mapFilename.contains("\\")) { rrenkert@59: path = mapFilename.substring(0, mapFilename.lastIndexOf("\\")); rrenkert@42: } rrenkert@42: symbols.save(path + "/symbols.sym"); rrenkert@42: } rrenkert@41: } rrenkert@41: