AbstractPointMap1DTest.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.geometry.core.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NavigableMap;
import java.util.NoSuchElementException;
import java.util.Set;
import org.apache.commons.geometry.core.collection.PointMapTestBase;
import org.apache.commons.geometry.core.partitioning.test.TestPoint1D;
import org.apache.commons.numbers.core.Precision;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class AbstractPointMap1DTest extends PointMapTestBase<TestPoint1D> {
@Test
void testGetPrecision() {
// arrange
final TestPointMap1D<Integer> map = getMap(PRECISION);
// act/assert
Assertions.assertSame(PRECISION, map.getPrecision());
}
/** {@inheritDoc} */
@Override
protected <V> TestPointMap1D<V> getMap(final Precision.DoubleEquivalence precision) {
return new TestPointMap1D<>(precision);
}
/** {@inheritDoc} */
@Override
protected TestPoint1D[] createPointArray() {
return new TestPoint1D[0];
}
/** {@inheritDoc} */
@Override
protected List<TestPoint1D> getNaNPoints() {
return Arrays.asList(new TestPoint1D(Double.NaN));
}
/** {@inheritDoc} */
@Override
protected List<TestPoint1D> getInfPoints() {
return Arrays.asList(
new TestPoint1D(Double.NEGATIVE_INFINITY),
new TestPoint1D(Double.POSITIVE_INFINITY));
}
/** {@inheritDoc} */
@Override
protected List<TestPoint1D> getTestPoints(final int cnt, final double eps) {
final double delta = 10 * eps;
return createPointList(-1.0, delta, cnt);
}
/** {@inheritDoc} */
@Override
protected List<TestPoint1D> getTestPointsAtDistance(final TestPoint1D pt, final double dist) {
return Arrays.asList(
new TestPoint1D(pt.getX() - dist),
new TestPoint1D(pt.getX() + dist));
}
/** {@inheritDoc} */
@Override
protected boolean eq(final TestPoint1D a, final TestPoint1D b, final Precision.DoubleEquivalence precision) {
return precision.eq(a.getX(), b.getX());
}
/** {@inheritDoc} */
@Override
protected int disambiguateNearToFarOrder(final TestPoint1D a, final TestPoint1D b) {
return Double.compare(a.getX(), b.getX());
}
private static List<TestPoint1D> createPointList(final double start, final double delta, final int cnt) {
final List<TestPoint1D> pts = new ArrayList<>(cnt);
double x = start;
for (int i = 0; i < cnt; ++i) {
pts.add(new TestPoint1D(x));
x += delta;
}
return pts;
}
private static final class TestPointMap1D<V> extends AbstractPointMap1D<TestPoint1D, V> {
TestPointMap1D(final Precision.DoubleEquivalence precision) {
super(precision, TestPoint1D::getX);
}
/** {@inheritDoc} */
@Override
public boolean containsKey(final Object key) {
return getMap().containsKey(key);
}
/** {@inheritDoc} */
@Override
public V get(final Object key) {
return getMap().get(key);
}
/** {@inheritDoc} */
@Override
public V remove(final Object key) {
return getMap().remove(key);
}
/** {@inheritDoc} */
@Override
public void clear() {
getMap().clear();
}
/** {@inheritDoc} */
@Override
public Set<TestPoint1D> keySet() {
return getMap().keySet();
}
/** {@inheritDoc} */
@Override
public Set<Entry<TestPoint1D, V>> entrySet() {
return getMap().entrySet();
}
/** {@inheritDoc} */
@Override
protected Entry<TestPoint1D, V> getEntryInternal(final TestPoint1D key) {
final NavigableMap<TestPoint1D, V> map = getMap();
final Entry<TestPoint1D, V> floor = map.floorEntry(key);
if (floor != null &&
map.comparator().compare(floor.getKey(), key) == 0) {
return floor;
}
return null;
}
/** {@inheritDoc} */
@Override
protected V putInternal(final TestPoint1D key, final V value) {
return getMap().put(key, value);
}
/** {@inheritDoc} */
@Override
protected Iterator<Entry<TestPoint1D, V>> nearToFarIterator(final TestPoint1D pt) {
return new NearToFarIterator(pt);
}
/** {@inheritDoc} */
@Override
protected Iterator<Entry<TestPoint1D, V>> farToNearIterator(final TestPoint1D pt) {
return new FarToNearIterator(pt);
}
private final class NearToFarIterator
implements Iterator<Entry<TestPoint1D, V>> {
private final TestPoint1D refPt;
private final Iterator<Entry<TestPoint1D, V>> low;
private final Iterator<Entry<TestPoint1D, V>> high;
private DistancedValue<Entry<TestPoint1D, V>> lowEntry;
private DistancedValue<Entry<TestPoint1D, V>> highEntry;
NearToFarIterator(final TestPoint1D refPt) {
this.refPt = refPt;
this.low = getMap().descendingMap().tailMap(refPt, false)
.entrySet().iterator();
this.high = getMap().tailMap(refPt).entrySet().iterator();
}
/** {@inheritDoc} */
@Override
public boolean hasNext() {
if (lowEntry == null) {
lowEntry = getNextEntry(low);
}
if (highEntry == null) {
highEntry = getNextEntry(high);
}
return lowEntry != null || highEntry != null;
}
/** {@inheritDoc} */
@Override
public Entry<TestPoint1D, V> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
final DistancedValue<Entry<TestPoint1D, V>> result;
if (lowEntry != null &&
(highEntry == null || lowEntry.getDistance() <= highEntry.getDistance())) {
result = lowEntry;
lowEntry = null;
} else {
result = highEntry;
highEntry = null;
}
return result != null ?
result.getValue() :
null;
}
private DistancedValue<Entry<TestPoint1D, V>> getNextEntry(final Iterator<Entry<TestPoint1D, V>> it) {
if (it.hasNext()) {
final Entry<TestPoint1D, V> entry = it.next();
return DistancedValue.of(entry, refPt.distance(entry.getKey()));
}
return null;
}
}
private final class FarToNearIterator
implements Iterator<Entry<TestPoint1D, V>> {
private final TestPoint1D refPt;
private Iterator<Entry<TestPoint1D, V>> low;
private Iterator<Entry<TestPoint1D, V>> high;
private DistancedValue<Entry<TestPoint1D, V>> lowEntry;
private DistancedValue<Entry<TestPoint1D, V>> highEntry;
private double lastLowValue = Double.NEGATIVE_INFINITY;
private double lastHighValue = Double.POSITIVE_INFINITY;
FarToNearIterator(final TestPoint1D refPt) {
this.refPt = refPt;
this.low = getMap().entrySet().iterator();
this.high = getMap().descendingMap().entrySet().iterator();
}
/** {@inheritDoc} */
@Override
public boolean hasNext() {
if (lowEntry == null && low != null && low.hasNext()) {
final Entry<TestPoint1D, V> entry = low.next();
lastLowValue = entry.getKey().getX();
if (entry.getKey().getX() >= lastHighValue) {
// we've crossed over the value returned by the high iterator
low = null;
} else {
lowEntry = DistancedValue.of(entry, refPt.distance(entry.getKey()));
}
}
if (highEntry == null && high != null && high.hasNext()) {
final Entry<TestPoint1D, V> entry = high.next();
lastHighValue = entry.getKey().getX();
if (entry.getKey().getX() <= lastLowValue) {
// we've crossed over the values returned by the low iterator
high = null;
} else {
highEntry = DistancedValue.of(entry, refPt.distance(entry.getKey()));
}
}
return lowEntry != null || highEntry != null;
}
/** {@inheritDoc} */
@Override
public Entry<TestPoint1D, V> next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
final DistancedValue<Entry<TestPoint1D, V>> result;
if (lowEntry != null &&
(highEntry == null || lowEntry.getDistance() >= highEntry.getDistance())) {
result = lowEntry;
lowEntry = null;
} else {
result = highEntry;
highEntry = null;
}
return result != null ?
result.getValue() :
null;
}
}
}
}