001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.osm; 003 004import java.util.Collection; 005import java.util.HashSet; 006import java.util.List; 007import java.util.Set; 008import java.util.stream.Collectors; 009 010import org.openstreetmap.josm.tools.Utils; 011 012/** 013 * IRelation captures the common functions of {@link Relation} and {@link RelationData}. 014 * @param <M> Type of OSM relation member 015 * @since 4098 016 */ 017public interface IRelation<M extends IRelationMember<?>> extends IPrimitive { 018 019 /** 020 * Returns the number of members. 021 * @return number of members 022 */ 023 int getMembersCount(); 024 025 /** 026 * Returns the relation member at the specified index. 027 * @param index the index of the relation member 028 * @return relation member at the specified index 029 * @since 13766 (IRelation) 030 */ 031 M getMember(int index); 032 033 /** 034 * Returns members of the relation. 035 * @return Members of the relation. Changes made in returned list are not mapped 036 * back to the primitive, use {@link #setMembers} to modify the members 037 * @since 1925 038 * @since 13766 (IRelation) 039 */ 040 List<M> getMembers(); 041 042 /** 043 * Sets members of the relation. 044 * @param members Can be null, in that case all members are removed 045 */ 046 void setMembers(List<M> members); 047 048 /** 049 * Returns id of the member at given index. 050 * @param idx member index 051 * @return id of the member at given index 052 */ 053 long getMemberId(int idx); 054 055 /** 056 * Returns role of the member at given index. 057 * @param idx member index 058 * @return role of the member at given index 059 */ 060 String getRole(int idx); 061 062 /** 063 * Returns type of the member at given index. 064 * @param idx member index 065 * @return type of the member at given index 066 */ 067 OsmPrimitiveType getMemberType(int idx); 068 069 /** 070 * Determines if at least one child primitive is incomplete. 071 * 072 * @return true if at least one child primitive is incomplete 073 * @since 13564 074 */ 075 default boolean hasIncompleteMembers() { 076 return false; 077 } 078 079 @Override 080 default int compareTo(IPrimitive o) { 081 return o instanceof IRelation ? Long.compare(getUniqueId(), o.getUniqueId()) : -1; 082 } 083 084 @Override 085 default String getDisplayName(NameFormatter formatter) { 086 return formatter.format(this); 087 } 088 089 /** 090 * Determines if this relation is a boundary. 091 * @return {@code true} if a boundary relation 092 */ 093 default boolean isBoundary() { 094 return "boundary".equals(get("type")); 095 } 096 097 @Override 098 default boolean isMultipolygon() { 099 return "multipolygon".equals(get("type")) || isBoundary(); 100 } 101 102 /** 103 * Returns an unmodifiable list of the {@link OsmPrimitive}s referred to by at least one member of this relation. 104 * @return an unmodifiable list of the primitives 105 * @since 13957 106 */ 107 default List<? extends IPrimitive> getMemberPrimitivesList() { 108 return Utils.transform(getMembers(), IRelationMember::getMember); 109 } 110 111 /** 112 * Replies a collection with the incomplete children this relation refers to. 113 * 114 * @return the incomplete children. Empty collection if no children are incomplete. 115 * @since 13957 116 */ 117 default Collection<? extends IPrimitive> getIncompleteMembers() { 118 Set<IPrimitive> ret = new HashSet<>(); 119 for (M rm : getMembers()) { 120 if (!rm.getMember().isIncomplete()) { 121 continue; 122 } 123 ret.add(rm.getMember()); 124 } 125 return ret; 126 } 127 128 /** 129 * Returns a list of relation members having the specified role. 130 * @param role role 131 * @return a list of relation members having the specified role 132 * @since 15418 133 */ 134 default List<? extends IPrimitive> findRelationMembers(String role) { 135 return getMembers().stream().filter(rmv -> role.equals(rmv.getRole())) 136 .map(IRelationMember::getMember).collect(Collectors.toList()); 137 } 138}