Passed
Push — master ( 08cd0d...9eabdf )
by Vincent
07:15
created

hasNext()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
dl 0
loc 3
ccs 1
cts 1
cp 1
crap 1
rs 10
1
/*
2
 * This file is part of ArakneUtils.
3
 *
4
 * ArakneUtils is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * ArakneUtils is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with ArakneUtils.  If not, see <https://www.gnu.org/licenses/>.
16
 *
17
 * Copyright (c) 2017-2021 Vincent Quatrevieux
18
 */
19
20
package fr.arakne.utils.maps.sight;
21
22
import fr.arakne.utils.maps.BattlefieldCell;
23
import fr.arakne.utils.maps.CoordinateCell;
24
25
import java.util.Iterator;
26
27
/**
28
 * Iterate between cells of the line of sight of two not aligned cells
29
 *
30
 * @param <C> The cell type
31
 */
32
final class NotAlignedLineOfSightIterator<C extends BattlefieldCell> implements Iterator<C> {
33
    private final BattlefieldSight<C> battlefield;
34
    private final CoordinateCell<C> source;
35
    private final CoordinateCell<C> target;
36
37
    private final int xDirection;
38
    private final int yDirection;
39
    private final double ySlope;
40
    private final double yAtZero;
41
42
    private int currentX;
43
    private int currentY;
44
45
    private int lastY;
46
    private int nextY;
47
48 1
    public NotAlignedLineOfSightIterator(BattlefieldSight<C> battlefield, CoordinateCell<C> source, CoordinateCell<C> target) {
49 1
        this.battlefield = battlefield;
50 1
        this.source = source;
51 1
        this.target = target;
52
53 1
        this.xDirection = source.x() > target.x() ? -1 : 1;
54 1
        this.yDirection = source.y() > target.y() ? -1 : 1;
55 1
        this.ySlope = (double) (target.y() - source.y()) / (double) (target.x() - source.x());
56 1
        this.yAtZero = source.y() - ySlope * source.x();
57
58 1
        init();
59 1
    }
60
61
    @Override
62
    public boolean hasNext() {
63 1
        return !target.is(currentX, currentY);
64
    }
65
66
    @Override
67
    public C next() {
0 ignored issues
show
Bug introduced by
Iteration beyond the the end of a collection should throw a NoSuchElementException.
Loading history...
68 1
        currentY += yDirection;
69
70
        // lastY is exceeded : increment the X value
71 1
        if (currentY * yDirection > lastY * yDirection) {
72 1
            currentX += xDirection;
73 1
            currentY = nextY;
74
75 1
            computeNextY();
76
        }
77
78 1
        return getCurrentCell();
79
    }
80
81
    /**
82
     * Initialise iterator
83
     */
84
    private void init() {
85 1
        currentX = source.x();
86 1
        currentY = source.y();
87
88 1
        computeNextY();
89 1
    }
90
91
    /**
92
     * Compute the target Y coordinate for the current X value
93
     * The value lastY is used as ending boundary for the Y coordinate iteration
94
     * The value nextY is used as start boundary for the Y coordinate iteration for the next X value
95
     */
96
    private void computeNextY() {
97
        // yMax is the value of Y at the current X
98
        // + 0.5 permit to ignore cells around the line of sight on diagonal (i.e. ySlope = 1)
99 1
        final double yAtCurrentX = (currentX + xDirection * 0.5) * ySlope + yAtZero;
100
101 1
        if (yDirection > 0) {
102 1
            nextY = (int) Math.round(yAtCurrentX);
103 1
            lastY = (int) Math.ceil(yAtCurrentX - 0.5);
104
        } else {
105 1
            nextY = (int) Math.ceil(yAtCurrentX - 0.5);
106 1
            lastY = (int) Math.round(yAtCurrentX);
107
        }
108 1
    }
109
110
    /**
111
     * @return The cell on the current coordinates
112
     */
113
    private C getCurrentCell() {
114 1
        return battlefield.getCellByCoordinates(currentX, currentY);
115
    }
116
}
117