001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.vector;
003
004import java.util.ArrayList;
005import java.util.Collections;
006import java.util.List;
007
008import org.openstreetmap.josm.data.osm.BBox;
009import org.openstreetmap.josm.data.osm.IPrimitive;
010import org.openstreetmap.josm.data.osm.IRelation;
011import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
012import org.openstreetmap.josm.data.osm.UniqueIdGenerator;
013import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
014
015/**
016 * The "Relation" type for vectors
017 *
018 * @author Taylor Smock
019 * @since 17862
020 */
021public class VectorRelation extends VectorPrimitive implements IRelation<VectorRelationMember> {
022    private static final UniqueIdGenerator RELATION_ID_GENERATOR = new UniqueIdGenerator();
023    private final List<VectorRelationMember> members = new ArrayList<>();
024    private BBox cachedBBox;
025
026    /**
027     * Create a new relation for a layer
028     * @param layer The layer the relation will belong to
029     */
030    public VectorRelation(String layer) {
031        super(layer);
032    }
033
034    @Override
035    public UniqueIdGenerator getIdGenerator() {
036        return RELATION_ID_GENERATOR;
037    }
038
039    @Override
040    public void accept(PrimitiveVisitor visitor) {
041        visitor.visit(this);
042    }
043
044    @Override
045    public BBox getBBox() {
046        if (this.cachedBBox == null) {
047            BBox tBBox = new BBox();
048            for (IPrimitive member : this.getMemberPrimitivesList()) {
049                tBBox.add(member.getBBox());
050            }
051            this.cachedBBox = tBBox.toImmutable();
052        }
053        return this.cachedBBox;
054    }
055
056    protected void addRelationMember(VectorRelationMember member) {
057        this.members.add(member);
058        member.getMember().addReferrer(this);
059        cachedBBox = null;
060    }
061
062    /**
063     * Remove the first instance of a member from the relation
064     *
065     * @param member The member to remove
066     */
067    protected void removeRelationMember(VectorRelationMember member) {
068        this.members.remove(member);
069        if (!this.members.contains(member)) {
070            member.getMember().removeReferrer(this);
071        }
072    }
073
074    @Override
075    public int getMembersCount() {
076        return this.members.size();
077    }
078
079    @Override
080    public VectorRelationMember getMember(int index) {
081        return this.members.get(index);
082    }
083
084    @Override
085    public List<VectorRelationMember> getMembers() {
086        return Collections.unmodifiableList(this.members);
087    }
088
089    @Override
090    public void setMembers(List<VectorRelationMember> members) {
091        this.members.clear();
092        this.members.addAll(members);
093    }
094
095    @Override
096    public long getMemberId(int idx) {
097        return this.getMember(idx).getMember().getId();
098    }
099
100    @Override
101    public String getRole(int idx) {
102        return this.getMember(idx).getRole();
103    }
104
105    @Override
106    public OsmPrimitiveType getMemberType(int idx) {
107        return this.getMember(idx).getType();
108    }
109
110    @Override
111    public OsmPrimitiveType getType() {
112        return this.getMembers().stream().map(VectorRelationMember::getType)
113          .allMatch(OsmPrimitiveType.CLOSEDWAY::equals) ? OsmPrimitiveType.MULTIPOLYGON : OsmPrimitiveType.RELATION;
114    }
115}