Source Code Cross Referenced for KMLVectorTransformer.java in  » GIS » GeoServer » org » vfny » geoserver » wms » responses » map » kml » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoServer » org.vfny.geoserver.wms.responses.map.kml 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
0002:         * This code is licensed under the GPL 2.0 license, availible at the root
0003:         * application directory.
0004:         */
0005:        package org.vfny.geoserver.wms.responses.map.kml;
0006:
0007:        import com.vividsolutions.jts.geom.Coordinate;
0008:        import com.vividsolutions.jts.geom.Geometry;
0009:        import com.vividsolutions.jts.geom.GeometryCollection;
0010:        import com.vividsolutions.jts.geom.LineSegment;
0011:        import com.vividsolutions.jts.geom.LineString;
0012:        import com.vividsolutions.jts.geom.MultiLineString;
0013:        import com.vividsolutions.jts.geom.MultiPoint;
0014:        import com.vividsolutions.jts.geom.MultiPolygon;
0015:        import com.vividsolutions.jts.geom.Point;
0016:        import com.vividsolutions.jts.geom.Polygon;
0017:        import org.geoserver.ows.util.RequestUtils;
0018:        import org.geotools.feature.Feature;
0019:        import org.geotools.feature.FeatureCollection;
0020:        import org.geotools.feature.FeatureIterator;
0021:        import org.geotools.feature.FeatureType;
0022:        import org.geotools.feature.type.DateUtil;
0023:        import org.geotools.geometry.jts.JTS;
0024:        import org.geotools.map.MapLayer;
0025:        import org.geotools.referencing.CRS;
0026:        import org.geotools.referencing.crs.DefaultGeographicCRS;
0027:        import org.geotools.renderer.style.LineStyle2D;
0028:        import org.geotools.renderer.style.MarkStyle2D;
0029:        import org.geotools.renderer.style.PolygonStyle2D;
0030:        import org.geotools.renderer.style.SLDStyleFactory;
0031:        import org.geotools.renderer.style.Style2D;
0032:        import org.geotools.renderer.style.TextStyle2D;
0033:        import org.geotools.styling.ExternalGraphic;
0034:        import org.geotools.styling.FeatureTypeStyle;
0035:        import org.geotools.styling.LineSymbolizer;
0036:        import org.geotools.styling.Mark;
0037:        import org.geotools.styling.PointSymbolizer;
0038:        import org.geotools.styling.PolygonSymbolizer;
0039:        import org.geotools.styling.Rule;
0040:        import org.geotools.styling.SLD;
0041:        import org.geotools.styling.Style;
0042:        import org.geotools.styling.Symbolizer;
0043:        import org.geotools.styling.TextSymbolizer;
0044:        import org.geotools.util.Converters;
0045:        import org.geotools.util.NumberRange;
0046:        import org.geotools.xml.SimpleBinding;
0047:        import org.geotools.xml.transform.TransformerBase;
0048:        import org.geotools.xml.transform.Translator;
0049:        import org.geotools.xs.bindings.XSDateBinding;
0050:        import org.geotools.xs.bindings.XSDateTimeBinding;
0051:        import org.geotools.xs.bindings.XSTimeBinding;
0052:        import org.opengis.filter.Filter;
0053:        import org.opengis.filter.expression.Expression;
0054:        import org.opengis.geometry.MismatchedDimensionException;
0055:        import org.opengis.referencing.FactoryException;
0056:        import org.opengis.referencing.crs.CoordinateReferenceSystem;
0057:        import org.opengis.referencing.operation.MathTransform;
0058:        import org.opengis.referencing.operation.TransformException;
0059:        import org.vfny.geoserver.global.GeoServer;
0060:        import org.vfny.geoserver.wms.WMSMapContext;
0061:        import org.vfny.geoserver.wms.responses.featureInfo.FeatureTemplate;
0062:        import org.vfny.geoserver.wms.responses.featureInfo.FeatureTimeTemplate;
0063:        import org.vfny.geoserver.wms.responses.map.kml.KMLGeometryTransformer.KMLGeometryTranslator;
0064:        import org.xml.sax.ContentHandler;
0065:        import org.xml.sax.SAXException;
0066:
0067:        import java.awt.Color;
0068:        import java.io.File;
0069:        import java.io.IOException;
0070:        import java.net.MalformedURLException;
0071:        import java.net.URL;
0072:        import java.text.ParseException;
0073:        import java.text.SimpleDateFormat;
0074:        import java.util.ArrayList;
0075:        import java.util.Arrays;
0076:        import java.util.Calendar;
0077:        import java.util.Date;
0078:        import java.util.Iterator;
0079:        import java.util.List;
0080:        import java.util.logging.Level;
0081:        import java.util.logging.Logger;
0082:
0083:        /**
0084:         * Transforms a feature collection to a kml document consisting of nested
0085:         * "Style" and "Placemark" elements for each feature in the collection.
0086:         * A new transfomer must be instantianted for each feature collection, 
0087:         * the feature collection provided to the translator is supposed to be
0088:         * the one coming out of the MapLayer 
0089:         * <p>
0090:         * Usage:
0091:         * </p>
0092:         * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
0093:         *
0094:         */
0095:        public class KMLVectorTransformer extends KMLTransformerBase {
0096:            /**
0097:             * logger
0098:             */
0099:            static Logger LOGGER = org.geotools.util.logging.Logging
0100:                    .getLogger("org.geoserver.kml");
0101:
0102:            /**
0103:             * Tolerance used to compare doubles for equality
0104:             */
0105:            static final double TOLERANCE = 1e-6;
0106:
0107:            /**
0108:             * The map context
0109:             */
0110:            protected final WMSMapContext mapContext;
0111:
0112:            /**
0113:             * The map layer being transformed
0114:             */
0115:            protected final MapLayer mapLayer;
0116:
0117:            /**
0118:             * The scale denominator.
0119:             *
0120:             * TODO: calcuate a real value based on image size to bbox ratio, as image
0121:             * size has no meanining for KML yet this is a fudge.
0122:             */
0123:            double scaleDenominator = 1;
0124:            NumberRange scaleRange = new NumberRange(scaleDenominator,
0125:                    scaleDenominator);
0126:
0127:            /**
0128:             * used to create 2d style objects for features
0129:             */
0130:            SLDStyleFactory styleFactory = new SLDStyleFactory();
0131:
0132:            /**
0133:             * Feature template, cached for performance reasons
0134:             */
0135:            FeatureTemplate template = new FeatureTemplate();
0136:
0137:            /**
0138:             * list of formats which correspond to the default formats in which 
0139:             * freemarker outputs dates when a user calls the ?datetime(),?date(),?time()
0140:             * fuctions. 
0141:             */
0142:            static List/*<SimpleDateFormat>*/dtformats = new ArrayList();
0143:            static List/*<SimpleDateFormat>*/dformats = new ArrayList();
0144:            static List/*<SimpleDateFormat>*/tformats = new ArrayList();
0145:            static {
0146:
0147:                //add default freemarker ones first since they are likely to be used 
0148:                // first, the order of this list matters.
0149:
0150:                dtformats.add(FeatureTemplate.DATETIME_FORMAT);
0151:                addFormats(dtformats, "dd%MM%yy hh:mm:ss");
0152:                addFormats(dtformats, "MM%dd%yy hh:mm:ss");
0153:                //addFormats(formats,"yy%MM%dd hh:mm:ss" );
0154:                addFormats(dtformats, "dd%MMM%yy hh:mm:ss");
0155:                addFormats(dtformats, "MMM%dd%yy hh:mm:ss");
0156:                //addFormats(formats,"yy%MMM%dd hh:mm:ss" );
0157:
0158:                addFormats(dtformats, "dd%MM%yy hh:mm");
0159:                addFormats(dtformats, "MM%dd%yy hh:mm");
0160:                //addFormats(formats,"yy%MM%dd hh:mm" );
0161:                addFormats(dtformats, "dd%MMM%yy hh:mm");
0162:                addFormats(dtformats, "MMM%dd%yy hh:mm");
0163:                //addFormats(formats,"yy%MMM%dd hh:mm" );
0164:
0165:                dformats.add(FeatureTemplate.DATE_FORMAT);
0166:                addFormats(dformats, "dd%MM%yy");
0167:                addFormats(dformats, "MM%dd%yy");
0168:                //addFormats(formats,"yy%MM%dd" );
0169:                addFormats(dformats, "dd%MMM%yy");
0170:                addFormats(dformats, "MMM%dd%yy");
0171:                //addFormats(formats,"yy%MMM%dd" );
0172:
0173:                tformats.add(FeatureTemplate.TIME_FORMAT);
0174:            }
0175:
0176:            static void addFormats(List formats, String pattern) {
0177:
0178:                formats.add(new SimpleDateFormat(pattern.replaceAll("%", "-")));
0179:                formats.add(new SimpleDateFormat(pattern.replaceAll("%", "/")));
0180:                formats.add(new SimpleDateFormat(pattern.replaceAll("%", ".")));
0181:                formats.add(new SimpleDateFormat(pattern.replaceAll("%", " ")));
0182:                formats.add(new SimpleDateFormat(pattern.replaceAll("%", ",")));
0183:
0184:            }
0185:
0186:            public KMLVectorTransformer(WMSMapContext mapContext,
0187:                    MapLayer mapLayer) {
0188:                this .mapContext = mapContext;
0189:                this .mapLayer = mapLayer;
0190:
0191:                setNamespaceDeclarationEnabled(false);
0192:            }
0193:
0194:            /**
0195:             * Sets the scale denominator.
0196:             */
0197:            public void setScaleDenominator(double scaleDenominator) {
0198:                this .scaleDenominator = scaleDenominator;
0199:            }
0200:
0201:            public Translator createTranslator(ContentHandler handler) {
0202:                return new KMLTranslator(handler);
0203:            }
0204:
0205:            protected class KMLTranslator extends KMLTranslatorSupport {
0206:                /**
0207:                 * Geometry transformer
0208:                 */
0209:                Translator geometryTranslator;
0210:
0211:                public KMLTranslator(ContentHandler contentHandler) {
0212:                    super (contentHandler);
0213:
0214:                    KMLGeometryTransformer geometryTransformer = new KMLGeometryTransformer();
0215:                    //geometryTransformer.setUseDummyZ( true );
0216:                    geometryTransformer.setOmitXMLDeclaration(true);
0217:                    geometryTransformer.setNamespaceDeclarationEnabled(true);
0218:
0219:                    GeoServer config = mapContext.getRequest().getGeoServer();
0220:                    geometryTransformer.setNumDecimals(config.getNumDecimals());
0221:
0222:                    geometryTranslator = geometryTransformer
0223:                            .createTranslator(contentHandler);
0224:                }
0225:
0226:                public void encode(Object o) throws IllegalArgumentException {
0227:                    FeatureCollection features = (FeatureCollection) o;
0228:                    FeatureType featureType = features.getSchema();
0229:
0230:                    if (isStandAlone()) {
0231:                        start("kml");
0232:                    }
0233:
0234:                    //start the root document, name it the name of the layer
0235:                    start("Document");
0236:                    element("name", mapLayer.getTitle());
0237:
0238:                    //get the styles for hte layer
0239:                    FeatureTypeStyle[] featureTypeStyles = filterFeatureTypeStyles(
0240:                            mapLayer.getStyle(), featureType);
0241:
0242:                    // encode the schemas (kml 2.2)
0243:                    encodeSchemas(features);
0244:
0245:                    // encode the layers
0246:                    encode(features, featureTypeStyles);
0247:
0248:                    //encode the legend
0249:                    //encodeLegendScreenOverlay();
0250:                    end("Document");
0251:
0252:                    if (isStandAlone()) {
0253:                        end("kml");
0254:                    }
0255:                }
0256:
0257:                /**
0258:                 * Encodes the <Schema> element in kml 2.2
0259:                 * @param featureTypeStyles
0260:                 */
0261:                protected void encodeSchemas(FeatureCollection featureTypeStyles) {
0262:                    // the code is at the moment in KML3VectorTransformer
0263:                }
0264:
0265:                protected void encode(FeatureCollection features,
0266:                        FeatureTypeStyle[] styles) {
0267:                    //grab a feader and process
0268:                    FeatureIterator reader = features.features();
0269:
0270:                    try {
0271:                        while (reader.hasNext()) {
0272:                            Feature feature = (Feature) reader.next();
0273:
0274:                            try {
0275:                                encode(feature, styles);
0276:                            } catch (RuntimeException t) {
0277:                                // if the stream has been closed by the client don't keep on going forward, this is not
0278:                                // a feature local issue
0279:                                if (t.getCause() instanceof  SAXException)
0280:                                    throw t;
0281:                                else
0282:                                    LOGGER.log(Level.WARNING,
0283:                                            "Failure tranforming feature to KML:"
0284:                                                    + feature.getID(), t);
0285:                            }
0286:                        }
0287:                    } finally {
0288:                        //make sure we always close
0289:                        features.close(reader);
0290:                    }
0291:                }
0292:
0293:                protected void encode(Feature feature, FeatureTypeStyle[] styles) {
0294:                    //get the feature id
0295:                    String featureId = featureId(feature);
0296:
0297:                    //start the document
0298:                    //start("Document");
0299:
0300:                    //            element("name", featureId);
0301:                    //            element("title", mapLayer.getTitle());
0302:
0303:                    //encode the styles, keep track of any labels provided by the 
0304:                    // styles
0305:                    if (encodeStyle(feature, styles)) {
0306:                        encodePlacemark(feature, styles);
0307:                    }
0308:
0309:                    //end("Document");
0310:                }
0311:
0312:                /**
0313:                 * Encodes the provided set of rules as KML styles.
0314:                 */
0315:                protected boolean encodeStyle(Feature feature,
0316:                        FeatureTypeStyle[] styles) {
0317:
0318:                    //encode hte Line/Poly styles
0319:                    List symbolizerList = new ArrayList();
0320:                    for (int j = 0; j < styles.length; j++) {
0321:                        Rule[] rules = filterRules(styles[j], feature);
0322:
0323:                        for (int i = 0; i < rules.length; i++) {
0324:                            symbolizerList.addAll(Arrays.asList(rules[i]
0325:                                    .getSymbolizers()));
0326:                        }
0327:                    }
0328:
0329:                    if (!symbolizerList.isEmpty()) {
0330:                        //start the style
0331:                        start("Style", KMLUtils.attributes(new String[] { "id",
0332:                                "GeoServerStyle" + feature.getID() }));
0333:
0334:                        //encode the icon
0335:                        encodeIconStyle(feature, styles);
0336:
0337:                        Symbolizer[] symbolizers = (Symbolizer[]) symbolizerList
0338:                                .toArray(new Symbolizer[symbolizerList.size()]);
0339:                        encodeStyle(feature, symbolizers);
0340:
0341:                        //end the style
0342:                        end("Style");
0343:
0344:                        //return true to specify that the feature has a style
0345:                        return true;
0346:                    } else {
0347:                        //dont encode
0348:                        return false;
0349:                    }
0350:
0351:                }
0352:
0353:                /**
0354:                 * Encodes an IconStyle for a feature.
0355:                 */
0356:                protected void encodeIconStyle(Feature feature,
0357:                        FeatureTypeStyle[] styles) {
0358:                    //encode the style for the icon
0359:                    //start IconStyle
0360:                    start("IconStyle");
0361:
0362:                    //make transparent if they didn't ask for attributes
0363:                    if (!mapContext.getRequest().getKMattr()) {
0364:                        encodeColor("00ffffff");
0365:                    }
0366:
0367:                    //figure out if line or polygon
0368:                    boolean line = feature.getDefaultGeometry() != null
0369:                            && (feature.getDefaultGeometry() instanceof  LineString || feature
0370:                                    .getDefaultGeometry() instanceof  MultiLineString);
0371:                    boolean poly = feature.getDefaultGeometry() != null
0372:                            && (feature.getDefaultGeometry() instanceof  Polygon || feature
0373:                                    .getDefaultGeometry() instanceof  MultiPolygon);
0374:
0375:                    //if line or polygon scale the label
0376:                    if (line || poly) {
0377:                        element("scale", "0.4");
0378:                    }
0379:                    //start Icon
0380:                    start("Icon");
0381:
0382:                    if (line || poly) {
0383:                        String imageURL;
0384:                        try {
0385:                            URL requestURL = new URL(mapContext.getRequest()
0386:                                    .getBaseUrl());
0387:                            imageURL = requestURL.getProtocol() + "://"
0388:                                    + requestURL.getHost() + ":"
0389:                                    + requestURL.getPort();
0390:                            imageURL += "/geoserver/"
0391:                                    + (poly ? "icon-poly.png" : "icon-line.png");
0392:                        } catch (MalformedURLException mue) {
0393:                            imageURL = "http://maps.google.com/mapfiles/kml/pal3/icon61.png";
0394:                        }
0395:                        element("href", imageURL);
0396:                    } else {
0397:                        //do nothing, this is handled by encodePointStyle
0398:                    }
0399:
0400:                    end("Icon");
0401:
0402:                    //end IconStyle
0403:                    end("IconStyle");
0404:
0405:                }
0406:
0407:                /**
0408:                 * Encodes the provided set of symbolizers as KML styles.
0409:                 */
0410:                protected void encodeStyle(Feature feature,
0411:                        Symbolizer[] symbolizers) {
0412:                    // look for line symbolizers, if there is any, we should tell the
0413:                    // polygon style to have an outline
0414:                    boolean forceOutline = false;
0415:                    for (int i = 0; i < symbolizers.length; i++) {
0416:                        if (symbolizers[i] instanceof  LineSymbolizer) {
0417:                            forceOutline = true;
0418:                            break;
0419:                        }
0420:                    }
0421:
0422:                    for (int i = 0; i < symbolizers.length; i++) {
0423:                        Symbolizer symbolizer = symbolizers[i];
0424:                        LOGGER.finer(new StringBuffer("Applying symbolizer ")
0425:                                .append(symbolizer).toString());
0426:
0427:                        //create a 2-D style
0428:                        Style2D style = styleFactory.createStyle(feature,
0429:                                symbolizer, scaleRange);
0430:
0431:                        //split out each type of symbolizer
0432:                        if (symbolizer instanceof  TextSymbolizer) {
0433:                            encodeTextStyle((TextStyle2D) style,
0434:                                    (TextSymbolizer) symbolizer);
0435:                        }
0436:
0437:                        if (symbolizer instanceof  PolygonSymbolizer) {
0438:                            encodePolygonStyle((PolygonStyle2D) style,
0439:                                    (PolygonSymbolizer) symbolizer,
0440:                                    forceOutline);
0441:                        }
0442:
0443:                        if (symbolizer instanceof  LineSymbolizer) {
0444:                            encodeLineStyle((LineStyle2D) style,
0445:                                    (LineSymbolizer) symbolizer);
0446:                        }
0447:
0448:                        if (symbolizer instanceof  PointSymbolizer) {
0449:                            encodePointStyle(style,
0450:                                    (PointSymbolizer) symbolizer);
0451:                        }
0452:                    }
0453:                }
0454:
0455:                /**
0456:                 * Encodes a KML IconStyle + PolyStyle from a polygon style and symbolizer.
0457:                 */
0458:                protected void encodePolygonStyle(PolygonStyle2D style,
0459:                        PolygonSymbolizer symbolizer, boolean forceOutline) {
0460:                    //star the polygon style
0461:                    start("PolyStyle");
0462:
0463:                    //fill
0464:                    if (symbolizer.getFill() != null) {
0465:                        //get opacity
0466:                        double opacity = SLD.opacity(symbolizer.getFill());
0467:
0468:                        if (Double.isNaN(opacity)) {
0469:                            //none specified, default to full opacity
0470:                            opacity = 1.0;
0471:                        }
0472:
0473:                        encodeColor(SLD.color(symbolizer.getFill()), opacity);
0474:                    } else {
0475:                        //make it transparent
0476:                        encodeColor("00aaaaaa");
0477:                    }
0478:
0479:                    //outline
0480:                    if (symbolizer.getStroke() != null || forceOutline) {
0481:                        element("outline", "1");
0482:                    } else {
0483:                        element("outline", "0");
0484:                    }
0485:
0486:                    end("PolyStyle");
0487:
0488:                    //if stroke specified add line style as well
0489:                    if (symbolizer.getStroke() != null) {
0490:                        start("LineStyle");
0491:
0492:                        //opacity
0493:                        double opacity = SLD.opacity(symbolizer.getStroke());
0494:
0495:                        if (Double.isNaN(opacity)) {
0496:                            //none specified, default to full opacity
0497:                            opacity = 1.0;
0498:                        }
0499:
0500:                        encodeColor(colorToHex((Color) style.getContour(),
0501:                                opacity));
0502:
0503:                        //width
0504:                        int width = SLD.width(symbolizer.getStroke());
0505:
0506:                        if (width != SLD.NOTFOUND) {
0507:                            element("width", Integer.toString(width));
0508:                        }
0509:
0510:                        end("LineStyle");
0511:                    }
0512:                }
0513:
0514:                /**
0515:                 * Encodes a KML IconStyle + LineStyle from a polygon style and symbolizer.
0516:                 */
0517:                protected void encodeLineStyle(LineStyle2D style,
0518:                        LineSymbolizer symbolizer) {
0519:                    start("LineStyle");
0520:
0521:                    //stroke
0522:                    if (symbolizer.getStroke() != null) {
0523:                        //opacity
0524:                        double opacity = SLD.opacity(symbolizer.getStroke());
0525:
0526:                        if (Double.isNaN(opacity)) {
0527:                            //default to full opacity
0528:                            opacity = 1.0;
0529:                        }
0530:
0531:                        encodeColor((Color) style.getContour(), opacity);
0532:
0533:                        //width
0534:                        int width = SLD.width(symbolizer.getStroke());
0535:
0536:                        if (width != SLD.NOTFOUND) {
0537:                            element("width", Integer.toString(width));
0538:                        }
0539:                    } else {
0540:                        //default
0541:                        encodeColor("ffaaaaaa");
0542:                        element("width", "1");
0543:                    }
0544:
0545:                    end("LineStyle");
0546:                }
0547:
0548:                /**
0549:                 * Encodes a KML IconStyle from a point style and symbolizer.
0550:                 */
0551:                protected void encodePointStyle(Style2D style,
0552:                        PointSymbolizer symbolizer) {
0553:                    start("IconStyle");
0554:
0555:                    if (style instanceof  MarkStyle2D) {
0556:                        Mark mark = SLD.mark(symbolizer);
0557:
0558:                        if (mark != null) {
0559:                            double opacity = SLD.opacity(mark.getFill());
0560:
0561:                            if (Double.isNaN(opacity)) {
0562:                                //default to full opacity
0563:                                opacity = 1.0;
0564:                            }
0565:
0566:                            if (mark.getFill() != null) {
0567:                                final Color color = SLD.color(mark.getFill());
0568:                                encodeColor(color, opacity);
0569:                            }
0570:                        } else {
0571:                            //default
0572:                            encodeColor("ffaaaaaa");
0573:                        }
0574:                    } else {
0575:                        //default
0576:                        encodeColor("ffaaaaaa");
0577:                    }
0578:
0579:                    element("colorMode", "normal");
0580:
0581:                    // placemark icon
0582:                    String iconHref = null;
0583:
0584:                    //if the point symbolizer uses an external graphic use it
0585:                    if ((symbolizer.getGraphic() != null)
0586:                            && (symbolizer.getGraphic().getExternalGraphics() != null)
0587:                            && (symbolizer.getGraphic().getExternalGraphics().length > 0)) {
0588:                        ExternalGraphic graphic = symbolizer.getGraphic()
0589:                                .getExternalGraphics()[0];
0590:
0591:                        try {
0592:                            if ("file".equals(graphic.getLocation()
0593:                                    .getProtocol())) {
0594:                                //it is a local file, reference locally from "styles" directory
0595:                                File file = new File(graphic.getLocation()
0596:                                        .getFile());
0597:                                iconHref = RequestUtils.baseURL(mapContext
0598:                                        .getRequest().getHttpServletRequest())
0599:                                        + "styles/" + file.getName();
0600:                            } else if ("http".equals(graphic.getLocation()
0601:                                    .getProtocol())) {
0602:                                iconHref = graphic.getLocation().toString();
0603:                            } else {
0604:                                // TODO: should we check for http:// and use it directly?
0605:                                //other protocols?
0606:                            }
0607:
0608:                        } catch (Exception e) {
0609:                            LOGGER.log(Level.WARNING,
0610:                                    "Error processing external graphic:"
0611:                                            + graphic, e);
0612:                        }
0613:                    }
0614:
0615:                    if (iconHref == null) {
0616:                        iconHref = "http://maps.google.com/mapfiles/kml/pal4/icon25.png";
0617:                    }
0618:
0619:                    start("Icon");
0620:
0621:                    element("href", iconHref);
0622:                    end("Icon");
0623:
0624:                    end("IconStyle");
0625:                }
0626:
0627:                /**
0628:                 * Encodes a KML LabelStyle from a text style and symbolizer.
0629:                 */
0630:                protected void encodeTextStyle(TextStyle2D style,
0631:                        TextSymbolizer symbolizer) {
0632:                    start("LabelStyle");
0633:
0634:                    if (symbolizer.getFill() != null) {
0635:                        double opacity = SLD.opacity(symbolizer.getFill());
0636:
0637:                        if (Double.isNaN(opacity)) {
0638:                            //default to full opacity
0639:                            opacity = 1.0;
0640:                        }
0641:
0642:                        encodeColor(SLD.color(symbolizer.getFill()), opacity);
0643:                    } else {
0644:                        //default
0645:                        encodeColor("ffffffff");
0646:                    }
0647:
0648:                    end("LabelStyle");
0649:                }
0650:
0651:                /**
0652:                 * Encodes a KML Placemark from a feature and optional name.
0653:                 */
0654:                protected void encodePlacemark(Feature feature,
0655:                        FeatureTypeStyle[] styles) {
0656:                    Geometry geometry = featureGeometry(feature);
0657:                    Coordinate centroid = geometryCentroid(geometry);
0658:
0659:                    start("Placemark", KMLUtils.attributes(new String[] { "id",
0660:                            feature.getID() }));
0661:
0662:                    //encode name + description only if kmattr was specified
0663:                    if (mapContext.getRequest().getKMattr()) {
0664:                        //name
0665:                        try {
0666:                            encodePlacemarkName(feature, styles);
0667:                        } catch (Exception e) {
0668:                            String msg = "Error occured processing 'title' template.";
0669:                            LOGGER.log(Level.WARNING, msg, e);
0670:                        }
0671:
0672:                        //description
0673:                        try {
0674:                            encodePlacemarkDescription(feature);
0675:                        } catch (Exception e) {
0676:                            String msg = "Error occured processing 'description' template.";
0677:                            LOGGER.log(Level.WARNING, msg, e);
0678:                        }
0679:                    }
0680:
0681:                    //look at
0682:                    encodePlacemarkLookAt(centroid);
0683:
0684:                    //time
0685:                    try {
0686:                        encodePlacemarkTime(feature);
0687:                    } catch (Exception e) {
0688:                        String msg = "Error occured processing 'time' template: "
0689:                                + e.getMessage();
0690:                        LOGGER.log(Level.WARNING, msg);
0691:                        LOGGER.log(Level.FINE, "", e);
0692:                    }
0693:
0694:                    //style reference
0695:                    element("styleUrl", "#GeoServerStyle" + feature.getID());
0696:
0697:                    // encode extended data (kml 2.2)
0698:                    encodeExtendedData(feature);
0699:
0700:                    //geometry
0701:                    encodePlacemarkGeometry(geometry, centroid);
0702:
0703:                    end("Placemark");
0704:                }
0705:
0706:                /**
0707:                 * Encodes kml 2.2 extended data section
0708:                 * @param feature
0709:                 */
0710:                protected void encodeExtendedData(Feature feature) {
0711:                    // code at the moment is in KML3VectorTransfomer
0712:                }
0713:
0714:                /**
0715:                 * Encodes a KML Placemark name from a feature by processing a
0716:                 * template.
0717:                 */
0718:                protected void encodePlacemarkName(Feature feature,
0719:                        FeatureTypeStyle[] styles) throws IOException {
0720:
0721:                    //order to use when figuring out what the name / label of a 
0722:                    // placemark should be:
0723:                    // 1. the title template for features
0724:                    // 2. a text sym with a label from teh sld
0725:                    // 3. nothing ( do not use fid )
0726:
0727:                    String title = template.title(feature);
0728:
0729:                    //ensure not empty and != fid
0730:                    if (title == null || "".equals(title)
0731:                            || feature.getID().equals(title)) {
0732:                        //try sld
0733:                        StringBuffer label = new StringBuffer();
0734:                        for (int i = 0; i < styles.length; i++) {
0735:                            Rule[] rules = filterRules(styles[i], feature);
0736:                            for (int j = 0; j < rules.length; j++) {
0737:                                Symbolizer[] syms = rules[j].getSymbolizers();
0738:                                for (int k = 0; k < syms.length; k++) {
0739:                                    if (syms[k] instanceof  TextSymbolizer) {
0740:                                        Expression e = SLD
0741:                                                .textLabel((TextSymbolizer) syms[k]);
0742:                                        Object object = e.evaluate(feature);
0743:                                        String value = null;
0744:
0745:                                        if (object instanceof  String) {
0746:                                            value = (String) object;
0747:                                        } else {
0748:                                            if (object != null) {
0749:                                                value = object.toString();
0750:                                            }
0751:                                        }
0752:
0753:                                        if ((value != null)
0754:                                                && !"".equals(value.trim())) {
0755:                                            label.append(value);
0756:                                        }
0757:                                    }
0758:                                }
0759:                            }
0760:                        }
0761:
0762:                        if (label.length() > 0) {
0763:                            title = label.toString();
0764:                        } else {
0765:                            title = null;
0766:                        }
0767:
0768:                    }
0769:
0770:                    if (title != null) {
0771:                        start("name");
0772:                        cdata(title);
0773:                        end("name");
0774:                    }
0775:
0776:                }
0777:
0778:                /**
0779:                 * Encodes a KML Placemark description from a feature by processing a
0780:                 * template.
0781:                 */
0782:                protected void encodePlacemarkDescription(Feature feature)
0783:                        throws IOException {
0784:
0785:                    String description = template.description(feature);
0786:
0787:                    if (description != null) {
0788:                        start("description");
0789:                        cdata(description);
0790:                        end("description");
0791:                    }
0792:                }
0793:
0794:                /**
0795:                 * Encods a KML Placemark LookAt from a geometry + centroid.
0796:                 */
0797:                protected void encodePlacemarkLookAt(Coordinate centroid) {
0798:                    start("LookAt");
0799:
0800:                    element("longitude", Double.toString(centroid.x));
0801:                    element("latitude", Double.toString(centroid.y));
0802:                    element("range", "700");
0803:                    element("tilt", "10.0");
0804:                    element("heading", "10.0");
0805:
0806:                    end("LookAt");
0807:                }
0808:
0809:                /**
0810:                 * Encodes a KML TimePrimitive geometry from a feature.
0811:                 */
0812:                protected void encodePlacemarkTime(Feature feature)
0813:                        throws IOException {
0814:                    try {
0815:                        String[] time = new FeatureTimeTemplate(template)
0816:                                .execute(feature);
0817:                        if (time.length == 0) {
0818:                            return;
0819:                        }
0820:
0821:                        if (time.length == 1) {
0822:                            String datetime = encodeDateTime(time[0]);
0823:                            if (datetime != null) {
0824:                                //timestamp case
0825:                                start("TimeStamp");
0826:                                element("when", datetime);
0827:                                end("TimeStamp");
0828:                            }
0829:
0830:                        } else {
0831:                            //timespan case
0832:                            String begin = encodeDateTime(time[0]);
0833:                            String end = encodeDateTime(time[1]);
0834:
0835:                            if (!(begin == null && end == null)) {
0836:                                start("TimeSpan");
0837:                                if (begin != null) {
0838:                                    element("begin", begin);
0839:                                }
0840:                                if (end != null) {
0841:                                    element("end", end);
0842:                                }
0843:                                end("TimeSpan");
0844:                            }
0845:                        }
0846:                    } catch (Exception e) {
0847:                        throw (IOException) new IOException().initCause(e);
0848:                    }
0849:                }
0850:
0851:                /**
0852:                 * Encodes a date as an xs:dateTime.
0853:                 */
0854:                protected String encodeDateTime(String date) throws Exception {
0855:
0856:                    //first try as date time
0857:                    Date d = parseDate(dtformats, date);
0858:                    if (d == null) {
0859:                        //then try as date
0860:                        d = parseDate(dformats, date);
0861:                    }
0862:                    if (d == null) {
0863:                        //try as time
0864:                        d = parseDate(tformats, date);
0865:                    }
0866:
0867:                    if (d == null) {
0868:                        //last ditch effort, try to parse as xml dates
0869:                        try {
0870:                            //try as xml date time
0871:                            d = DateUtil.deserializeDateTime(date);
0872:                        } catch (Exception e1) {
0873:                            try {
0874:                                //try as xml date
0875:                                d = DateUtil.deserializeDate(date);
0876:                            } catch (Exception e2) {
0877:                            }
0878:                        }
0879:                    }
0880:
0881:                    if (d != null) {
0882:                        Calendar c = Calendar.getInstance();
0883:                        c.setTime(d);
0884:                        return new XSDateTimeBinding().encode(c, null);
0885:                    }
0886:
0887:                    LOGGER.warning("Could not parse date: " + date);
0888:                    return null;
0889:                }
0890:
0891:                /**
0892:                 * Parses a date as a string into a well-known format.
0893:                 */
0894:                protected Date parseDate(List formats, String date) {
0895:                    for (Iterator f = formats.iterator(); f.hasNext();) {
0896:                        SimpleDateFormat format = (SimpleDateFormat) f.next();
0897:                        Date d = null;
0898:                        try {
0899:                            d = format.parse(date);
0900:                        } catch (ParseException e) {
0901:                        }
0902:
0903:                        if (d != null) {
0904:                            return d;
0905:                        }
0906:                    }
0907:
0908:                    return null;
0909:                }
0910:
0911:                /**
0912:                 * Encodes a KML Placemark geometry from a geometry + centroid.
0913:                 */
0914:                protected void encodePlacemarkGeometry(Geometry geometry,
0915:                        Coordinate centroid) {
0916:                    //if point, just encode a single point, otherwise encode the geometry
0917:                    // + centroid
0918:                    if (geometry instanceof  Point
0919:                            || (geometry instanceof  MultiPoint)
0920:                            && ((MultiPoint) geometry).getNumPoints() == 1) {
0921:                        encodeGeometry(geometry);
0922:                    } else {
0923:                        start("MultiGeometry");
0924:
0925:                        //the centroid
0926:                        start("Point");
0927:
0928:                        if (!Double.isNaN(centroid.z)) {
0929:                            element("coordinates", centroid.x + ","
0930:                                    + centroid.y + "," + centroid.z);
0931:                        } else {
0932:                            element("coordinates", centroid.x + ","
0933:                                    + centroid.y);
0934:                        }
0935:
0936:                        end("Point");
0937:
0938:                        //the actual geometry
0939:                        encodeGeometry(geometry);
0940:
0941:                        end("MultiGeometry");
0942:                    }
0943:
0944:                }
0945:
0946:                /**
0947:                 * Encodes a KML geometry.
0948:                 */
0949:                protected void encodeGeometry(Geometry geometry) {
0950:                    if (geometry instanceof  GeometryCollection) {
0951:                        //unwrap the collection
0952:                        GeometryCollection collection = (GeometryCollection) geometry;
0953:
0954:                        for (int i = 0; i < collection.getNumGeometries(); i++) {
0955:                            encodeGeometry(collection.getGeometryN(i));
0956:                        }
0957:                    } else {
0958:                        geometryTranslator.encode(geometry);
0959:                    }
0960:                }
0961:
0962:                /**
0963:                 * Encodes a color element from its color + opacity representation.
0964:                 *
0965:                 * @param color The color to encode.
0966:                 * @param opacity The opacity ( alpha ) of the color.
0967:                 */
0968:                void encodeColor(Color color, double opacity) {
0969:                    encodeColor(colorToHex(color, opacity));
0970:                }
0971:
0972:                /**
0973:                 * Encodes a color element from its hex representation.
0974:                 *
0975:                 * @param hex The hex value ( with alpha ) of the color.
0976:                 *
0977:                 */
0978:                void encodeColor(String hex) {
0979:                    element("color", hex);
0980:                }
0981:
0982:                /**
0983:                 * Checks if a rule can be triggered at the current scale level
0984:                 * 
0985:                 * @param r
0986:                 *            The rule
0987:                 * @return true if the scale is compatible with the rule settings
0988:                 */
0989:                boolean isWithInScale(Rule r) {
0990:                    return ((r.getMinScaleDenominator() - TOLERANCE) <= scaleDenominator)
0991:                            && ((r.getMaxScaleDenominator() + TOLERANCE) > scaleDenominator);
0992:                }
0993:
0994:                /**
0995:                 * Returns the id of the feature removing special characters like
0996:                 * '&','>','<','%'.
0997:                 */
0998:                String featureId(Feature feature) {
0999:                    String id = feature.getID();
1000:                    id = id.replaceAll("&", "");
1001:                    id = id.replaceAll(">", "");
1002:                    id = id.replaceAll("<", "");
1003:                    id = id.replaceAll("%", "");
1004:
1005:                    return id;
1006:                }
1007:
1008:                /**
1009:                 * Rreturns the geometry for the feature reprojecting if necessary.
1010:                 */
1011:                Geometry featureGeometry(Feature f) {
1012:                    // get the geometry
1013:                    Geometry geom = f.getDefaultGeometry();
1014:
1015:                    //rprojection done in KMLTransformer
1016:                    //            if (!CRS.equalsIgnoreMetadata(sourceCrs, mapContext.getCoordinateReferenceSystem())) {
1017:                    //                try {
1018:                    //                    MathTransform transform = CRS.findMathTransform(sourceCrs,
1019:                    //                            mapContext.getCoordinateReferenceSystem(), true);
1020:                    //                    geom = JTS.transform(geom, transform);
1021:                    //                } catch (MismatchedDimensionException e) {
1022:                    //                    LOGGER.severe(e.getLocalizedMessage());
1023:                    //                } catch (TransformException e) {
1024:                    //                    LOGGER.severe(e.getLocalizedMessage());
1025:                    //                } catch (FactoryException e) {
1026:                    //                    LOGGER.severe(e.getLocalizedMessage());
1027:                    //                }
1028:                    //            }
1029:
1030:                    return geom;
1031:                }
1032:
1033:                /**
1034:                 * Returns the centroid of the geometry, handling  a geometry collection.
1035:                 * <p>
1036:                 * In the case of a collection a multi point containing the centroid of
1037:                 * each geometry in the collection is calculated. The first point in
1038:                 * the multi point is returned as the cetnroid.
1039:                 * </p>
1040:                 */
1041:                Coordinate geometryCentroid(Geometry g) {
1042:                    //TODO: should the collecftion case return the centroid of hte 
1043:                    // multi point?
1044:                    if (g instanceof  GeometryCollection) {
1045:                        GeometryCollection gc = (GeometryCollection) g;
1046:
1047:                        //check for case of single geometry
1048:                        if (gc.getNumGeometries() == 1) {
1049:                            g = gc.getGeometryN(0);
1050:                        } else {
1051:                            Coordinate[] pts = new Coordinate[gc
1052:                                    .getNumGeometries()];
1053:
1054:                            for (int t = 0; t < gc.getNumGeometries(); t++) {
1055:                                pts[t] = gc.getGeometryN(t).getCentroid()
1056:                                        .getCoordinate();
1057:                            }
1058:
1059:                            return g.getFactory().createMultiPoint(pts)
1060:                                    .getCoordinates()[0];
1061:                        }
1062:                    }
1063:
1064:                    if (g instanceof  Point) {
1065:                        //thats easy
1066:                        return g.getCoordinate();
1067:                    } else if (g instanceof  LineString) {
1068:                        //make sure the point we return is actually on the line
1069:                        double tol = 1E-6;
1070:                        double mid = g.getLength() / 2d;
1071:
1072:                        Coordinate[] coords = g.getCoordinates();
1073:
1074:                        //walk along the linestring until we get to a point where we 
1075:                        // have two coordinates that straddle the midpoint
1076:                        double len = 0d;
1077:                        for (int i = 1; i < coords.length; i++) {
1078:                            LineSegment line = new LineSegment(coords[i - 1],
1079:                                    coords[i]);
1080:                            len += line.getLength();
1081:
1082:                            if (Math.abs(len - mid) < tol) {
1083:                                //close enough
1084:                                return line.getCoordinate(1);
1085:                            }
1086:
1087:                            if (len > mid) {
1088:                                //we have gone past midpoint
1089:                                return line.pointAlong(1 - ((len - mid) / line
1090:                                        .getLength()));
1091:                            }
1092:                        }
1093:
1094:                        //should never get there
1095:                        return g.getCentroid().getCoordinate();
1096:                    } else {
1097:                        //return the actual centroid
1098:                        return g.getCentroid().getCoordinate();
1099:                    }
1100:                }
1101:
1102:                /**
1103:                 * Utility method to convert an int into hex, padded to two characters.
1104:                 * handy for generating colour strings.
1105:                 *
1106:                 * @param i Int to convert
1107:                 * @return String a two character hex representation of i
1108:                 * NOTE: this is a utility method and should be put somewhere more useful.
1109:                 */
1110:                String intToHex(int i) {
1111:                    String prelim = Integer.toHexString(i);
1112:
1113:                    if (prelim.length() < 2) {
1114:                        prelim = "0" + prelim;
1115:                    }
1116:
1117:                    return prelim;
1118:                }
1119:
1120:                /**
1121:                 * Utility method to convert a Color and opacity (0,1.0) into a KML
1122:                 * color ref.
1123:                 *
1124:                 * @param c The color to convert.
1125:                 * @param opacity Opacity / alpha, double from 0 to 1.0.
1126:                 *
1127:                 * @return A String of the form "#AABBGGRR".
1128:                 */
1129:                String colorToHex(Color c, double opacity) {
1130:                    return new StringBuffer().append(
1131:                            intToHex(new Float(255 * opacity).intValue()))
1132:                            .append(intToHex(c.getBlue())).append(
1133:                                    intToHex(c.getGreen())).append(
1134:                                    intToHex(c.getRed())).toString();
1135:                }
1136:
1137:                /**
1138:                 * Filters the feature type styles of <code>style</code> returning only
1139:                 * those that apply to <code>featureType</code>
1140:                 * <p>
1141:                 * This methods returns feature types for which
1142:                 * <code>featureTypeStyle.getFeatureTypeName()</code> matches the name
1143:                 * of the feature type of <code>featureType</code>, or matches the name of
1144:                 * any parent type of the feature type of <code>featureType</code>. This
1145:                 * method returns an empty array in the case of which no rules match.
1146:                 * </p>
1147:                 * @param style The style containing the feature type styles.
1148:                 * @param featureType The feature type being filtered against.
1149:                 *
1150:                 */
1151:                protected FeatureTypeStyle[] filterFeatureTypeStyles(
1152:                        Style style, FeatureType featureType) {
1153:                    FeatureTypeStyle[] featureTypeStyles = style
1154:                            .getFeatureTypeStyles();
1155:
1156:                    if ((featureTypeStyles == null)
1157:                            || (featureTypeStyles.length == 0)) {
1158:                        return new FeatureTypeStyle[0];
1159:                    }
1160:
1161:                    ArrayList filtered = new ArrayList(featureTypeStyles.length);
1162:
1163:                    for (int i = 0; i < featureTypeStyles.length; i++) {
1164:                        FeatureTypeStyle featureTypeStyle = featureTypeStyles[i];
1165:                        String featureTypeName = featureTypeStyle
1166:                                .getFeatureTypeName();
1167:
1168:                        //does this style have any rules
1169:                        if (featureTypeStyle.getRules() == null
1170:                                || featureTypeStyle.getRules().length == 0) {
1171:                            continue;
1172:                        }
1173:
1174:                        //does this style apply to the feature collection
1175:                        if (featureType.getTypeName().equalsIgnoreCase(
1176:                                featureTypeName)
1177:                                || featureType.isDescendedFrom(null,
1178:                                        featureTypeName)) {
1179:                            filtered.add(featureTypeStyle);
1180:                        }
1181:                    }
1182:
1183:                    return (FeatureTypeStyle[]) filtered
1184:                            .toArray(new FeatureTypeStyle[filtered.size()]);
1185:                }
1186:
1187:                /**
1188:                 * Filters the rules of <code>featureTypeStyle</code> returnting only
1189:                 * those that apply to <code>feature</code>.
1190:                 * <p>
1191:                 * This method returns rules for which:
1192:                 * <ol>
1193:                 *  <li><code>rule.getFilter()</code> matches <code>feature</code>, or:
1194:                 *  <li>the rule defines an "ElseFilter", and the feature matches no
1195:                 *  other rules.
1196:                 * </ol>
1197:                 * This method returns an empty array in the case of which no rules
1198:                 * match.
1199:                 * </p>
1200:                 * @param featureTypeStyle The feature type style containing the rules.
1201:                 * @param feature The feature being filtered against.
1202:                 *
1203:                 */
1204:                Rule[] filterRules(FeatureTypeStyle featureTypeStyle,
1205:                        Feature feature) {
1206:                    Rule[] rules = featureTypeStyle.getRules();
1207:
1208:                    if ((rules == null) || (rules.length == 0)) {
1209:                        return new Rule[0];
1210:                    }
1211:
1212:                    ArrayList filtered = new ArrayList(rules.length);
1213:
1214:                    //process the rules, keep track of the need to apply an else filters
1215:                    boolean match = false;
1216:                    boolean hasElseFilter = false;
1217:
1218:                    for (int i = 0; i < rules.length; i++) {
1219:                        Rule rule = rules[i];
1220:                        LOGGER.finer(new StringBuffer("Applying rule: ")
1221:                                .append(rule.toString()).toString());
1222:
1223:                        //does this rule have an else filter
1224:                        if (rule.hasElseFilter()) {
1225:                            hasElseFilter = true;
1226:
1227:                            continue;
1228:                        }
1229:
1230:                        //is this rule within scale?
1231:                        if (!isWithInScale(rule)) {
1232:                            continue;
1233:                        }
1234:
1235:                        //does this rule have a filter which applies to the feature
1236:                        Filter filter = rule.getFilter();
1237:
1238:                        if ((filter == null) || filter.evaluate(feature)) {
1239:                            match = true;
1240:
1241:                            filtered.add(rule);
1242:                        }
1243:                    }
1244:
1245:                    //if no rules mached the feautre, re-run through the rules applying
1246:                    // any else filters
1247:                    if (!match && hasElseFilter) {
1248:                        //loop through again and apply all the else rules
1249:                        for (int i = 0; i < rules.length; i++) {
1250:                            Rule rule = rules[i];
1251:
1252:                            //is this rule within scale?
1253:                            if (!isWithInScale(rule)) {
1254:                                continue;
1255:                            }
1256:
1257:                            if (rule.hasElseFilter()) {
1258:                                filtered.add(rule);
1259:                            }
1260:                        }
1261:                    }
1262:
1263:                    return (Rule[]) filtered.toArray(new Rule[filtered.size()]);
1264:                }
1265:            }
1266:        }
w__ww.___j___a__va_2_s.c__o__m___ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.