Source Code Cross Referenced for Formatter.java in  » GIS » GeoTools-2.4.1 » org » geotools » referencing » wkt » 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 » GeoTools 2.4.1 » org.geotools.referencing.wkt 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *   
005:         *   (C) 2004-2006, Geotools Project Managment Committee (PMC)
006:         *   (C) 2004, Institut de Recherche pour le Développement
007:         *
008:         *    This library is free software; you can redistribute it and/or
009:         *    modify it under the terms of the GNU Lesser General Public
010:         *    License as published by the Free Software Foundation; either
011:         *    version 2.1 of the License, or (at your option) any later version.
012:         *
013:         *    This library is distributed in the hope that it will be useful,
014:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
015:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
016:         *    Lesser General Public License for more details.
017:         *
018:         *    This package contains documentation from OpenGIS specifications.
019:         *    OpenGIS consortium's work is fully acknowledged here.
020:         */
021:        package org.geotools.referencing.wkt;
022:
023:        // J2SE dependencies and extensions
024:        import java.lang.reflect.Array;
025:        import java.text.FieldPosition;
026:        import java.text.NumberFormat;
027:        import java.util.Collection;
028:        import java.util.Iterator;
029:        import java.util.Locale;
030:        import javax.units.NonSI;
031:        import javax.units.SI;
032:        import javax.units.Unit;
033:        import javax.units.UnitFormat;
034:
035:        // OpenGIS dependencies
036:        import org.opengis.metadata.Identifier;
037:        import org.opengis.metadata.citation.Citation;
038:        import org.opengis.parameter.GeneralParameterValue;
039:        import org.opengis.parameter.ParameterDescriptor;
040:        import org.opengis.parameter.ParameterValue;
041:        import org.opengis.parameter.ParameterValueGroup;
042:        import org.opengis.referencing.IdentifiedObject;
043:        import org.opengis.referencing.datum.Datum;
044:        import org.opengis.referencing.cs.CoordinateSystemAxis;
045:        import org.opengis.referencing.operation.MathTransform;
046:        import org.opengis.referencing.operation.OperationMethod;
047:        import org.opengis.util.CodeList;
048:        import org.opengis.util.GenericName;
049:        import org.opengis.util.InternationalString;
050:
051:        // Geotools dependencies
052:        import org.geotools.metadata.iso.citation.Citations;
053:        import org.geotools.resources.Arguments;
054:        import org.geotools.resources.Utilities;
055:        import org.geotools.resources.X364;
056:        import org.geotools.resources.XMath;
057:        import org.geotools.resources.i18n.Errors;
058:        import org.geotools.resources.i18n.ErrorKeys;
059:
060:        /**
061:         * Format {@link Formattable} objects as
062:         * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
063:         * Known Text</cite> (WKT)</A>.
064:         *
065:         * A formatter is constructed with a specified set of symbols.
066:         * The {@linkplain Locale locale} associated with the symbols is used for querying
067:         * {@linkplain org.opengis.metadata.citation.Citation#getTitle authority titles}.
068:         *
069:         * @since 2.0
070:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/wkt/Formatter.java $
071:         * @version $Id: Formatter.java 25477 2007-05-10 13:01:00Z desruisseaux $
072:         * @author Martin Desruisseaux
073:         *
074:         * @see <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html">Well Know Text specification</A>
075:         * @see <A HREF="http://gdal.velocet.ca/~warmerda/wktproblems.html">OGC WKT Coordinate System Issues</A>
076:         */
077:        public class Formatter {
078:            /**
079:             * Do not format an {@code "AUTHORITY"} element for instances of those classes.
080:             *
081:             * @see #authorityAllowed
082:             */
083:            private static final Class[] AUTHORITY_EXCLUDE = { CoordinateSystemAxis.class };
084:
085:            /**
086:             * ANSI X3.64 codes for syntax coloring. Used only if syntax coloring
087:             * has been explicitly enabled.
088:             */
089:            private static final String NUMBER_COLOR = X364.YELLOW, // Floating point numbers only, not integers.
090:                    INTEGER_COLOR = X364.YELLOW,
091:                    UNIT_COLOR = X364.YELLOW,
092:                    AXIS_COLOR = X364.CYAN,
093:                    CODELIST_COLOR = X364.CYAN,
094:                    PARAMETER_COLOR = X364.GREEN,
095:                    METHOD_COLOR = X364.GREEN,
096:                    DATUM_COLOR = X364.GREEN,
097:                    ERROR_COLOR = X364.BACKGROUND_RED;
098:
099:            /**
100:             * The symbols to use for this formatter.
101:             */
102:            private final Symbols symbols;
103:
104:            /**
105:             * The preferred authority for object or parameter names.
106:             *
107:             * @see AbstractParser#getAuthority
108:             * @see AbstractParser#setAuthority
109:             */
110:            Citation authority = Citations.OGC;
111:
112:            /**
113:             * Whatever we allow syntax coloring on ANSI X3.64 compatible terminal.
114:             *
115:             * @see AbstractParser#isColorEnabled
116:             * @see AbstractParser#setColorEnabled
117:             */
118:            boolean colorEnabled = false;
119:
120:            /**
121:             * The unit for formatting measures, or {@code null} for the "natural" unit of each WKT
122:             * element. This value is set for example by "GEOGCS", which force its enclosing "PRIMEM" to
123:             * take the same units than itself.
124:             */
125:            private Unit linearUnit, angularUnit;
126:
127:            /**
128:             * The object to use for formatting numbers.
129:             */
130:            private final NumberFormat numberFormat;
131:
132:            /**
133:             * The object to use for formatting units.
134:             */
135:            private final UnitFormat unitFormat = UnitFormat.getAsciiInstance();
136:
137:            /**
138:             * Dummy field position.
139:             */
140:            private final FieldPosition dummy = new FieldPosition(0);
141:
142:            /**
143:             * The buffer in which to format. Consider this field as private final; the only
144:             * method to set the buffer to a new value is {@link AbstractParser#format}.
145:             */
146:            StringBuffer buffer;
147:
148:            /**
149:             * The starting point in the buffer. Always 0, except when used by
150:             * {@link AbstractParser#format}.
151:             */
152:            int bufferBase;
153:
154:            /**
155:             * The amount of space to use in indentation, or 0 if indentation is disabled.
156:             */
157:            final int indentation;
158:
159:            /**
160:             * The amount of space to write on the left side of each line. This amount is increased
161:             * by {@code indentation} every time a {@link Formattable} object is appended in a
162:             * new indentation level.
163:             */
164:            private int margin;
165:
166:            /**
167:             * {@code true} if a new line were requested during the execution
168:             * of {@link #append(Formattable)}. This is used to determine if
169:             * {@code UNIT} and {@code AUTHORITY} elements should appears
170:             * on a new line too.
171:             */
172:            private boolean lineChanged;
173:
174:            /**
175:             * {@code true} if the WKT is invalid. Similar to {@link #unformattable}, except that
176:             * this field is reset to {@code false} after the invalid part has been processed by
177:             * {@link #append(Formattable)}. This field is for internal use only.
178:             */
179:            private boolean invalidWKT;
180:
181:            /**
182:             * Non-null if the WKT is invalid. If non-null, then this field contains the interface class
183:             * of the problematic part (e.g. {@link org.opengis.referencing.crs.EngineeringCRS}).
184:             */
185:            private Class/*<?>*/unformattable;
186:
187:            /**
188:             * Warning that may be produced during WKT formatting, or {@code null} if none.
189:             */
190:            String warning;
191:
192:            /**
193:             * Creates a new instance of the formatter with the default symbols.
194:             */
195:            public Formatter() {
196:                this (Symbols.DEFAULT, 0);
197:            }
198:
199:            /**
200:             * Creates a new instance of the formatter. The whole WKT will be formatted
201:             * on a single line.
202:             *
203:             * @param symbols The symbols.
204:             */
205:            public Formatter(final Symbols symbols) {
206:                this (symbols, 0);
207:            }
208:
209:            /**
210:             * Creates a new instance of the formatter with the specified indentation width.
211:             * The WKT will be formatted on many lines, and the indentation width will have
212:             * the value specified to this constructor. If the specified indentation is 0,
213:             * then the whole WKT will be formatted on a single line.
214:             *
215:             * @param symbols The symbols.
216:             * @param indentation The amount of spaces to use in indentation. Typical values are 2 or 4.
217:             */
218:            public Formatter(final Symbols symbols, final int indentation) {
219:                this .symbols = symbols;
220:                this .indentation = indentation;
221:                if (symbols == null) {
222:                    throw new IllegalArgumentException(Errors.format(
223:                            ErrorKeys.NULL_ARGUMENT_$1, "symbols"));
224:                }
225:                if (indentation < 0) {
226:                    throw new IllegalArgumentException(Errors.format(
227:                            ErrorKeys.ILLEGAL_ARGUMENT_$2, "indentation",
228:                            new Integer(indentation)));
229:                }
230:                numberFormat = (NumberFormat) symbols.numberFormat.clone();
231:                buffer = new StringBuffer();
232:            }
233:
234:            /**
235:             * Constructor for private use by {@link AbstractParser#format} only.
236:             * This constructor help to share some objects with {@link AbstractParser}.
237:             */
238:            Formatter(final Symbols symbols, final NumberFormat numberFormat) {
239:                this .symbols = symbols;
240:                indentation = Formattable.getIndentation();
241:                this .numberFormat = numberFormat; // No clone needed.
242:                // Do not set the buffer. It will be set by AbstractParser.format.
243:            }
244:
245:            /**
246:             * Set the colors using the specified ANSI escape. The color is ignored
247:             * unless syntax coloring has been explicitly enabled. The {@code color}
248:             * should be a constant from {@link X364}.
249:             */
250:            private void setColor(final String color) {
251:                if (colorEnabled) {
252:                    buffer.append(color);
253:                }
254:            }
255:
256:            /**
257:             * Reset the colors to the default. This method do nothing
258:             * unless syntax coloring has been explicitly enabled.
259:             */
260:            private void resetColor() {
261:                if (colorEnabled) {
262:                    buffer.append(X364.DEFAULT);
263:                }
264:            }
265:
266:            /**
267:             * Returns the color to uses for the name of the specified object.
268:             */
269:            private static String getNameColor(final IdentifiedObject object) {
270:                if (object instanceof  Datum) {
271:                    return DATUM_COLOR;
272:                }
273:                if (object instanceof  OperationMethod) {
274:                    return METHOD_COLOR;
275:                }
276:                if (object instanceof  CoordinateSystemAxis) {
277:                    return AXIS_COLOR;
278:                }
279:                // Note: we can't test for MathTransform here, since it is not an IdentifiedObject.
280:                //       If we want to provide a color for the MathTransform name, we would need to
281:                //       do that in 'append(String)' method, but the later is for general string...
282:                return null;
283:            }
284:
285:            /**
286:             * Add a separator to the buffer, if needed.
287:             *
288:             * @param newLine if {@code true}, add a line separator too.
289:             */
290:            private void appendSeparator(final boolean newLine) {
291:                int length = buffer.length();
292:                char c;
293:                do {
294:                    if (length == bufferBase) {
295:                        return;
296:                    }
297:                    c = buffer.charAt(--length);
298:                    if (c == symbols.open || c == symbols.openArray) {
299:                        return;
300:                    }
301:                } while (Character.isWhitespace(c) || c == symbols.space);
302:                buffer.append(symbols.separator);
303:                buffer.append(symbols.space);
304:                if (newLine && indentation != 0) {
305:                    buffer.append(System.getProperty("line.separator", "\n"));
306:                    buffer.append(Utilities.spaces(margin));
307:                    lineChanged = true;
308:                }
309:            }
310:
311:            /**
312:             * Append the specified {@code Formattable} object. This method will automatically append
313:             * the keyword (e.g. <code>"GEOCS"</code>), the name and the authority code, and will invokes
314:             * <code>formattable.{@linkplain Formattable#formatWKT formatWKT}(this)</code> for completing
315:             * the inner part of the WKT.
316:             *
317:             * @param formattable The formattable object to append to the WKT.
318:             */
319:            public void append(final Formattable formattable) {
320:                /*
321:                 * Formats the opening bracket and the object name (e.g. "NAD27").
322:                 * The WKT entity name (e.g. "PROJCS") will be formatted later.
323:                 * The result of this code portion looks like the following:
324:                 *
325:                 *         <previous text>,
326:                 *           ["NAD27 / Idaho Central"
327:                 */
328:                appendSeparator(true);
329:                int base = buffer.length();
330:                buffer.append(symbols.open);
331:                final IdentifiedObject info = (formattable instanceof  IdentifiedObject) ? (IdentifiedObject) formattable
332:                        : null;
333:                if (info != null) {
334:                    final String c = getNameColor(info);
335:                    if (c != null) {
336:                        setColor(c);
337:                    }
338:                    buffer.append(symbols.quote);
339:                    buffer.append(getName(info));
340:                    buffer.append(symbols.quote);
341:                    if (c != null) {
342:                        resetColor();
343:                    }
344:                }
345:                /*
346:                 * Formats the part after the object name, then insert the WKT element name
347:                 * in front of them. The result of this code portion looks like the following:
348:                 *
349:                 *         <previous text>,
350:                 *           PROJCS["NAD27 / Idaho Central",
351:                 *             GEOGCS[...etc...],
352:                 *             ...etc...
353:                 */
354:                indent(+1);
355:                lineChanged = false;
356:                String keyword = formattable.formatWKT(this );
357:                if (colorEnabled && invalidWKT) {
358:                    invalidWKT = false;
359:                    buffer.insert(base, ERROR_COLOR + X364.BACKGROUND_DEFAULT);
360:                    base += ERROR_COLOR.length();
361:                }
362:                buffer.insert(base, keyword);
363:                /*
364:                 * Formats the AUTHORITY[<name>,<code>] entity, if there is one. The entity
365:                 * will be on the same line than the enclosing one if no line separator were
366:                 * added (e.g. SPHEROID["Clarke 1866", ..., AUTHORITY["EPSG","7008"]]), or on
367:                 * a new line otherwise. After this block, the result looks like the following:
368:                 *
369:                 *         <previous text>,
370:                 *           PROJCS["NAD27 / Idaho Central",
371:                 *             GEOGCS[...etc...],
372:                 *             ...etc...
373:                 *             AUTHORITY["EPSG","26769"]]
374:                 */
375:                final Identifier identifier = getIdentifier(info);
376:                if (identifier != null && authorityAllowed(info)) {
377:                    final Citation authority = identifier.getAuthority();
378:                    if (authority != null) {
379:                        /*
380:                         * Since WKT often use abbreviations, search for the shortest
381:                         * title or alternate title. If one is found, it will be used
382:                         * as the authority name (e.g. "EPSG").
383:                         */
384:                        InternationalString inter = authority.getTitle();
385:                        String title = (inter != null) ? inter
386:                                .toString(symbols.locale) : null;
387:                        for (final Iterator it = authority.getAlternateTitles()
388:                                .iterator(); it.hasNext();) {
389:                            inter = (InternationalString) it.next();
390:                            if (inter != null) {
391:                                final String candidate = inter
392:                                        .toString(symbols.locale);
393:                                if (candidate != null) {
394:                                    if (title == null
395:                                            || candidate.length() < title
396:                                                    .length()) {
397:                                        title = candidate;
398:                                    }
399:                                }
400:                            }
401:                        }
402:                        if (title != null) {
403:                            appendSeparator(lineChanged);
404:                            buffer.append("AUTHORITY");
405:                            buffer.append(symbols.open);
406:                            buffer.append(symbols.quote);
407:                            buffer.append(title);
408:                            buffer.append(symbols.quote);
409:                            final String code = identifier.getCode();
410:                            if (code != null) {
411:                                buffer.append(symbols.separator);
412:                                buffer.append(symbols.quote);
413:                                buffer.append(code);
414:                                buffer.append(symbols.quote);
415:                            }
416:                            buffer.append(symbols.close);
417:                        }
418:                    }
419:                }
420:                buffer.append(symbols.close);
421:                lineChanged = true;
422:                indent(-1);
423:            }
424:
425:            /**
426:             * Append the specified OpenGIS's {@code IdentifiedObject} object.
427:             *
428:             * @param info The info object to append to the WKT.
429:             */
430:            public void append(final IdentifiedObject info) {
431:                if (info instanceof  Formattable) {
432:                    append((Formattable) info);
433:                } else {
434:                    append(new Adapter(info));
435:                }
436:            }
437:
438:            /**
439:             * Append the specified math transform.
440:             *
441:             * @param transform The transform object to append to the WKT.
442:             */
443:            public void append(final MathTransform transform) {
444:                if (transform instanceof  Formattable) {
445:                    append((Formattable) transform);
446:                } else {
447:                    append(new Adapter(transform));
448:                }
449:            }
450:
451:            /**
452:             * Append a code list to the WKT.
453:             */
454:            public void append(final CodeList code) {
455:                if (code != null) {
456:                    appendSeparator(false);
457:                    setColor(CODELIST_COLOR);
458:                    final String name = code.name();
459:                    final boolean needQuotes = (name.indexOf(' ') >= 0);
460:                    if (needQuotes) {
461:                        buffer.append(symbols.quote);
462:                    }
463:                    buffer.append(name);
464:                    if (needQuotes) {
465:                        buffer.append(symbols.quote);
466:                        setInvalidWKT(code.getClass());
467:                    }
468:                    resetColor();
469:                }
470:            }
471:
472:            /**
473:             * Append a {@linkplain ParameterValue parameter} in WKT form. If the supplied parameter
474:             * is actually a {@linkplain ParameterValueGroup parameter group}, all parameters will be
475:             * inlined.
476:             */
477:            public void append(final GeneralParameterValue parameter) {
478:                if (parameter instanceof  ParameterValueGroup) {
479:                    for (final Iterator it = ((ParameterValueGroup) parameter)
480:                            .values().iterator(); it.hasNext();) {
481:                        append((GeneralParameterValue) it.next());
482:                    }
483:                }
484:                if (parameter instanceof  ParameterValue) {
485:                    final ParameterValue param = (ParameterValue) parameter;
486:                    // Covariance: Remove cast if covariance is allowed.
487:                    final ParameterDescriptor descriptor = (ParameterDescriptor) param
488:                            .getDescriptor();
489:                    final Unit valueUnit = descriptor.getUnit();
490:                    Unit unit = valueUnit;
491:                    if (unit != null && !Unit.ONE.equals(unit)) {
492:                        if (linearUnit != null && unit.isCompatible(linearUnit)) {
493:                            unit = linearUnit;
494:                        } else if (angularUnit != null
495:                                && unit.isCompatible(angularUnit)) {
496:                            unit = angularUnit;
497:                        }
498:                    }
499:                    appendSeparator(true);
500:                    final int start = buffer.length();
501:                    buffer.append("PARAMETER");
502:                    final int stop = buffer.length();
503:                    buffer.append(symbols.open);
504:                    setColor(PARAMETER_COLOR);
505:                    buffer.append(symbols.quote);
506:                    buffer.append(getName(descriptor));
507:                    buffer.append(symbols.quote);
508:                    resetColor();
509:                    buffer.append(symbols.separator);
510:                    buffer.append(symbols.space);
511:                    if (unit != null) {
512:                        double value;
513:                        try {
514:                            value = param.doubleValue(unit);
515:                        } catch (IllegalStateException exception) {
516:                            // May happen if a parameter is mandatory (e.g. "semi-major")
517:                            // but no value has been set for this parameter.
518:                            if (colorEnabled) {
519:                                buffer.insert(stop, X364.BACKGROUND_DEFAULT);
520:                                buffer.insert(start, ERROR_COLOR);
521:                            }
522:                            warning = exception.getLocalizedMessage();
523:                            value = Double.NaN;
524:                        }
525:                        if (!unit.equals(valueUnit)) {
526:                            value = XMath.fixRoundingError(value, 9);
527:                        }
528:                        format(value);
529:                    } else {
530:                        appendObject(param.getValue());
531:                    }
532:                    buffer.append(symbols.close);
533:                }
534:            }
535:
536:            /**
537:             * Append the specified value to a string buffer. If the value is an array, then the
538:             * array elements are appended recursively (i.e. the array may contains sub-array).
539:             */
540:            private void appendObject(final Object value) {
541:                if (value == null) {
542:                    buffer.append("null");
543:                    return;
544:                }
545:                if (value.getClass().isArray()) {
546:                    buffer.append(symbols.openArray);
547:                    final int length = Array.getLength(value);
548:                    for (int i = 0; i < length; i++) {
549:                        if (i != 0) {
550:                            buffer.append(symbols.separator);
551:                            buffer.append(symbols.space);
552:                        }
553:                        appendObject(Array.get(value, i));
554:                    }
555:                    buffer.append(symbols.closeArray);
556:                    return;
557:                }
558:                if (value instanceof  Number) {
559:                    format((Number) value);
560:                } else {
561:                    buffer.append(symbols.quote);
562:                    buffer.append(value);
563:                    buffer.append(symbols.quote);
564:                }
565:            }
566:
567:            /**
568:             * Append an integer number. A comma (or any other element
569:             * separator) will be written before the number if needed.
570:             */
571:            public void append(final int number) {
572:                appendSeparator(false);
573:                format(number);
574:            }
575:
576:            /**
577:             * Append a floating point number. A comma (or any other element
578:             * separator) will be written before the number if needed.
579:             */
580:            public void append(final double number) {
581:                appendSeparator(false);
582:                format(number);
583:            }
584:
585:            /**
586:             * Appends a unit in WKT form. For example, {@code append(SI.KILOMETER)}
587:             * can append "<code>UNIT["km", 1000]</code>" to the WKT.
588:             */
589:            public void append(final Unit unit) {
590:                if (unit != null) {
591:                    appendSeparator(lineChanged);
592:                    buffer.append("UNIT");
593:                    buffer.append(symbols.open);
594:                    setColor(UNIT_COLOR);
595:                    buffer.append(symbols.quote);
596:                    if (NonSI.DEGREE_ANGLE.equals(unit)) {
597:                        buffer.append("degree");
598:                    } else {
599:                        unitFormat.format(unit, buffer, dummy);
600:                    }
601:                    buffer.append(symbols.quote);
602:                    resetColor();
603:                    Unit base = null;
604:                    if (SI.METER.isCompatible(unit)) {
605:                        base = SI.METER;
606:                    } else if (SI.SECOND.isCompatible(unit)) {
607:                        base = SI.SECOND;
608:                    } else if (SI.RADIAN.isCompatible(unit)) {
609:                        if (!Unit.ONE.equals(unit)) {
610:                            base = SI.RADIAN;
611:                        }
612:                    }
613:                    if (base != null) {
614:                        append(unit.getConverterTo(base).convert(1));
615:                    }
616:                    buffer.append(symbols.close);
617:                }
618:            }
619:
620:            /**
621:             * Append a character string. The string will be written between quotes.
622:             * A comma (or any other element separator) will be written before the string if needed.
623:             */
624:            public void append(final String text) {
625:                appendSeparator(false);
626:                buffer.append(symbols.quote);
627:                buffer.append(text);
628:                buffer.append(symbols.quote);
629:            }
630:
631:            /**
632:             * Format an arbitrary number.
633:             */
634:            private void format(final Number number) {
635:                if (number instanceof  Byte || number instanceof  Short
636:                        || number instanceof  Integer) {
637:                    format(number.intValue());
638:                } else {
639:                    format(number.doubleValue());
640:                }
641:            }
642:
643:            /**
644:             * Format an integer number.
645:             */
646:            private void format(final int number) {
647:                setColor(INTEGER_COLOR);
648:                final int fraction = numberFormat.getMinimumFractionDigits();
649:                numberFormat.setMinimumFractionDigits(0);
650:                numberFormat.format(number, buffer, dummy);
651:                numberFormat.setMinimumFractionDigits(fraction);
652:                resetColor();
653:            }
654:
655:            /**
656:             * Format a floating point number.
657:             */
658:            private void format(final double number) {
659:                setColor(NUMBER_COLOR);
660:                numberFormat.format(number, buffer, dummy);
661:                resetColor();
662:            }
663:
664:            /**
665:             * Increase or reduce the indentation. A value of {@code +1} increase
666:             * the indentation by the amount of spaces specified at construction time,
667:             * and a value of {@code +1} reduce it.
668:             */
669:            private void indent(final int amount) {
670:                margin = Math.max(0, margin + indentation * amount);
671:            }
672:
673:            /**
674:             * Tells if an {@code "AUTHORITY"} element is allowed for the specified object.
675:             */
676:            private static boolean authorityAllowed(final IdentifiedObject info) {
677:                for (int i = 0; i < AUTHORITY_EXCLUDE.length; i++) {
678:                    if (AUTHORITY_EXCLUDE[i].isInstance(info)) {
679:                        return false;
680:                    }
681:                }
682:                return true;
683:            }
684:
685:            /**
686:             * Returns the preferred identifier for the specified object. If the specified
687:             * object contains an identifier from the preferred authority (usually
688:             * {@linkplain Citations#OGC Open Geospatial}), then this identifier is
689:             * returned. Otherwise, the first identifier is returned. If the specified
690:             * object contains no identifier, then this method returns {@code null}.
691:             *
692:             * @param  info The object to looks for a preferred identifier.
693:             * @return The preferred identifier, or {@code null} if none.
694:             *
695:             * @since 2.3
696:             */
697:            public Identifier getIdentifier(final IdentifiedObject info) {
698:                Identifier first = null;
699:                if (info != null) {
700:                    final Collection/*<Identifier>*/identifiers = info
701:                            .getIdentifiers();
702:                    if (identifiers != null) {
703:                        for (final Iterator it = identifiers.iterator(); it
704:                                .hasNext();) {
705:                            final Identifier id = (Identifier) it.next();
706:                            if (authorityMatches(id.getAuthority())) {
707:                                return id;
708:                            }
709:                            if (first == null) {
710:                                first = id;
711:                            }
712:                        }
713:                    }
714:                }
715:                return first;
716:            }
717:
718:            /**
719:             * Checks if the specified authority can be recognized as the expected authority.
720:             * This implementation do not requires an exact matches. A matching title is enough.
721:             */
722:            private boolean authorityMatches(final Citation citation) {
723:                if (authority == citation) {
724:                    return true;
725:                }
726:                return (citation != null)
727:                        && authority
728:                                .getTitle()
729:                                .toString(Locale.US)
730:                                .equalsIgnoreCase(
731:                                        citation.getTitle().toString(Locale.US));
732:            }
733:
734:            /**
735:             * Returns the preferred name for the specified object. If the specified
736:             * object contains a name from the preferred authority (usually
737:             * {@linkplain Citations#OGC Open Geospatial}), then this name is
738:             * returned. Otherwise, the first name found is returned.
739:             *
740:             * @param  info The object to looks for a preferred name.
741:             * @return The preferred name.
742:             */
743:            public String getName(final IdentifiedObject info) {
744:                final Identifier name = info.getName();
745:                if (!authorityMatches(name.getAuthority())) {
746:                    final Collection/*<GenericName>*/aliases = info.getAlias();
747:                    if (aliases != null) {
748:                        /*
749:                         * The main name doesn't matches. Search in alias. We will first
750:                         * check if alias implements Identifier (this is the case of
751:                         * Geotools implementation). Otherwise, we will look at the
752:                         * scope in generic name.
753:                         */
754:                        for (final Iterator it = aliases.iterator(); it
755:                                .hasNext();) {
756:                            final GenericName alias = (GenericName) it.next();
757:                            if (alias instanceof  Identifier) {
758:                                final Identifier candidate = (Identifier) alias;
759:                                if (authorityMatches(candidate.getAuthority())) {
760:                                    return candidate.getCode();
761:                                }
762:                            }
763:                        }
764:                        final String title = authority.getTitle().toString(
765:                                Locale.US);
766:                        for (final Iterator it = aliases.iterator(); it
767:                                .hasNext();) {
768:                            final GenericName alias = (GenericName) it.next();
769:                            final GenericName scope = alias.getScope();
770:                            if (scope != null) {
771:                                if (title.equalsIgnoreCase(scope.toString())) {
772:                                    return alias.asLocalName().toString();
773:                                }
774:                            }
775:                        }
776:                    }
777:                }
778:                return name.getCode();
779:            }
780:
781:            /**
782:             * The linear unit for formatting measures, or {@code null} for the "natural" unit of each
783:             * WKT element.
784:             *
785:             * @return The unit for measure. Default value is {@code null}.
786:             */
787:            public Unit getLinearUnit() {
788:                return linearUnit;
789:            }
790:
791:            /**
792:             * Set the unit for formatting linear measures.
793:             *
794:             * @param unit The new unit, or {@code null}.
795:             */
796:            public void setLinearUnit(final Unit unit) {
797:                if (unit != null && !SI.METER.isCompatible(unit)) {
798:                    throw new IllegalArgumentException(Errors.format(
799:                            ErrorKeys.NON_LINEAR_UNIT_$1, unit));
800:                }
801:                linearUnit = unit;
802:            }
803:
804:            /**
805:             * The angular unit for formatting measures, or {@code null} for the "natural" unit of
806:             * each WKT element. This value is set for example by "GEOGCS", which force its enclosing
807:             * "PRIMEM" to take the same units than itself.
808:             *
809:             * @return The unit for measure. Default value is {@code null}.
810:             */
811:            public Unit getAngularUnit() {
812:                return angularUnit;
813:            }
814:
815:            /**
816:             * Set the angular unit for formatting measures.
817:             *
818:             * @param unit The new unit, or {@code null}.
819:             */
820:            public void setAngularUnit(final Unit unit) {
821:                if (unit != null
822:                        && (!SI.RADIAN.isCompatible(unit) || Unit.ONE
823:                                .equals(unit))) {
824:                    throw new IllegalArgumentException(Errors.format(
825:                            ErrorKeys.NON_ANGULAR_UNIT_$1, unit));
826:                }
827:                angularUnit = unit;
828:            }
829:
830:            /**
831:             * Returns {@code true} if the WKT in this formatter is not strictly compliant to the
832:             * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html">WKT
833:             * specification</A>. This method returns {@code true} if {@link #setInvalidWKT} has
834:             * been invoked at least once. The action to take regarding invalid WKT is caller-dependant.
835:             * For example {@link Formattable#toString} will accepts loose WKT formatting and ignore this
836:             * flag, while {@link Formattable#toWKT} requires strict WKT formatting and will thrown an
837:             * exception if this flag is set.
838:             */
839:            public boolean isInvalidWKT() {
840:                return unformattable != null
841:                        || (buffer != null && buffer.length() == 0);
842:                /*
843:                 * Note: we really use a "and" condition (not an other "or") for the buffer test because
844:                 *       the buffer is reset to 'null' by AbstractParser after a successfull formatting.
845:                 */
846:            }
847:
848:            /**
849:             * Returns the class declared by the last call to {@link #setInvalidWKT}.
850:             */
851:            final Class getUnformattableClass() {
852:                return unformattable;
853:            }
854:
855:            /**
856:             * Set a flag marking the current WKT as not strictly compliant to the
857:             * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html">WKT
858:             * specification</A>. This method is invoked by {@link Formattable#formatWKT} methods when the
859:             * object to format is more complex than what the WKT specification allows. For example this
860:             * method is invoked when an {@linkplain org.geotools.referencing.crs.DefaultEngineeringCRS
861:             * engineering CRS} uses different unit for each axis, An application can tests
862:             * {@link #isInvalidWKT} later for checking WKT validity.
863:             *
864:             * @param unformattable The type of the component that can't be formatted,
865:             *        for example {@link org.opengis.referencing.crs.EngineeringCRS}.
866:             *
867:             * @see UnformattableObjectException#getUnformattableClass
868:             *
869:             * @since 2.4
870:             */
871:            public void setInvalidWKT(final Class unformattable) {
872:                this .unformattable = unformattable;
873:                invalidWKT = true;
874:            }
875:
876:            /**
877:             * Set a flag marking the current WKT as not strictly compliant to the WKT specification.
878:             *
879:             * @deprecated Replaced by {@link #setInvalidWKT(Class)}.
880:             */
881:            public void setInvalidWKT() {
882:                setInvalidWKT(IdentifiedObject.class);
883:            }
884:
885:            /**
886:             * Returns the WKT in its current state.
887:             */
888:            public String toString() {
889:                return buffer.toString();
890:            }
891:
892:            /**
893:             * Clear this formatter. All properties (including {@linkplain #getLinearUnit unit}
894:             * and {@linkplain #isInvalidWKT WKT validity flag} are reset to their default value.
895:             * After this method call, this {@code Formatter} object is ready for formatting
896:             * a new object.
897:             */
898:            public void clear() {
899:                if (buffer != null) {
900:                    buffer.setLength(0);
901:                }
902:                linearUnit = null;
903:                angularUnit = null;
904:                unformattable = null;
905:                warning = null;
906:                invalidWKT = false;
907:                lineChanged = false;
908:                margin = 0;
909:            }
910:
911:            /**
912:             * Set the preferred indentation from the command line. This indentation is used by
913:             * {@link Formattable#toWKT()} when no indentation were explicitly requested. This
914:             * method can be invoked from the command line using the following syntax:
915:             *
916:             * <blockquote>
917:             * {@code java org.geotools.referencing.wkt.Formatter -indentation=}<var>&lt;preferred
918:             * indentation&gt;</var>
919:             * </blockquote>
920:             */
921:            public static void main(String[] args) {
922:                final Arguments arguments = new Arguments(args);
923:                final int indentation = arguments
924:                        .getRequiredInteger(Formattable.INDENTATION);
925:                args = arguments.getRemainingArguments(0);
926:                Formattable.setIndentation(indentation);
927:            }
928:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.