001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.mappaint.styleelement;
003
004import java.util.Objects;
005
006import org.openstreetmap.josm.data.osm.OsmPrimitive;
007import org.openstreetmap.josm.data.osm.Way;
008import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
009import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
010import org.openstreetmap.josm.gui.mappaint.Cascade;
011import org.openstreetmap.josm.gui.mappaint.Environment;
012import org.openstreetmap.josm.gui.mappaint.Keyword;
013import org.openstreetmap.josm.tools.CheckParameterUtil;
014
015public class RepeatImageElement extends StyleElement {
016
017    public enum LineImageAlignment { TOP, CENTER, BOTTOM }
018
019    public MapImage pattern;
020    public float offset;
021    public float spacing;
022    public float phase;
023    public LineImageAlignment align;
024
025    private static final String[] REPEAT_IMAGE_KEYS = {REPEAT_IMAGE, REPEAT_IMAGE_WIDTH, REPEAT_IMAGE_HEIGHT, REPEAT_IMAGE_OPACITY,
026            null, null};
027
028    public RepeatImageElement(Cascade c, MapImage pattern, float offset, float spacing, float phase, LineImageAlignment align) {
029        super(c, 2.9f);
030        CheckParameterUtil.ensureParameterNotNull(pattern);
031        CheckParameterUtil.ensureParameterNotNull(align);
032        this.pattern = pattern;
033        this.offset = offset;
034        this.spacing = spacing;
035        this.phase = phase;
036        this.align = align;
037    }
038
039    public static RepeatImageElement create(Environment env) {
040        MapImage pattern = NodeElement.createIcon(env, REPEAT_IMAGE_KEYS);
041        if (pattern == null)
042            return null;
043        Cascade c = env.mc.getCascade(env.layer);
044        float offset = c.get(REPEAT_IMAGE_OFFSET, 0f, Float.class);
045        float spacing = c.get(REPEAT_IMAGE_SPACING, 0f, Float.class);
046        float phase = -c.get(REPEAT_IMAGE_PHASE, 0f, Float.class);
047
048        LineImageAlignment align = LineImageAlignment.CENTER;
049        Keyword alignKW = c.get(REPEAT_IMAGE_ALIGN, Keyword.CENTER, Keyword.class);
050        if ("top".equals(alignKW.val)) {
051            align = LineImageAlignment.TOP;
052        } else if ("bottom".equals(alignKW.val)) {
053            align = LineImageAlignment.BOTTOM;
054        }
055
056        return new RepeatImageElement(c, pattern, offset, spacing, phase, align);
057    }
058
059    @Override
060    public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, StyledMapRenderer painter,
061            boolean selected, boolean outermember, boolean member) {
062        Way w = (Way) primitive;
063        painter.drawRepeatImage(w, pattern, painter.isInactiveMode() || w.isDisabled(), offset, spacing, phase, align);
064    }
065
066    @Override
067    public boolean isProperLineStyle() {
068        return true;
069    }
070
071    @Override
072    public boolean equals(Object obj) {
073        if (this == obj) return true;
074        if (obj == null || getClass() != obj.getClass()) return false;
075        if (!super.equals(obj)) return false;
076        RepeatImageElement that = (RepeatImageElement) obj;
077        return Float.compare(that.offset, offset) == 0 &&
078                Float.compare(that.spacing, spacing) == 0 &&
079                Float.compare(that.phase, phase) == 0 &&
080                Objects.equals(pattern, that.pattern) &&
081                align == that.align;
082    }
083
084    @Override
085    public int hashCode() {
086        return Objects.hash(super.hashCode(), pattern, offset, spacing, phase, align);
087    }
088
089    @Override
090    public String toString() {
091        return "RepeatImageStyle{" + super.toString() + "pattern=[" + pattern +
092                "], offset=" + offset + ", spacing=" + spacing +
093                ", phase=" + (-phase) + ", align=" + align + '}';
094    }
095}