0001: //$$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/tools/shape/AVL2SLD.java $$
0002: /*---------------- FILE HEADER ------------------------------------------
0003: This file is part of deegree.
0004: Copyright (C) 2001-2008 by:
0005: Department of Geography, University of Bonn
0006: http://www.giub.uni-bonn.de/deegree/
0007: lat/lon GmbH
0008: http://www.lat-lon.de
0009:
0010: This library is free software; you can redistribute it and/or
0011: modify it under the terms of the GNU Lesser General Public
0012: License as published by the Free Software Foundation; either
0013: version 2.1 of the License, or (at your option) any later version.
0014:
0015: This library is distributed in the hope that it will be useful,
0016: but WITHOUT ANY WARRANTY; without even the implied warranty of
0017: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0018: Lesser General Public License for more details.
0019:
0020: You should have received a copy of the GNU Lesser General Public
0021: License along with this library; if not, write to the Free Software
0022: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0023:
0024: Contact:
0025:
0026: Andreas Poth
0027: lat/lon GmbH
0028: Aennchenstraße 19
0029: 53177 Bonn
0030: Germany
0031: E-Mail: poth@lat-lon.de
0032:
0033: Prof. Dr. Klaus Greve
0034: Department of Geography
0035: University of Bonn
0036: Meckenheimer Allee 166
0037: 53115 Bonn
0038: Germany
0039: E-Mail: greve@giub.uni-bonn.de
0040:
0041: ---------------------------------------------------------------------------*/
0042:
0043: package org.deegree.tools.shape;
0044:
0045: import java.awt.Color;
0046: import java.awt.image.BufferedImage;
0047: import java.io.File;
0048: import java.io.FileOutputStream;
0049: import java.io.FileReader;
0050: import java.io.FileWriter;
0051: import java.io.FilenameFilter;
0052: import java.io.IOException;
0053: import java.io.Reader;
0054: import java.util.ArrayList;
0055: import java.util.HashMap;
0056: import java.util.List;
0057: import java.util.Map;
0058: import java.util.regex.Matcher;
0059: import java.util.regex.Pattern;
0060:
0061: import org.deegree.datatypes.QualifiedName;
0062: import org.deegree.framework.util.ImageUtils;
0063: import org.deegree.framework.util.StringTools;
0064: import org.deegree.framework.xml.Marshallable;
0065: import org.deegree.graphics.sld.AbstractLayer;
0066: import org.deegree.graphics.sld.AbstractStyle;
0067: import org.deegree.graphics.sld.ExternalGraphic;
0068: import org.deegree.graphics.sld.FeatureTypeStyle;
0069: import org.deegree.graphics.sld.Fill;
0070: import org.deegree.graphics.sld.Font;
0071: import org.deegree.graphics.sld.Graphic;
0072: import org.deegree.graphics.sld.GraphicFill;
0073: import org.deegree.graphics.sld.LabelPlacement;
0074: import org.deegree.graphics.sld.LineSymbolizer;
0075: import org.deegree.graphics.sld.Mark;
0076: import org.deegree.graphics.sld.NamedLayer;
0077: import org.deegree.graphics.sld.PointPlacement;
0078: import org.deegree.graphics.sld.PointSymbolizer;
0079: import org.deegree.graphics.sld.PolygonSymbolizer;
0080: import org.deegree.graphics.sld.Rule;
0081: import org.deegree.graphics.sld.Stroke;
0082: import org.deegree.graphics.sld.StyleFactory;
0083: import org.deegree.graphics.sld.StyledLayerDescriptor;
0084: import org.deegree.graphics.sld.Symbolizer;
0085: import org.deegree.graphics.sld.TextSymbolizer;
0086: import org.deegree.io.shpapi.MainFile;
0087: import org.deegree.io.shpapi.ShapeConst;
0088: import org.deegree.model.filterencoding.ComplexFilter;
0089: import org.deegree.model.filterencoding.Filter;
0090: import org.deegree.model.filterencoding.FilterConstructionException;
0091: import org.deegree.model.filterencoding.Literal;
0092: import org.deegree.model.filterencoding.LogicalOperation;
0093: import org.deegree.model.filterencoding.Operation;
0094: import org.deegree.model.filterencoding.OperationDefines;
0095: import org.deegree.model.filterencoding.PropertyIsCOMPOperation;
0096: import org.deegree.model.filterencoding.PropertyName;
0097:
0098: /**
0099: * <p>
0100: * This class converts ESRI *.avl files to OGC SLD documents. The current version of this tool isn't
0101: * able to convert each and every construction that is possible with an *.avl file. But most of the
0102: * common expressions will be mapped.
0103: * </p>
0104: * <p>
0105: * Because SLD (version 1.0.0) does not know inline bitmap or fill pattern definition directly
0106: * (maybe it is possible using some SVG tags) all polygon fill patterns must be converted to images
0107: * that are written to the file system and referenced as external graphic by the created SLD style.
0108: * The similar is true for symbol definitions. SLD just 'knowns' a few predefined symbols that are
0109: * not able to capture all symbols known by ArcView. In this context deegree also will extend the
0110: * well known symbol by using ASCII codes to references symbols defined in an available font. This
0111: * will enable deegree to transform the ArcView option defining a symbol by using an ACSII character
0112: * directly. At least even if the synthax for this is SLD compliant most SLD implementation probably
0113: * won't be able to evaluate this.
0114: * </p>
0115: *
0116: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth </a>
0117: * @author last edited by: $Author: aschmitz $
0118: *
0119: * @version $Revision: 10466 $, $Date: 2008-03-06 00:32:01 -0800 (Thu, 06 Mar 2008) $
0120: */
0121: public class AVL2SLD {
0122:
0123: private String fileRootName = null;
0124:
0125: private String targetDir = null;
0126:
0127: private Map<String, Map<String, Object>> blocks = new HashMap<String, Map<String, Object>>();
0128:
0129: private static AVLPointSymbolCodeList cl = null;
0130:
0131: /**
0132: * @param fileRootName
0133: * @param targetDir
0134: */
0135: public AVL2SLD(String fileRootName, String targetDir) {
0136: this .fileRootName = fileRootName;
0137: this .targetDir = targetDir;
0138: if (!this .targetDir.endsWith("/")) {
0139: this .targetDir = this .targetDir + "/";
0140: }
0141: }
0142:
0143: /**
0144: * reads the avl file assigned to a class instance
0145: *
0146: * @throws IOException
0147: */
0148: public void read() throws IOException {
0149: Reader reader = new FileReader(fileRootName + ".avl");
0150: StringBuffer sb = new StringBuffer(50000);
0151: int c = 0;
0152: while ((c = reader.read()) > -1) {
0153: if (c == 9)
0154: c = ' ';
0155: // if ( c != 10 && c != 13) {
0156: sb.append((char) c);
0157: // }
0158: }
0159: reader.close();
0160:
0161: // create a entry in 'blocks' for each '(' ... ')'
0162: // enclosed section
0163: String[] s1 = splitavl(sb.toString());
0164:
0165: for (int i = 1; i < s1.length; i++) {
0166: // write each KVP of section to a map and store it
0167: // in the blocks map.
0168: // the Class, Pattern and he Child key will be treated
0169: // as array because it isn't unique
0170: int pos = s1[i].indexOf(' ');
0171: if (pos < 0)
0172: continue;
0173: String section = s1[i].substring(0, pos).trim();
0174: String[] s2 = StringTools.toArray(s1[i].substring(pos,
0175: s1[i].length()), ":\n", false);
0176: Map<String, Object> block = new HashMap<String, Object>();
0177: for (int j = 0; j < s2.length; j = j + 2) {
0178: if (s2[j].trim().equals("Class")) {
0179: List<String> list = (List<String>) block
0180: .get("Class");
0181: if (list == null) {
0182: list = new ArrayList<String>();
0183: }
0184: list.add(s2[j + 1]);
0185: block.put(s2[j], list);
0186: } else if (s2[j].trim().equals("Child")) {
0187: List<String> list = (List<String>) block
0188: .get("Child");
0189: if (list == null) {
0190: list = new ArrayList<String>();
0191: }
0192: list.add(s2[j + 1]);
0193: block.put(s2[j], list);
0194: } else if (s2[j].trim().equals("Pattern")) {
0195: List<String> list = (List<String>) block
0196: .get("Pattern");
0197: if (list == null) {
0198: list = new ArrayList<String>();
0199: }
0200: list.add(s2[j + 1]);
0201: block.put(s2[j], list);
0202: } else if (s2[j].trim().equals("Bits")) {
0203: List<String> list = (List<String>) block
0204: .get("Bits");
0205: if (list == null) {
0206: list = new ArrayList<String>();
0207: }
0208: list.add(s2[j + 1]);
0209: block.put(s2[j], list);
0210: } else {
0211: block.put(s2[j], s2[j + 1].trim());
0212: }
0213: }
0214: blocks.put(section, block);
0215: }
0216:
0217: }
0218:
0219: /**
0220: * returns a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
0221: * will be created
0222: *
0223: * @return a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
0224: * will be created
0225: * @throws IOException
0226: * @throws Exception
0227: */
0228: public AbstractStyle getStyle() throws IOException, Exception {
0229: Map odb = blocks.get("ODB.1");
0230: String roots = (String) odb.get("Roots");
0231: Map legend = blocks.get("Legend." + roots);
0232: String filterCol = null;
0233: if (legend.get("FieldNames") != null) {
0234: Map block = blocks.get("AVStr." + legend.get("FieldNames"));
0235: filterCol = (String) block.get("S");
0236: filterCol = StringTools.validateString(filterCol, "\"")
0237: .toUpperCase();
0238: }
0239:
0240: int geoType = getGeometryType();
0241:
0242: AbstractStyle style = null;
0243: switch (geoType) {
0244: case ShapeConst.SHAPE_TYPE_POINT:
0245: style = createPointStyle(legend, filterCol);
0246: break;
0247: case ShapeConst.SHAPE_TYPE_POLYLINE:
0248: style = createLinesStyle(legend, filterCol);
0249: break;
0250: case ShapeConst.SHAPE_TYPE_POLYGON:
0251: style = createPolygonStyle(legend, filterCol);
0252: break;
0253: case ShapeConst.SHAPE_TYPE_MULTIPOINT:
0254: style = createPointStyle(legend, filterCol);
0255: break;
0256: default:
0257: throw new Exception("unknown geometry type: " + geoType);
0258: }
0259: return style;
0260: }
0261:
0262: /**
0263: * creates a <tt>StyledLayerDescriptor</tt> from the avl file assigned to the instace of a
0264: * <tt>AVLReader</tt>. The returned instance of a <tt>StyledLayerDescriptor</tt> just
0265: * contains one style that may containes several <tt>Rule</tt>s
0266: *
0267: * @return a <tt>StyledLayerDescriptor</tt> created from the avl file assigned to the instace
0268: * of a <tt>AVLReader</tt>. The returned instance of a <tt>StyledLayerDescriptor</tt>
0269: * just contains one style that may containes several <tt>Rule</tt>s
0270: * @throws IOException
0271: * @throws Exception
0272: */
0273: public StyledLayerDescriptor getStyledLayerDescriptor()
0274: throws IOException, Exception {
0275: AbstractStyle style = getStyle();
0276: String[] t = StringTools.toArray(fileRootName, "/", false);
0277: String name = "default:" + t[t.length - 1];
0278: AbstractLayer layer = new NamedLayer(name, null,
0279: new AbstractStyle[] { style });
0280: return new StyledLayerDescriptor(new AbstractLayer[] { layer },
0281: "1.0.0");
0282: }
0283:
0284: /**
0285: * @return parse a string and return array of blocks between braces "(" and ")". It accounts for braces
0286: * in quoted strings.
0287: *
0288: * @param s
0289: * string to parse
0290: */
0291: public static String[] splitavl(String s) {
0292: if (s == null || s.equals("")) {
0293: return new String[0];
0294: }
0295:
0296: Pattern pat = Pattern.compile("\\(([^)\"]|\"[^\"]*\")*\\)");
0297: Matcher mat = pat.matcher(s);
0298: int prevend = 0;
0299: ArrayList<String> vec = new ArrayList<String>();
0300: while (mat.find()) {
0301: int start = mat.start();
0302: int end = mat.end();
0303: if (prevend < start - 1) {
0304: String str = s.substring(prevend, start).trim();
0305: if (str.length() > 0) {
0306: vec.add(str);
0307: }
0308: }
0309: String str = s.substring(start + 1, end - 1).trim();
0310: if (str.length() > 0) {
0311: vec.add(str);
0312: }
0313: prevend = end;
0314: }
0315: if (prevend < s.length() - 1) {
0316: String str = s.substring(prevend).trim();
0317: if (str.length() > 0) {
0318: vec.add(str);
0319: }
0320: }
0321:
0322: // no value selected
0323: if (vec.size() == 0) {
0324: return new String[0];
0325: }
0326:
0327: return vec.toArray(new String[vec.size()]);
0328: }
0329:
0330: private int getGeometryType() throws IOException {
0331: MainFile mf = new MainFile(fileRootName);
0332: int type = mf.getShapeTypeByRecNo(1);
0333: mf.close();
0334: return type;
0335: }
0336:
0337: /**
0338: * creates a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
0339: * will be created
0340: *
0341: * @param legend
0342: * @param filterCol
0343: * @return a <tt>Style</tt>.
0344: */
0345: // private AbstractStyle[] createPointStyles( Map legend, String filterCol ) {
0346: // AbstractStyle[] styles = null;
0347: // return styles;
0348: // }
0349: /**
0350: * creates a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
0351: * will be created
0352: *
0353: * @param legend
0354: * @param filterCol
0355: * @return a <tt>Style</tt>.
0356: */
0357: private AbstractStyle createPointStyle(Map legend, String filterCol)
0358: throws FilterConstructionException {
0359: try {
0360: cl = new AVLPointSymbolCodeList();
0361: } catch (Exception e) {
0362: e.printStackTrace();
0363: }
0364: String tmp = (String) legend.get("Symbols");
0365: Map block = blocks.get("SymList." + tmp);
0366: List classes = (List) legend.get("Class");
0367: List children = (List) block.get("Child");
0368:
0369: List<Rule> list = new ArrayList<Rule>(classes.size());
0370: for (int i = 0; i < classes.size(); i++) {
0371: String clNo = (String) classes.get(i);
0372: Map clss = blocks.get("LClass." + clNo);
0373: String childNo = (String) children.get(i);
0374: Map<String, Object> child = blocks.get("CMkSym." + childNo);
0375: Rule rule = null;
0376: if (child == null) {
0377: child = blocks.remove("BMkSym." + childNo);
0378: rule = createSimplePointRule(clss, child, filterCol);
0379: } else {
0380: rule = createComplexPointRule(clss, child, filterCol);
0381: }
0382: if (rule != null) {
0383: list.add(rule);
0384: }
0385: }
0386: Rule[] rules = list.toArray(new Rule[list.size()]);
0387: FeatureTypeStyle fts = StyleFactory
0388: .createFeatureTypeStyle(rules);
0389:
0390: String[] t = StringTools.toArray(fileRootName, "/", false);
0391: String name = "default:" + t[t.length - 1];
0392: return StyleFactory.createStyle(name, null, null, fts);
0393: }
0394:
0395: /**
0396: * creates a Style for a line symbol
0397: *
0398: * @param clss
0399: * @param child
0400: * @return a Style for a line symbol
0401: */
0402: private Rule createSimplePointRule(Map clss,
0403: Map<String, Object> child, String filterCol) {
0404:
0405: if (clss.get("IsNoData") != null) {
0406: return null;
0407: }
0408:
0409: String label = (String) clss.get("Label");
0410: label = StringTools.validateString(label, "\"");
0411: Filter filter = createFilter(clss, filterCol);
0412: // get foreground color
0413: String clrIdx = (String) child.get("Color");
0414: Map<String, Object> color = blocks.get("TClr." + clrIdx);
0415: double fgOpacity = 1f;
0416: if (color != null
0417: && "\"Transparent\"".equals(color.get("Name"))) {
0418: fgOpacity = 0f;
0419: }
0420: Color fgColor = createColor(color);
0421: if (fgColor == null) {
0422: fgColor = Color.BLACK;
0423: }
0424: // get background color (what ever this means)
0425: clrIdx = (String) child.get("BgColor");
0426: color = blocks.get("TClr." + clrIdx);
0427: double bgOpacity = 1f;
0428: if (color != null
0429: && "\"Transparent\"".equals(color.get("Name"))) {
0430: bgOpacity = 0f;
0431: }
0432: Color bgColor = createColor(color);
0433: if (bgColor == null) {
0434: bgColor = Color.BLACK;
0435: }
0436:
0437: double size = Double.parseDouble((String) child.get("Size"));
0438: double rotation = Double.parseDouble((String) child
0439: .get("Angle"));
0440:
0441: // creation of a font from a avl file is a triky thing because
0442: // esri uses their own font names and codes
0443: // --> don' know if this works
0444: String fntIdx = (String) child.get("Font");
0445: Map fntMap = blocks.get("NFont." + fntIdx);
0446: Font font = createFont(fntMap);
0447: PointPlacement pp = StyleFactory.createPointPlacement();
0448: LabelPlacement labelPlacement = StyleFactory
0449: .createLabelPlacement(pp);
0450: TextSymbolizer textSym = StyleFactory.createTextSymbolizer(
0451: fgColor, font, filterCol, labelPlacement);
0452:
0453: String patternIdx = (String) ((ArrayList) child.get("Pattern"))
0454: .get(0);
0455: String symbol = cl.getSymbol(patternIdx);
0456:
0457: // create a Mark with a stroke and fill to controll both
0458: // opacities
0459: Stroke stroke = StyleFactory.createStroke(fgColor, 1,
0460: fgOpacity, null, "mitre", "butt");
0461: Fill fill = StyleFactory.createFill(bgColor, bgOpacity);
0462: Mark mark = StyleFactory.createMark(symbol, fill, stroke);
0463:
0464: Graphic graphic = StyleFactory.createGraphic(null, mark, 1,
0465: size, rotation);
0466: PointSymbolizer pointSym = StyleFactory
0467: .createPointSymbolizer(graphic);
0468:
0469: return StyleFactory.createRule(new Symbolizer[] { pointSym,
0470: textSym }, label, label, "", null, filter, false, 0,
0471: 9E99);
0472: }
0473:
0474: private Rule createComplexPointRule(Map clss,
0475: Map<String, Object> child, String filterCol)
0476: throws FilterConstructionException {
0477:
0478: if (clss.get("IsNoData") != null) {
0479: return null;
0480: }
0481:
0482: String tmp = (String) child.get("Symbols");
0483: Map block = blocks.get("SymList." + tmp);
0484: List children = (List) block.get("Child");
0485:
0486: List<Symbolizer> smbls = new ArrayList<Symbolizer>();
0487: for (int i = 0; i < children.size(); i++) {
0488: String childNo = (String) children.get(i);
0489: Map child_ = blocks.get("CMkSym." + childNo);
0490: Rule rule = null;
0491: if (child_ == null) {
0492: child = blocks.remove("BMkSym." + childNo);
0493: rule = createSimplePointRule(clss, child, filterCol);
0494: } else {
0495: rule = createComplexPointRule(clss, child, filterCol);
0496: }
0497: Symbolizer[] sym = rule.getSymbolizers();
0498: for (int j = 0; j < sym.length; j++) {
0499: smbls.add(sym[j]);
0500: }
0501: }
0502: Symbolizer[] sym = new Symbolizer[smbls.size()];
0503: sym = smbls.toArray(sym);
0504:
0505: String label = (String) clss.get("Label");
0506: label = StringTools.validateString(label, "\"");
0507: Filter filter = createFilter(clss, filterCol);
0508:
0509: return StyleFactory.createRule(sym, label, label, "", null,
0510: filter, false, 0, 9E99);
0511: }
0512:
0513: private Font createFont(Map fntMap) {
0514: String idx = (String) fntMap.get("Family");
0515: String family = (String) blocks.get("AVStr." + idx).get("S");
0516: idx = (String) fntMap.get("Name");
0517: String name = (String) blocks.get("AVStr." + idx).get("S");
0518: idx = (String) fntMap.get("Style");
0519: String style = (String) blocks.get("AVStr." + idx).get("S");
0520: String weight = (String) fntMap.get("Weight");
0521: String wideness = (String) fntMap.get("Wideness");
0522:
0523: boolean italic = style.equals("Italic");
0524: boolean bold = Integer.parseInt(weight) > 1;
0525:
0526: return StyleFactory.createFont(family, italic, bold, 12);
0527: }
0528:
0529: /**
0530: * creates a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
0531: * will be created
0532: *
0533: * @param legend
0534: * @param filterCol
0535: * @return a <tt>Style</tt>.
0536: */
0537: private AbstractStyle createLinesStyle(Map legend, String filterCol) {
0538: String tmp = (String) legend.get("Symbols");
0539: Map block = blocks.get("SymList." + tmp);
0540: List classes = (List) legend.get("Class");
0541: List children = (List) block.get("Child");
0542: List<Rule> list = new ArrayList<Rule>(classes.size());
0543: for (int i = 0; i < classes.size(); i++) {
0544: String clNo = (String) classes.get(i);
0545: Map clss = blocks.get("LClass." + clNo);
0546: String childNo = (String) children.get(i);
0547: Map<String, Object> child = blocks.get("BLnSym." + childNo);
0548:
0549: if (child == null) {
0550: // won't be treated correctly because we can't transform
0551: // lines with sambols at the moment
0552: child = blocks.get("CLnSym." + childNo);
0553: }
0554: Rule rule = createLineRule(clss, child, filterCol);
0555: if (rule != null) {
0556: list.add(rule);
0557: }
0558: }
0559: Rule[] rules = list.toArray(new Rule[list.size()]);
0560: FeatureTypeStyle fts = StyleFactory
0561: .createFeatureTypeStyle(rules);
0562:
0563: String[] t = StringTools.toArray(fileRootName, "/", false);
0564: String name = "default:" + t[t.length - 1];
0565: return StyleFactory.createStyle(name, null, null, fts);
0566: }
0567:
0568: /**
0569: * creates a Style for a line symbol
0570: *
0571: * @param clss
0572: * @param child
0573: * @return a Style for a line symbol
0574: */
0575: private Rule createLineRule(Map clss, Map<String, Object> child,
0576: String filterCol) {
0577:
0578: if (clss.get("IsNoData") != null) {
0579: return null;
0580: }
0581:
0582: String label = (String) clss.get("Label");
0583: label = StringTools.validateString(label, "\"");
0584: Filter filter = createFilter(clss, filterCol);
0585:
0586: String clrIdx = (String) child.get("Color");
0587: Map<String, Object> color = blocks.get("TClr." + clrIdx);
0588: double opacity = 1f;
0589: if (color != null
0590: && "\"Transparent\"".equals(color.get("Name"))
0591: && color.size() > 0) {
0592: opacity = 0f;
0593: }
0594: Color colour = createColor(color);
0595: if (colour == null) {
0596: colour = Color.BLACK;
0597: }
0598:
0599: double width = 1.0; // default Width
0600: if (child.get("Width") != null) {
0601: width = Double.parseDouble((String) child.get("Width"))
0602: + width;
0603: }
0604: // double width = Double.parseDouble( (String)child.get("Width") ) + 1;
0605: List<String> pl = (List<String>) child.get("Pattern");
0606:
0607: if (child.get("Pattern") == null) { // create a default pattern List if
0608: // it is null
0609: pl = new ArrayList<String>();
0610: for (int i = 0; i < 16; i++) { // Fill the default List with
0611: // default values "0.00000000000000"
0612: pl.add("0.00000000000000");
0613: }
0614: }
0615:
0616: // List pl = (List)child.get("Pattern");
0617: float[] dashArray = createDashArray(pl);
0618: Stroke stroke = StyleFactory.createStroke(colour, width,
0619: opacity, dashArray, "mitre", "butt");
0620: LineSymbolizer lineSym = StyleFactory
0621: .createLineSymbolizer(stroke);
0622:
0623: return StyleFactory.createRule(new Symbolizer[] { lineSym },
0624: label, label, "", null, filter, false, 0, 9E99);
0625: }
0626:
0627: /**
0628: * creates a <tt>Style</tt>. For each class/child contained in a avl file one <tt>Rule</tt>
0629: * will be created
0630: *
0631: * @param legend
0632: * @param filterCol
0633: * @return a <tt>Style</tt>.
0634: */
0635: private AbstractStyle createPolygonStyle(Map legend,
0636: String filterCol) throws Exception {
0637: String tmp = (String) legend.get("Symbols");
0638: Map block = blocks.get("SymList." + tmp);
0639: List classes = (List) legend.get("Class");
0640: List children = (List) block.get("Child");
0641: List<Rule> list = new ArrayList<Rule>(classes.size());
0642: for (int i = 0; i < classes.size(); i++) {
0643: String clNo = (String) classes.get(i);
0644: Map clss = blocks.get("LClass." + clNo);
0645: String childNo = (String) children.get(i);
0646: Map<String, Object> child = blocks.get("BShSym." + childNo);
0647: Rule rule = null;
0648: if (child == null) {
0649: // VShSym is a vector polygon fill
0650: child = blocks.get("VShSym." + childNo);
0651: rule = createPolygonVecRule(clss, child, filterCol);
0652: } else {
0653: rule = createPolygonBMPRule(clss, child, filterCol);
0654: }
0655: if (rule != null) {
0656: list.add(rule);
0657: }
0658: // TODO
0659: // write special method for vector polygon fill
0660: }
0661: Rule[] rules = list.toArray(new Rule[list.size()]);
0662: FeatureTypeStyle fts = StyleFactory
0663: .createFeatureTypeStyle(rules);
0664:
0665: String[] t = StringTools.toArray(fileRootName, "/", false);
0666: String name = "default:" + t[t.length - 1];
0667: return StyleFactory.createStyle(name, null, null, fts);
0668: }
0669:
0670: /**
0671: * creates a Style for a line symbol
0672: *
0673: * @param clss
0674: * @param child
0675: * @return a Style for a line symbol
0676: */
0677: private Rule createPolygonBMPRule(Map clss,
0678: Map<String, Object> child, String filterCol)
0679: throws Exception {
0680:
0681: if (clss.get("IsNoData") != null) {
0682: return null;
0683: }
0684:
0685: String label = (String) clss.get("Label");
0686: label = StringTools.validateString(label, "\"");
0687:
0688: Filter filter = null;
0689: if (filterCol != null) {
0690: filter = createFilter(clss, filterCol);
0691: }
0692: // get foreground color
0693: String clrIdx = (String) child.get("Color");
0694: Map<String, Object> color = blocks.get("TClr." + clrIdx);
0695: double opacity = 1f;
0696: if (color != null
0697: && "\"Transparent\"".equals(color.get("Name"))) {
0698: opacity = 0f;
0699: }
0700:
0701: Color fgColor = createColor(color);
0702: if (fgColor == null) {
0703: fgColor = Color.BLACK;
0704: }
0705: // get color of the outlining stroke
0706: clrIdx = (String) child.get("OutlineColor");
0707: color = blocks.get("TClr." + clrIdx);
0708: double outLOpacity = 1f;
0709: if (color != null
0710: && "\"Transparent\"".equals(color.get("Name"))) {
0711: outLOpacity = 0f;
0712: }
0713: Color outLColor = createColor(color);
0714: if (outLColor == null) {
0715: outLColor = Color.BLACK;
0716: }
0717: // get background color
0718: clrIdx = (String) child.get("BgColor");
0719: color = blocks.get("TClr." + clrIdx);
0720: double bgOpacity = 1f;
0721: if (color != null
0722: && "\"Transparent\"".equals(color.get("Name"))) {
0723: bgOpacity = 0f;
0724: }
0725: Color bgColor = createColor(color);
0726:
0727: // create fill pattern as an image that will be referenced as
0728: // external graphic
0729: String stippleIdx = (String) child.get("Stipple");
0730: String src = null;
0731: if (stippleIdx != null) {
0732: Map stipple = blocks.get("Stipple." + stippleIdx);
0733: src = createExternalGraphicFromStipple(stipple, label,
0734: fgColor, bgColor);
0735: }
0736:
0737: double width = Double.parseDouble((String) child
0738: .get("OutlineWidth")) + 1;
0739: Stroke stroke = StyleFactory.createStroke(outLColor, width,
0740: outLOpacity, null, "mitre", "butt");
0741: Fill fill = null;
0742: if (stippleIdx != null) {
0743: ExternalGraphic eg = StyleFactory.createExternalGraphic(
0744: "file:///" + src, "image/gif");
0745: Graphic graph = StyleFactory.createGraphic(eg, null,
0746: opacity, 10, 0);
0747: GraphicFill gf = StyleFactory.createGraphicFill(graph);
0748: fill = StyleFactory.createFill(fgColor, opacity, gf);
0749: } else {
0750: fill = StyleFactory.createFill(fgColor, opacity);
0751: }
0752: PolygonSymbolizer polySym = StyleFactory
0753: .createPolygonSymbolizer(stroke, fill);
0754: return StyleFactory.createRule(new Symbolizer[] { polySym },
0755: label, label, "", null, filter, false, 0, 9E99);
0756: }
0757:
0758: /**
0759: * creates a Style for a line symbol
0760: *
0761: * @param clss
0762: * @param child
0763: * @return a Style for a line symbol
0764: */
0765: private Rule createPolygonVecRule(Map clss,
0766: Map<String, Object> child, String filterCol)
0767: throws Exception {
0768:
0769: if (clss.get("IsNoData") != null) {
0770: return null;
0771: }
0772:
0773: String label = (String) clss.get("Label");
0774: label = StringTools.validateString(label, "\"");
0775:
0776: Filter filter = null;
0777: if (filterCol != null) {
0778: filter = createFilter(clss, filterCol);
0779: }
0780: // get foreground color
0781: String clrIdx = (String) child.get("Color");
0782: Map<String, Object> color = blocks.get("TClr." + clrIdx);
0783: double opacity = 1f;
0784: if (color != null
0785: && "\"Transparent\"".equals(color.get("Name"))) {
0786: opacity = 0f;
0787: }
0788: Color fgColor = createColor(color);
0789: if (fgColor == null) {
0790: fgColor = Color.BLACK;
0791: }
0792: // get color of the outlining stroke
0793: clrIdx = (String) child.get("OutlineColor");
0794: color = blocks.get("TClr." + clrIdx);
0795: double outLOpacity = 1f;
0796: if (color != null
0797: && "\"Transparent\"".equals(color.get("Name"))) {
0798: outLOpacity = 0f;
0799: }
0800: Color outLColor = createColor(color);
0801: if (outLColor == null) {
0802: outLColor = Color.BLACK;
0803: }
0804: // get background color
0805: clrIdx = (String) child.get("BgColor");
0806: color = blocks.get("TClr." + clrIdx);
0807: double bgOpacity = 1f;
0808: if (color != null
0809: && "\"Transparent\"".equals(color.get("Name"))) {
0810: bgOpacity = 0f;
0811: }
0812: Color bgColor = createColor(color);
0813:
0814: // create fill pattern as an image that will be referenced as
0815: // external graphic
0816: String stippleIdx = (String) child.get("Stipple");
0817: String src = null;
0818: if (stippleIdx != null) {
0819: Map stipple = blocks.get("Stipple." + stippleIdx);
0820: src = createExternalGraphicFromStipple(stipple, label,
0821: fgColor, bgColor);
0822: }
0823:
0824: double width = Double.parseDouble((String) child
0825: .get("OutlineWidth")) + 1;
0826: Stroke stroke = StyleFactory.createStroke(outLColor, width,
0827: outLOpacity, null, "mitre", "butt");
0828: Fill fill = null;
0829: if (stippleIdx != null) {
0830: ExternalGraphic eg = StyleFactory.createExternalGraphic(
0831: "file:///" + src, "image/gif");
0832: Graphic graph = StyleFactory.createGraphic(eg, null,
0833: opacity, 10, 0);
0834: GraphicFill gf = StyleFactory.createGraphicFill(graph);
0835: fill = StyleFactory.createFill(fgColor, opacity, gf);
0836: } else {
0837: fill = StyleFactory.createFill(fgColor, opacity);
0838: }
0839: PolygonSymbolizer polySym = StyleFactory
0840: .createPolygonSymbolizer(stroke, fill);
0841: return StyleFactory.createRule(new Symbolizer[] { polySym },
0842: label, label, "", null, filter, false, 0, 9E99);
0843: }
0844:
0845: /**
0846: * creates an image from a stipple and stores it as a gif image. The method returns the full
0847: * name of the stored image.
0848: *
0849: * @param stipple
0850: * @return an image from a stipple and stores it as a gif image. The method returns the full
0851: * name of the stored image.
0852: */
0853: private String createExternalGraphicFromStipple(Map stipple,
0854: String label, Color fg, Color bg) throws Exception {
0855:
0856: if (label != null) {
0857: label = label.replace(' ', '_');
0858: label = label.replace('.', '_');
0859: label = label.replace(';', '_');
0860: label = label.replace(',', '_');
0861: label = label.replace('-', '_');
0862: label = label.replace(':', '_');
0863: }
0864: String tmp = (String) stipple.get("Columns");
0865: int cols = Integer.parseInt(tmp);
0866: tmp = (String) stipple.get("Rows");
0867: int rows = Integer.parseInt(tmp);
0868:
0869: List bList = (List) stipple.get("Bits");
0870: StringBuffer bStr = new StringBuffer(1000);
0871: for (int i = 0; i < bList.size(); i++) {
0872: String[] t = StringTools.toArray(((String) bList.get(i))
0873: .trim(), " ", false);
0874: for (int j = 0; j < t.length; j++) {
0875: bStr.append(t[j]);
0876: }
0877: }
0878:
0879: char[] ch = bStr.toString().toCharArray();
0880:
0881: BufferedImage bi = createFillPattern(cols, rows, ch, fg, bg);
0882:
0883: final String format = "gif";
0884:
0885: String[] t = StringTools.toArray(fileRootName, "/", false);
0886: String base = t[t.length - 1];
0887: StringBuffer fileName = new StringBuffer();
0888: fileName.append(targetDir).append(base);
0889: if (label != null) {
0890: fileName.append("_").append(label).append(".").append(
0891: format);
0892: } else {
0893: fileName.append(".").append(format);
0894: }
0895:
0896: // FileOutputStream fos = new FileOutputStream( targetDir + base + '_' + label + "." +
0897: // format );
0898: FileOutputStream fos = new FileOutputStream(fileName.toString());
0899: ImageUtils.saveImage(bi, fos, format, 1.0f);
0900: // Encoders.encodeGif(fos,bi);
0901: fos.close();
0902:
0903: if (targetDir.startsWith("/")) {
0904: if (label != null) {
0905: return targetDir.substring(1, targetDir.length())
0906: + base + '_' + label + "." + format;
0907: } else {
0908: return targetDir.substring(1, targetDir.length())
0909: + base + "." + format;
0910: }
0911: } else {
0912: if (label != null) {
0913: return targetDir + base + '_' + label + "." + format;
0914: } else {
0915: return targetDir + base + "." + format;
0916: }
0917:
0918: }
0919:
0920: }
0921:
0922: /**
0923: * creates a <tt>BufferedImage</tt> using the stipple contained in the passed char array.
0924: *
0925: * @param cols
0926: * @param rows
0927: * @param ch
0928: * @return a <tt>BufferedImage</tt> using the stipple contained in the passed char array.
0929: */
0930: private BufferedImage createFillPattern(int cols, int rows,
0931: char[] ch, Color fg, Color bg) {
0932: BufferedImage bi = new BufferedImage(cols, rows,
0933: BufferedImage.TYPE_INT_ARGB);
0934: int cntChar = 0;
0935: byte[] bTmp = null;
0936: char chr = ' ';
0937: int hexCnt = 0;
0938: if (cols % 8 != 0) {
0939: hexCnt = (cols / 8 + 1) * 8;
0940: } else {
0941: hexCnt = cols;
0942: }
0943: for (int i = 0; i < rows; i++) {
0944: for (int j = 0; j < hexCnt; j++) {
0945: if (j % 4 == 0) {
0946: chr = ch[cntChar++];
0947: bTmp = getBits(chr);
0948: }
0949: if (j < cols) {
0950: if (bTmp[j % 4] == 0) {
0951: if (bg != null) {
0952: bi.setRGB(j, i, bg.getRGB());
0953: }
0954: } else {
0955: bi.setRGB(j, i, fg.getRGB());
0956: }
0957: }
0958: }
0959: }
0960: return bi;
0961: }
0962:
0963: private byte[] getBits(int ch) {
0964: switch (ch) {
0965: case '0':
0966: return new byte[] { 0, 0, 0, 0 };
0967: case '1':
0968: return new byte[] { 0, 0, 0, 1 };
0969: case '2':
0970: return new byte[] { 0, 0, 1, 0 };
0971: case '3':
0972: return new byte[] { 0, 0, 1, 1 };
0973: case '4':
0974: return new byte[] { 0, 1, 0, 0 };
0975: case '5':
0976: return new byte[] { 0, 1, 0, 1 };
0977: case '6':
0978: return new byte[] { 0, 1, 1, 0 };
0979: case '7':
0980: return new byte[] { 0, 1, 1, 1 };
0981: case '8':
0982: return new byte[] { 1, 0, 0, 0 };
0983: case '9':
0984: return new byte[] { 1, 0, 0, 1 };
0985: case 'a':
0986: return new byte[] { 1, 0, 1, 0 };
0987: case 'b':
0988: return new byte[] { 1, 0, 1, 1 };
0989: case 'c':
0990: return new byte[] { 1, 1, 0, 0 };
0991: case 'd':
0992: return new byte[] { 1, 1, 0, 1 };
0993: case 'e':
0994: return new byte[] { 1, 1, 1, 0 };
0995: case 'f':
0996: return new byte[] { 1, 1, 1, 1 };
0997: default:
0998: return new byte[] { 0, 0, 0, 0 };
0999: }
1000: }
1001:
1002: /**
1003: * @return creates a dasharray for constructing a stroke from the pattern entries of a avl xxxSym. block
1004: *
1005: * @param pl
1006: */
1007: private float[] createDashArray(List<String> pl) {
1008: int cnt = 0;
1009: for (int i = 0; i < pl.size(); i++) {
1010: if (Float.parseFloat(pl.get(i)) > 0) {
1011: cnt++;
1012: } else {
1013: break;
1014: }
1015: }
1016: float[] pattern = null;
1017: if (cnt > 0) {
1018: pattern = new float[cnt];
1019: for (int i = 0; i < pattern.length; i++) {
1020: pattern[i] = Float.parseFloat(pl.get(i));
1021: }
1022: }
1023: return pattern;
1024: }
1025:
1026: /**
1027: * creates a AWT color from a val color block
1028: *
1029: * @param color
1030: * @return a AWT color from a val color block
1031: */
1032: private Color createColor(Map<String, Object> color) {
1033: StringBuffer hex = new StringBuffer("0x");
1034: if (color != null
1035: && !"\"Transparent\"".equals(color.get("Name"))) {
1036: String red = (String) color.get("Red");
1037: if (red == null)
1038: red = "0x0000";
1039: int c = (int) ((Integer.decode(red).intValue() / 65535f) * 255);
1040: if (c < 15) {
1041: hex.append(0);
1042: }
1043: hex.append(Integer.toHexString(c));
1044: String green = (String) color.get("Green");
1045: if (green == null)
1046: green = "0x0000";
1047: c = (int) ((Integer.decode(green).intValue() / 65535f) * 255);
1048: if (c < 15) {
1049: hex.append(0);
1050: }
1051: hex.append(Integer.toHexString(c));
1052: String blue = (String) color.get("Blue");
1053: if (blue == null)
1054: blue = "0x0000";
1055: c = (int) ((Integer.decode(blue).intValue() / 65535f) * 255);
1056: if (c < 15) {
1057: hex.append(0);
1058: }
1059: hex.append(Integer.toHexString(c));
1060: } else {
1061: // hex.append("000000");
1062: return null;
1063: }
1064: return Color.decode(hex.toString());
1065: }
1066:
1067: private Filter createFilter(Map clss, String filterCol) {
1068:
1069: if (clss.get("Label") == null) {
1070: return null;
1071: }
1072: Filter filter = null;
1073:
1074: String maxN = (String) clss.get("MaxStr");
1075: String minN = (String) clss.get("MinStr");
1076: if (maxN != null && minN != null) {
1077: filter = createStringFilter(clss, filterCol);
1078: } else {
1079: filter = createNumberFilter(clss, filterCol);
1080: }
1081:
1082: return filter;
1083: }
1084:
1085: private Filter createStringFilter(Map clss, String filterCol) {
1086: Filter filter;
1087: Operation oper = null;
1088: String maxN = (String) clss.get("MaxStr");
1089: String minN = (String) clss.get("MinStr");
1090: maxN = maxN.substring(1, maxN.length() - 1);
1091: minN = minN.substring(1, minN.length() - 1);
1092: if (maxN.equals(minN)) {
1093: oper = new PropertyIsCOMPOperation(
1094: OperationDefines.PROPERTYISEQUALTO,
1095: new PropertyName(new QualifiedName(filterCol)),
1096: new Literal(minN));
1097: } else {
1098: ArrayList<Operation> list = new ArrayList<Operation>();
1099: Operation op = new PropertyIsCOMPOperation(
1100: OperationDefines.PROPERTYISLESSTHANOREQUALTO,
1101: new PropertyName(new QualifiedName(filterCol)),
1102: new Literal(maxN));
1103: list.add(op);
1104: op = new PropertyIsCOMPOperation(
1105: OperationDefines.PROPERTYISGREATERTHANOREQUALTO,
1106: new PropertyName(new QualifiedName(filterCol)),
1107: new Literal(minN));
1108: list.add(op);
1109:
1110: oper = new LogicalOperation(OperationDefines.AND, list);
1111: }
1112: filter = new ComplexFilter(oper);
1113: return filter;
1114: }
1115:
1116: private Filter createNumberFilter(Map clss, String filterCol) {
1117:
1118: String maxN = (String) clss.get("MaxNum");
1119: String minN = (String) clss.get("MinNum");
1120: if (maxN == null) {
1121: maxN = "9E99";
1122: }
1123: if (minN == null) {
1124: minN = "-9E99";
1125: }
1126: double t1 = Double.parseDouble(minN);
1127: double t2 = Double.parseDouble(maxN);
1128: Operation oper = null;
1129: if (t1 == t2) {
1130: // if t1 == t2 no range is defined and so an 'is equal to'
1131: // opertaion must be used
1132: if (((int) t1) == t1) {
1133: // if no significant fraction values are present
1134: // cast the value to int
1135: oper = new PropertyIsCOMPOperation(
1136: OperationDefines.PROPERTYISEQUALTO,
1137: new PropertyName(new QualifiedName(filterCol)),
1138: new Literal("" + ((int) t1)));
1139: } else {
1140: oper = new PropertyIsCOMPOperation(
1141: OperationDefines.PROPERTYISEQUALTO,
1142: new PropertyName(new QualifiedName(filterCol)),
1143: new Literal("" + t1));
1144: }
1145: } else {
1146: // if t1 != t2 range of valid values is defined and so an so two
1147: // operation (one for each border of the range) are used
1148: ArrayList<Operation> list = new ArrayList<Operation>();
1149: Operation op = new PropertyIsCOMPOperation(
1150: OperationDefines.PROPERTYISLESSTHANOREQUALTO,
1151: new PropertyName(new QualifiedName(filterCol)),
1152: new Literal(maxN));
1153: list.add(op);
1154: op = new PropertyIsCOMPOperation(
1155: OperationDefines.PROPERTYISGREATERTHANOREQUALTO,
1156: new PropertyName(new QualifiedName(filterCol)),
1157: new Literal(minN));
1158: list.add(op);
1159:
1160: oper = new LogicalOperation(OperationDefines.AND, list);
1161:
1162: }
1163:
1164: return new ComplexFilter(oper);
1165:
1166: }
1167:
1168: private static String[] getAVLFiles(String dir) {
1169: File file = new File(dir);
1170: return file.list(new DFileFilter());
1171:
1172: }
1173:
1174: private static void printHelp() {
1175:
1176: System.out
1177: .println("Converts ESRI *.avl files to OGC SLD documents. The current version of ");
1178: System.out
1179: .println("this tool isn't able to convert each and every construction that is ");
1180: System.out
1181: .println("possible with an *.avl file. But most of the common expressions will be mapped.");
1182: System.out
1183: .println("Supported are *.avl files for point, lines and polygons.");
1184: System.out.println("");
1185: System.out
1186: .println("-sourceFile -> full path to the *.avl file to be converted. ");
1187: System.out
1188: .println(" in the same directory a shapefile with the same name as the *.avl");
1189: System.out
1190: .println(" file must exist! (conditional, -sourceFile or -sourceDir must ");
1191: System.out.println(" be defined)");
1192: System.out
1193: .println("-sourceDir -> directory containing one or more *.avl files. for each existing");
1194: System.out
1195: .println(" *.avl file a shapefile with the same base name must exist. ");
1196: System.out
1197: .println(" (conditional, -sourceFile or -sourceDir must be defined)");
1198: System.out
1199: .println("-targetDir -> directory where the created SLD document(s) will be stored. (optional)");
1200: System.out.println("-h -> print this help");
1201: }
1202:
1203: /**
1204: *
1205: * @param args
1206: * @throws Exception
1207: */
1208: public static void main(String[] args) throws Exception {
1209:
1210: Map<String, String> map = new HashMap<String, String>();
1211:
1212: for (int i = 0; i < args.length; i += 2) {
1213: map.put(args[i], args[i + 1]);
1214: }
1215:
1216: if (map.get("-sourceFile") == null
1217: && map.get("-sourceDir") == null
1218: && map.get("-h") == null) {
1219: System.out
1220: .println("-sourceFile or -sourceDir must be defined!");
1221: System.out.println();
1222: printHelp();
1223: System.exit(1);
1224: }
1225:
1226: if (map.get("-h") != null) {
1227: printHelp();
1228: System.exit(0);
1229: }
1230:
1231: String targetDir = ".";
1232: String[] sourceFiles = null;
1233: if (map.get("-sourceFile") != null) {
1234: sourceFiles = new String[] { map.get("-sourceFile") };
1235: // set the default target directory to the sourceFile's directory
1236: targetDir = sourceFiles[0].substring(0, sourceFiles[0]
1237: .lastIndexOf("/"));
1238: }
1239:
1240: if (sourceFiles == null) {
1241: String sourceDir = map.get("-sourceDir");
1242: sourceFiles = getAVLFiles(sourceDir);
1243: for (int i = 0; i < sourceFiles.length; i++) {
1244: sourceFiles[i] = sourceDir + '/' + sourceFiles[i];
1245: }
1246: // set the default target directory to the source directory
1247: targetDir = sourceDir;
1248:
1249: }
1250:
1251: // String targetDir = ".";
1252: if (map.get("-targetDir") != null) {
1253: targetDir = map.get("-targetDir");
1254: }
1255:
1256: for (int i = 0; i < sourceFiles.length; i++) {
1257: System.out.println("processing: " + sourceFiles[i]);
1258: int pos = sourceFiles[i].lastIndexOf('.');
1259: String file = sourceFiles[i].substring(0, pos);
1260: AVL2SLD avl = new AVL2SLD(file, targetDir);
1261: avl.read();
1262: StyledLayerDescriptor sld = avl.getStyledLayerDescriptor();
1263: String[] t = StringTools.toArray(file, "/", false);
1264: FileWriter fos = new FileWriter(targetDir + '/'
1265: + t[t.length - 1] + ".xml");
1266: fos.write(((Marshallable) sld).exportAsXML());
1267: fos.close();
1268: }
1269: }
1270:
1271: /**
1272: *
1273: *
1274: * @version $Revision: 10466 $
1275: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
1276: */
1277: private static class DFileFilter implements FilenameFilter {
1278: /**
1279: * @param f
1280: * @return true if accepted
1281: */
1282: public boolean accept(File f, String name) {
1283: int pos = name.lastIndexOf(".");
1284: String ext = name.substring(pos + 1);
1285: return ext.toUpperCase().equals("AVL");
1286: }
1287: }
1288:
1289: }
|