view src/java/de/intevation/mxd/writer/MapScriptWriter.java @ 87:7d4cf2db43f1

Added new writer classes to be flexible in creating mapfiles.
author Raimund Renkert <rrenkert@intevation.de>
date Tue, 31 May 2011 17:54:43 +0200
parents e468cf8701ea
children df2eb0e7d229
line wrap: on
line source
package de.intevation.mxd.writer;

import org.apache.log4j.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import javax.xml.xpath.XPathConstants;
import java.awt.Color;

import edu.umn.gis.mapscript.mapObj;
import edu.umn.gis.mapscript.layerObj;
import edu.umn.gis.mapscript.classObj;
import edu.umn.gis.mapscript.styleObj;
import edu.umn.gis.mapscript.colorObj;
import edu.umn.gis.mapscript.symbolObj;
import edu.umn.gis.mapscript.symbolSetObj;
import edu.umn.gis.mapscript.lineObj;
import edu.umn.gis.mapscript.pointObj;

import edu.umn.gis.mapscript.MS_UNITS;
import edu.umn.gis.mapscript.MS_LAYER_TYPE;
import edu.umn.gis.mapscript.MS_SYMBOL_TYPE;

import de.intevation.mxd.utils.XMLUtils;

/**
 * The Mapfile Writer.
 * This Writer uses the MapScript Java API to create Mapfiles from a DOM.
 *
 * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a>
 */
public class MapScriptWriter
implements IWriter
{
    /**
     * The Logger.
     */
    private static final Logger logger = Logger.getLogger(MapScriptWriter.class);

    /**
     * Private member.
     */
    private Document root;
    private mapObj map;
    private String mapFilename;

    public MapScriptWriter() {
        map = new mapObj("");
        mapFilename = "";
    }

    public MapScriptWriter(String templ, String filename) {
        map = new mapObj(templ);
        mapFilename = filename;
    }

    /**
     * Write the mapfile.
     * @param doc The root document containin the map attributes.
     *
     * @return Currently always true.
     */
    public boolean write(Document doc)
    throws Exception {
        logger.debug("write()");
        this.root = doc;

        //Get the filename.
        Element fileNode = (Element)XMLUtils.xpath(
            root,
            "/mxd/file",
            XPathConstants.NODE);
        //Write the map attributes.
        writeMap();
        //Write the layers.
        writeLayer();
        //Save the map.
        mapObj cloneMap = map.cloneMap();
        cloneMap.save(mapFilename);
        return true;
    }

    /**
     * Create the map object and set the attributes.
     */
    private void writeMap() {
        logger.debug("writeMap()");
        //Get the map.
        Element mapNode = (Element)XMLUtils.xpath(
            root,
            "/mxd/map",
            XPathConstants.NODE);

        //Set the name.
        map.setName(mapNode.getAttribute("name"));
        map.setMetaData("wms_title", mapNode.getAttribute("name"));
        //Set the extent.
        map.setExtent(
            Double.parseDouble(mapNode.getAttribute("extent_min_x")),
            Double.parseDouble(mapNode.getAttribute("extent_min_y")),
            Double.parseDouble(mapNode.getAttribute("extent_max_x")),
            Double.parseDouble(mapNode.getAttribute("extent_max_y")));

        //Set the units.
        String units = mapNode.getAttribute("units");
        MS_UNITS msu;
        if(units.equals("feet")) {
            msu = MS_UNITS.MS_FEET;
        }
        else if(units.equals("inches")) {
            msu = MS_UNITS.MS_INCHES;
        }
        else if(units.equals("kilometers")) {
            msu = MS_UNITS.MS_KILOMETERS;
        }
        else if(units.equals("meters")) {
            msu = MS_UNITS.MS_METERS;
        }
        else if(units.equals("miles")) {
            msu = MS_UNITS.MS_MILES;
        }
        else if(units.equals("nauticalmiles")) {
            msu = MS_UNITS.MS_NAUTICALMILES;
        }
        else if(units.equals("points")) {
            msu = MS_UNITS.MS_PIXELS;
        }
        else {
            msu = MS_UNITS.MS_METERS;
        }
        map.setUnits(msu);

        //TODO: Find out whats the correct scale value.
        //map.setScaledenom(Double.parseDouble(mapNode.getAttribute("scale")));
    }

    /**
     * Create layer objects and set the attributes.
     */
    private void writeLayer()
    throws Exception {
        logger.debug("writeLayer()");
        Element mapNode = (Element)XMLUtils.xpath(
            root,
            "/mxd/map",
            XPathConstants.NODE);
        NodeList list = mapNode.getElementsByTagName("layer");
        for(int i = 0; i < list.getLength(); i++) {
            Element layerElement = (Element)list.item(i);
            layerObj layer = new layerObj(map);

            //The layer name.
            layer.setName(layerElement.getAttribute("name"));

            //The layer status.
            String stat = layerElement.getAttribute("status");
            if (stat.equals("on")) {
                layer.setStatus(1);
            }
            else {
                layer.setStatus(0);
            }

            //The scale.
            double maxScale =
                Double.parseDouble(layerElement.getAttribute("max_scale"));
            double minScale =
                Double.parseDouble(layerElement.getAttribute("min_scale"));
            layer.setMaxscaledenom(maxScale);
            layer.setMinscaledenom(minScale);

            //The layer type.
            String type = layerElement.getAttribute("type");
            if(type.equals("point")) {
                layer.setType(MS_LAYER_TYPE.MS_LAYER_POINT);
            }
            else if (type.equals("line")) {
                layer.setType(MS_LAYER_TYPE.MS_LAYER_LINE);
            }

            //The layer datasource.
            layer.setData(layerElement.getAttribute("data_source"));

            //Write classes.
            writeClass(layer, layerElement);
        }

    }

    /**
     * Adds the classes to the layer.
     * @param layer        Mapscript layer object.
     * @param layerElement Dom element containing the class attributes.
     */
    private void writeClass(layerObj layer, Element layerElement)
    throws Exception {
        logger.debug("writeClass(layerObj, Element)");
        //Get all renderer elements (renderer in arcgis equals class in the
        //mapfile.)
        NodeList list = layerElement.getElementsByTagName("renderer");

        //Create all found class objects and write the symbols and styles for
        //each class.
        for(int i = 0; i < list.getLength(); i++) {
            Element classElement = (Element)list.item(i);
            classObj co = new classObj(layer);
            co.setName(classElement.getAttribute("name"));
            if(classElement.hasAttribute("field_count")) {
                int count =
                    Integer.parseInt(classElement.getAttribute("field_count"));
                String exp = "";
                for(int j = 0; j < count; j++) {
                    //TODO Find a way to create Expressions.
                    exp = "([" + classElement.getAttribute("expression_field_" + j);
                    exp += "] " + classElement.getAttribute("expression_operator");
                    exp += " " + classElement.getAttribute("value") + ")";
                }
                co.setExpression(exp);
            }
            //Write symbols and styles.
            NodeList slist = classElement.getElementsByTagName("symbol");
            String type = layerElement.getAttribute("type");
            if(type.equals("point")) {
                for(int j = 0; j < slist.getLength(); j++){
                    Element symbolElement = (Element) slist.item(j);
                    MarkerStyleWriter swriter = new MarkerStyleWriter (this.map, co);
                    swriter.write (symbolElement);
                }
            }
            else if(type.equals("line")) {
                for(int j = 0; j < slist.getLength(); j++){
                    Element symbolElement = (Element) slist.item(j);
                    LineStyleWriter swriter = new LineStyleWriter (this.map, co);
                    swriter.write (symbolElement);
                }
            }
            symbolSetObj symbolSet = map.getSymbolset();
            saveSymbolSet(symbolSet);
        }
    }

    /**
     * Adds the symbols and styles to the mapfile.
     * @param co           Mapscript class object.
     * @param classElement Dom element containing the style and symbol
     *                     attributes.
     */
    private void writeSymbol(classObj co, Element classElement) {
        //Get all symbol elements from dom.
        NodeList list = classElement.getElementsByTagName("symbol");

        //Get the symbol set from the map object.
        symbolSetObj symbolSet = map.getSymbolset();

        for(int i = 0; i < list.getLength(); i++){
            Element symbolElement = (Element) list.item(i);
            styleObj style = new styleObj(co);
            if (symbolElement.hasAttribute("angle")) {
                style.setAngle(
                    Double.parseDouble(symbolElement.getAttribute("angle")));
            }
            if(symbolElement.hasAttribute("color")) {
                String c = symbolElement.getAttribute("color");
                Color col = Color.decode(c);
                colorObj color = new colorObj(
                    col.getRed(),
                    col.getGreen(),
                    col.getBlue(),
                    -4);
                style.setColor(color);
            }
            if (symbolElement.hasAttribute ("size")) {
                style.setSize(Double.parseDouble(
                    symbolElement.getAttribute("size")));
            }
            if(symbolElement.hasAttribute("outline_color")) {
                Color oCol = Color.decode(
                    symbolElement.getAttribute("outline_color"));
                colorObj outlineColor = new colorObj(
                    oCol.getRed(),
                    oCol.getGreen(),
                    oCol.getBlue(),
                    -4);
                style.setOutlinecolor(outlineColor);
                style.setOutlinewidth(Double.parseDouble(
                    symbolElement.getAttribute("outline_size")));
            }
            //Section for line symbols
            //Setting the width
            if(symbolElement.hasAttribute("width")) {
                style.setWidth((int)Double.parseDouble(
                    symbolElement.getAttribute("width")));
            }
            String name = symbolElement.getAttribute("name");
            style.setSymbolByName(map, name);
            symbolObj sym = symbolSet.getSymbolByName(name);

            //The following lines are for dashed and/or dotted lines.
            //These lines throw an "incorrect array size" error.
            //TODO Find out how to set the pattern correctly.
//            style.setPatternlength(2);
//            double[] vals = new double[] {1.0, 2.0, 3.0};
//            vals[0] = 1.0;
//            vals[1] = 2.0;
//            vals[2] = 3.0;
//            vals[3] = 4.0;
//            style.setPattern(vals);
            String symType = symbolElement.getAttribute("style");
            if(symType.equals("point")) {
                writePointSymbol(sym, symbolElement);
            }
            else if (symType.equals("arrow")) {
                writeArrowSymbol(sym, symbolElement);
            }
            else if (symType.equals("char")) {
                writeCharSymbol(sym, symbolElement);
            }
            else if(symType.equals("line")) {
                writeSimpleLineSymbol(sym, symbolElement);
            }
        }
        saveSymbolSet(symbolSet);
    }


    /**
     * Write point symbols to the map.
     * @param symbol The symbol object.
     * @param symbolElement The DOM object containing the attributes.
     */
    private void writePointSymbol(symbolObj symbol, Element symbolElement) {
        lineObj points = new lineObj();
        points.add(new pointObj(1,1,0));
        symbol.setType(MS_SYMBOL_TYPE.MS_SYMBOL_ELLIPSE.swigValue());
        symbol.setPoints(points);
        symbol.setFilled(1);
    }


    /**
     * Write arrow symbol to the map.
     * @param symbol The symbol object.
     * @param symbolElement The DOM object containig the attributes.
     */
    private void writeArrowSymbol(symbolObj symbol, Element symbolElement) {
        double len = Double.parseDouble(symbolElement.getAttribute("length"));
        double width = Double.parseDouble(symbolElement.getAttribute("width"));
        double ratio = len/width;
        lineObj points = new lineObj();

        points.add(new pointObj(0, 0, 0));
        points.add(new pointObj((1*ratio), 0.5, 0));
        points.add(new pointObj(0, 1, 0));
        points.add(new pointObj(0, 0, 0));
        symbol.setType(MS_SYMBOL_TYPE.MS_SYMBOL_VECTOR.swigValue());
        symbol.setPoints(points);
        symbol.setFilled(1);
    }


    /**
     * Write font symbols to the map.
     * @param symbol The symbol object.
     * @param symbolElement The DOM object containing the attributes.
     */
    private void writeCharSymbol(symbolObj symbol, Element symbolElement) {
        //TODO Write the symbol correctly. See Issue 3885 on trac.osgeo.org
        symbol.setFont(symbolElement.getAttribute("font"));
        symbol.setType(MS_SYMBOL_TYPE.MS_SYMBOL_TRUETYPE.swigValue());
        symbol.setAntialias(1);
        symbol.setCharacter("#&" + symbolElement.getAttribute("char") + ";");
    }


    private void writeSimpleLineSymbol(
        symbolObj symbol,
        Element symbolElement) {
        logger.debug("writeSimpleLineSymbol()");
        symbol.setType(MS_SYMBOL_TYPE.MS_SYMBOL_SIMPLE.swigValue());
        String ls = symbolElement.getAttribute("linestyle");
        if(ls.equals("solid")) {
            symbol.setFilled(1);
        }
    }


    /**
     * Save the symbol set.
     * @param symbols The symbol set.
     */
    private void saveSymbolSet(symbolSetObj symbols) {
        Element fileNode = (Element)XMLUtils.xpath(
            root,
            "/mxd/file",
            XPathConstants.NODE);
        String path = "";
        if(mapFilename.contains("/")) {
            path = mapFilename.substring(0, mapFilename.lastIndexOf("/"));
        }
        else if(mapFilename.contains("\\")) {
            path = mapFilename.substring(0, mapFilename.lastIndexOf("\\"));
        }
        symbols.save(path + "/symbols.sym");
    }
}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)