use of org.opengis.referencing.IdentifiedObject in project sis by apache.
the class ParameterFormat method formatSummary.
/**
* Implementation of public {@code format(…)} methods for {@code NAME_SUMMARY} content level.
*
* @param objects the collection of objects to format.
* @param out the stream or buffer where to write the summary.
* @throws IOException if an error occurred will writing to the given appendable.
*/
private void formatSummary(final IdentifiedObject[] objects, final Appendable out) throws IOException {
final Vocabulary resources = Vocabulary.getResources(displayLocale);
/*
* Prepares all rows before we write them to the output stream, because not all
* identified objects may have names with the same scopes in the same order. We
* also need to iterate over all rows in order to know the number of columns.
*
* The first column is reserved for the identifier. We put null as a sentinal key for
* that column name, to be replaced later by "Identifier" in user locale. We can not
* put the localized strings in the map right now because they could conflict with
* the scope of some alias to be processed below.
*/
boolean hasIdentifiers = false;
final List<String[]> rows = new ArrayList<>();
final Map<String, Integer> columnIndices = new LinkedHashMap<>();
// See above comment for the meaning of "null" here.
columnIndices.put(null, 0);
if (preferredCodespaces != null) {
for (final String codespace : preferredCodespaces) {
columnIndices.put(codespace, columnIndices.size());
}
}
for (final IdentifiedObject object : objects) {
// Will growth later if needed.
String[] row = new String[columnIndices.size()];
/*
* Put the first identifier in the first column. If no identifier has a codespace in the list
* supplied by the user, then we will use the first identifier (any codespace) as a fallback.
*/
final Set<ReferenceIdentifier> identifiers = object.getIdentifiers();
if (identifiers != null) {
// Paranoiac check.
Identifier identifier = null;
for (final ReferenceIdentifier candidate : identifiers) {
if (candidate != null) {
// Paranoiac check.
if (isPreferredCodespace(candidate.getCodeSpace())) {
identifier = candidate;
// Format now.
break;
}
if (identifier == null) {
// To be used as a fallback if we find nothing better.
identifier = candidate;
}
}
}
if (identifier != null) {
row[0] = IdentifiedObjects.toString(identifier);
hasIdentifiers = true;
}
}
/*
* If the name's codespace is in the list of codespaces asked by the user, add that name
* in the current row and clear the 'name' locale variable. Otherwise, keep the 'name'
* locale variable in case we found no alias to format.
*/
ReferenceIdentifier name = object.getName();
if (name != null) {
// Paranoiac check.
final String codespace = name.getCodeSpace();
if (isPreferredCodespace(codespace)) {
row = putIfAbsent(resources, row, columnIndices, codespace, name.getCode());
name = null;
}
}
/*
* Put all aliases having a codespace in the list asked by the user.
*/
final Collection<GenericName> aliases = object.getAlias();
if (aliases != null) {
// Paranoiac check.
for (final GenericName alias : aliases) {
if (alias != null) {
// Paranoiac check.
final String codespace = NameToIdentifier.getCodeSpace(alias, displayLocale);
if (isPreferredCodespace(codespace)) {
row = putIfAbsent(resources, row, columnIndices, codespace, alias.tip().toInternationalString().toString(displayLocale));
name = null;
}
}
}
}
/*
* If no name and no alias have a codespace in the list of codespaces asked by the user,
* force the addition of primary name regardless its codespace.
*/
if (name != null) {
row = putIfAbsent(resources, row, columnIndices, name.getCodeSpace(), name.getCode());
}
rows.add(row);
}
/*
* Writes the table. The header will contain one column for each codespace in the order declared
* by the user. If the user did not specified any codespace, or if we had to write codespace not
* on the user list, then those codespaces will be written in the order we found them.
*/
final boolean hasColors = (colors != null);
final TableAppender table = new TableAppender(out, columnSeparator);
table.setMultiLinesCells(true);
table.appendHorizontalSeparator();
for (String codespace : columnIndices.keySet()) {
if (codespace == null) {
// Skip empty column.
if (!hasIdentifiers)
continue;
codespace = resources.getString(Vocabulary.Keys.Identifier);
}
if (hasColors) {
codespace = X364.BOLD.sequence() + codespace + X364.NORMAL.sequence();
}
table.append(codespace);
nextColumn(table);
}
table.appendHorizontalSeparator();
/*
* Writes row content.
*/
final int numColumns = columnIndices.size();
for (final String[] row : rows) {
for (int i = hasIdentifiers ? 0 : 1; i < numColumns; i++) {
if (i < row.length) {
final String name = row[i];
if (name != null) {
table.append(name);
}
}
nextColumn(table);
}
table.nextLine();
}
table.appendHorizontalSeparator();
table.flush();
}
use of org.opengis.referencing.IdentifiedObject in project sis by apache.
the class ParameterFormat method format.
/**
* Formats the given object to the given stream of buffer.
* The object may be an instance of any of the following types:
*
* <ul>
* <li>{@link ParameterValueGroup}</li>
* <li>{@link ParameterDescriptorGroup}</li>
* <li>{@link OperationMethod}</li>
* <li><code>{@linkplain IdentifiedObject}[]</code> — accepted only for {@link ContentLevel#NAME_SUMMARY}.</li>
* </ul>
*
* @throws IOException if an error occurred while writing to the given appendable.
*/
@Override
public void format(final Object object, final Appendable toAppendTo) throws IOException {
ArgumentChecks.ensureNonNull("object", object);
ArgumentChecks.ensureNonNull("toAppendTo", toAppendTo);
final boolean isSummary = contentLevel == ContentLevel.NAME_SUMMARY;
final ParameterDescriptorGroup descriptor;
final ParameterValueGroup values;
final Identifier name;
if (object instanceof ParameterValueGroup) {
values = (ParameterValueGroup) object;
descriptor = values.getDescriptor();
name = descriptor.getName();
} else if (object instanceof ParameterDescriptorGroup) {
descriptor = (ParameterDescriptorGroup) object;
values = null;
name = descriptor.getName();
} else if (object instanceof OperationMethod) {
final OperationMethod operation = (OperationMethod) object;
descriptor = operation.getParameters();
values = null;
name = operation.getName();
} else if (isSummary && object instanceof IdentifiedObject[]) {
formatSummary((IdentifiedObject[]) object, toAppendTo);
return;
} else {
throw new IllegalArgumentException(Errors.getResources(displayLocale).getString(Errors.Keys.UnsupportedType_1, object.getClass()));
}
if (isSummary) {
final List<GeneralParameterDescriptor> parameters = descriptor.descriptors();
formatSummary(parameters.toArray(new IdentifiedObject[parameters.size()]), toAppendTo);
} else {
format(name.getCode(), descriptor, values, toAppendTo);
}
}
use of org.opengis.referencing.IdentifiedObject in project sis by apache.
the class EPSGFactoryTest method testFindGeographic.
/**
* Tests {@link EPSGFactory#newIdentifiedObjectFinder()} method with a geographic CRS.
*
* @throws FactoryException if an error occurred while querying the factory.
*/
@Test
@DependsOnMethod("testWGS84")
public void testFindGeographic() throws FactoryException {
final EPSGFactory factory = TestFactorySource.factory;
assumeNotNull(factory);
final IdentifiedObjectFinder finder = factory.newIdentifiedObjectFinder();
final DefaultGeographicCRS crs = (DefaultGeographicCRS) CRS.fromWKT("GEOGCS[“WGS 84”,\n" + // Use the alias instead than primary name for forcing a deeper search.
" DATUM[“WGS 84”,\n" + // Different name for forcing a deeper search.
" SPHEROID[“WGS 1984”, 6378137.0, 298.257223563]],\n" + " PRIMEM[“Greenwich”, 0.0],\n" + " UNIT[“degree”, 0.017453292519943295],\n" + " AXIS[“Geodetic latitude”, NORTH],\n" + " AXIS[“Geodetic longitude”, EAST]]");
/*
* First, search for a CRS with axis order that does not match the ones in the EPSG database.
* IdentifiedObjectFinder should not accept EPSG:4326 as a match for the given CRS.
*/
assertEquals("Full scan should be enabled by default.", IdentifiedObjectFinder.Domain.VALID_DATASET, finder.getSearchDomain());
assertTrue("Should not find WGS84 because the axis order is not the same.", finder.find(crs.forConvention(AxesConvention.NORMALIZED)).isEmpty());
/*
* Ensure that the cache is empty.
*/
finder.setSearchDomain(IdentifiedObjectFinder.Domain.DECLARATION);
assertTrue("Should not find without a full scan, because the WKT contains no identifier " + "and the CRS name is ambiguous (more than one EPSG object have this name).", finder.find(crs).isEmpty());
/*
* Scan the database for searching the CRS.
*/
finder.setSearchDomain(IdentifiedObjectFinder.Domain.ALL_DATASET);
final IdentifiedObject found = finder.findSingleton(crs);
assertNotNull("With full scan allowed, the CRS should be found.", found);
assertEpsgNameAndIdentifierEqual("WGS 84", 4326, found);
/*
* Should find the CRS without the need of a full scan, because of the cache.
*/
finder.setSearchDomain(IdentifiedObjectFinder.Domain.DECLARATION);
assertSame("The CRS should still in the cache.", found, finder.findSingleton(crs));
}
use of org.opengis.referencing.IdentifiedObject in project sis by apache.
the class FeatureFormat method formatValue.
/**
* Appends the given attribute value, in a truncated form if it exceed the maximal value length.
*
* @param value the value to append.
* @param table where to append the value.
* @param length number of characters appended before this method call in the current table cell.
* @return number of characters appended after this method call in the current table cell, or -1 if
* the length exceed the maximal length (in which case the caller should break iteration).
*/
private int formatValue(final Object value, final TableAppender table, final int length) {
String text;
if (value instanceof InternationalString) {
text = ((InternationalString) value).toString(displayLocale);
} else if (value instanceof GenericName) {
text = toString((GenericName) value);
} else if (value instanceof AbstractIdentifiedType) {
text = toString(((AbstractIdentifiedType) value).getName());
} else if (value instanceof IdentifiedObject) {
text = IdentifiedObjects.getIdentifierOrName((IdentifiedObject) value);
} else if ((text = Geometries.toString(value)) == null) {
text = value.toString();
}
final int remaining = MAXIMAL_VALUE_LENGTH - length;
if (remaining >= text.length()) {
table.append(text);
return length + text.length();
} else {
table.append(text, 0, Math.max(0, remaining - 1)).append('…');
return -1;
}
}
use of org.opengis.referencing.IdentifiedObject in project sis by apache.
the class Formatter method append.
/**
* Appends the given {@code FormattableObject}.
* This method performs the following steps:
*
* <ul>
* <li>Invoke <code>object.{@linkplain FormattableObject#formatTo(Formatter) formatTo}(this)</code>.</li>
* <li>Prepend the keyword returned by the above method call (e.g. {@code "GEOCS"}).</li>
* <li>If the given object is an instance of {@link IdentifiedObject}, then append complementary information:</li>
* </ul>
*
* <blockquote><table class="sis">
* <caption>Complementary WKT elements</caption>
* <tr><th>WKT 2 element</th><th>WKT 1 element</th><th>For types</th></tr>
* <tr><td>{@code Anchor[…]}</td> <td></td> <td>{@link Datum}</td></tr>
* <tr><td>{@code Scope[…]}</td> <td></td> <td>{@link ReferenceSystem}, {@link Datum}, {@link CoordinateOperation}</td></tr>
* <tr><td>{@code Area[…]}</td> <td></td> <td>{@link ReferenceSystem}, {@link Datum}, {@link CoordinateOperation}</td></tr>
* <tr><td>{@code BBox[…]}</td> <td></td> <td>{@link ReferenceSystem}, {@link Datum}, {@link CoordinateOperation}</td></tr>
* <tr><td>{@code VerticalExtent[…]}</td><td></td> <td>{@link ReferenceSystem}, {@link Datum}, {@link CoordinateOperation}</td></tr>
* <tr><td>{@code TimeExtent[…]}</td> <td></td> <td>{@link ReferenceSystem}, {@link Datum}, {@link CoordinateOperation}</td></tr>
* <tr><td>{@code Id[…]}</td><td>{@code Authority[…]}</td><td>{@link IdentifiedObject}</td></tr>
* <tr><td>{@code Remarks[…]}</td> <td></td> <td>{@link ReferenceSystem}, {@link CoordinateOperation}</td></tr>
* </table></blockquote>
*
* @param object the formattable object to append to the WKT, or {@code null} if none.
*/
public void append(final FormattableObject object) {
if (object == null) {
return;
}
/*
* Safety check: ensure that we do not have circular dependencies (e.g. a ProjectedCRS contains
* a Conversion which may contain the ProjectedCRS as its target CRS). Without this protection,
* a circular dependency would cause an OutOfMemoryError.
*/
final int stackDepth = enclosingElements.size();
for (int i = stackDepth; --i >= 0; ) {
if (enclosingElements.get(i) == object) {
throw new IllegalStateException(Errors.getResources(locale).getString(Errors.Keys.CircularReference));
}
}
enclosingElements.add(object);
if (hasContextualUnit < 0) {
// Test if leftmost bit is set to 1.
throw new IllegalStateException(Errors.getResources(locale).getString(Errors.Keys.TreeDepthExceedsMaximum));
}
hasContextualUnit <<= 1;
/*
* Add a new line if it was requested, open the bracket and increase indentation in case the
* element to format contains other FormattableObject elements.
*/
appendSeparator();
int base = buffer.length();
elementStart = buffer.appendCodePoint(symbols.getOpeningBracket(0)).length();
indent(+1);
/*
* Formats the inner part, then prepend the WKT keyword.
* The result looks like the following:
*
* <previous text>,
* PROJCS["NAD27 / Idaho Central",
* GEOGCS[...etc...],
* ...etc...
*/
IdentifiedObject info = (object instanceof IdentifiedObject) ? (IdentifiedObject) object : null;
String keyword = object.formatTo(this);
if (keyword == null) {
if (info != null) {
setInvalidWKT(info, null);
} else {
setInvalidWKT(object.getClass(), null);
}
keyword = getName(object.getClass());
} else if (toUpperCase != 0) {
final Locale locale = symbols.getLocale();
keyword = (toUpperCase >= 0) ? keyword.toUpperCase(locale) : keyword.toLowerCase(locale);
}
if (highlightError && colors != null) {
final String color = colors.getAnsiSequence(ElementKind.ERROR);
if (color != null) {
buffer.insert(base, color + BACKGROUND_DEFAULT);
base += color.length();
}
}
highlightError = false;
buffer.insert(base, keyword);
/*
* When formatting geometry coordinates, we may need to shift all numbers by the width
* of the keyword inserted above in order to keep numbers properly aligned. Exemple:
*
* BOX[ 4.000 -10.000
* 50.000 2.000]
*/
if (keywordSpaceAt != null) {
final int length = keyword.length();
final CharSequence additionalMargin = CharSequences.spaces(keyword.codePointCount(0, length));
final int n = keywordSpaceAt.size();
for (int i = 0; i < n; ) {
int p = keywordSpaceAt.getInt(i);
// Take in account spaces added previously.
p += (++i * length);
buffer.insert(p, additionalMargin);
}
keywordSpaceAt.clear();
}
/*
* Format the SCOPE["…"], AREA["…"] and other elements. Some of those information
* are available only for Datum, CoordinateOperation and ReferenceSystem objects.
*/
if (info == null && convention.majorVersion() != 1 && object instanceof GeneralParameterValue) {
info = ((GeneralParameterValue) object).getDescriptor();
}
if (info != null) {
appendComplement(info, (stackDepth >= 1) ? enclosingElements.get(stackDepth - 1) : null, (stackDepth >= 2) ? enclosingElements.get(stackDepth - 2) : null);
}
/*
* Close the bracket, then update the queue of enclosed elements by removing this element.
*/
buffer.appendCodePoint(symbols.getClosingBracket(0));
indent(-1);
enclosingElements.remove(stackDepth);
hasContextualUnit >>>= 1;
}
Aggregations