Archived
0

Implement check of intersect controlling spheres

This commit is contained in:
iMoHax
2016-10-28 16:18:29 +03:00
parent cc7db01dd6
commit 58de159911
3 changed files with 540 additions and 0 deletions

View File

@@ -0,0 +1,186 @@
package ru.trader.analysis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.core.Market;
import ru.trader.core.Place;
import ru.trader.core.StarSystemFilter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class PowerPlayAnalyzator {
private final static Logger LOG = LoggerFactory.getLogger(PowerPlayAnalyzator.class);
private final static double CONTROLLING_RADIUS = 15;
private final Market market;
private StarSystemFilter starSystemFilter;
public PowerPlayAnalyzator(Market market) {
this.market = market;
}
public StarSystemFilter getStarSystemFilter() {
return starSystemFilter;
}
public void setStarSystemFilter(StarSystemFilter starSystemFilter) {
this.starSystemFilter = starSystemFilter;
}
public Collection<Place> getNear(Collection<Place> starSystems, Collection<Place> centers, double radius, double maxDistance){
return starSystems.stream()
.filter(new FarDropper(centers, maxDistance))
.filter(intersectsAnyPredicate(centers, radius).negate())
.sorted(new DistanceComparator(centers))
.collect(Collectors.toList());
}
public Collection<Place> getIntersects(Place checkedSystem, Collection<Place> starSystems, Collection<Place> centers, double radius){
return starSystems.stream()
.filter(new FarDropper(centers, radius))
.filter(intersectsPredicate(checkedSystem, centers, radius))
.collect(Collectors.toList());
}
public Collection<Place> getIntersects(Collection<Place> starSystems, Collection<Place> centers, double radius){
return starSystems.stream()
.filter(new FarDropper(centers, radius))
.filter(intersectsPredicate(centers, radius))
.collect(Collectors.toList());
}
private Predicate<Place> intersectsAnyPredicate(Collection<Place> places, double radius){
Predicate<Place> intersects = null;
for (Place place : places) {
if (intersects == null) intersects = new Controlling(place, radius);
else intersects = intersects.or(new Controlling(place, radius));
}
return intersects;
}
private Predicate<Place> intersectsPredicate(Collection<Place> places, double radius){
Predicate<Place> intersects = null;
for (Place place : places) {
if (intersects == null) intersects = new Controlling(place, radius);
else intersects = intersects.and(new Controlling(place, radius));
}
return intersects;
}
private Predicate<Place> intersectsPredicate(Place checkedPlace, Collection<Place> places, double radius){
return new Controlling(checkedPlace, radius).and(intersectsAnyPredicate(places, radius));
}
private class Controlling implements Predicate<Place> {
private final Place center;
private final double radius;
private Controlling(Place center, double radius) {
this.center = center;
this.radius = radius;
}
@Override
public boolean test(Place place) {
double distance = center.getDistance(place);
LOG.trace("Check {}, distance to {} = {}, radius = {}", place, center, distance, radius);
return distance <= radius;
}
}
private class FarDropper implements Predicate<Place> {
private double minX;
private double maxX;
private double minY;
private double maxY;
private double minZ;
private double maxZ;
private FarDropper(Collection<Place> centers, double radius) {
minX = Double.NaN; maxX = Double.NaN;
minY = Double.NaN; maxY = Double.NaN;
minZ = Double.NaN; maxZ = Double.NaN;
for (Place center : centers) {
if (Double.isNaN(minX) || minX > center.getX()) minX = center.getX();
if (Double.isNaN(minY) || minY > center.getY()) minY = center.getY();
if (Double.isNaN(minZ) || minZ > center.getZ()) minZ = center.getZ();
if (Double.isNaN(maxX) || maxX < center.getX()) maxX = center.getX();
if (Double.isNaN(maxY) || maxY < center.getY()) maxY = center.getY();
if (Double.isNaN(maxZ) || maxZ < center.getZ()) maxZ = center.getZ();
}
minX -= radius;
minY -= radius;
minZ -= radius;
maxX += radius;
maxY += radius;
maxZ += radius;
}
@Override
public boolean test(Place place) {
boolean res = place.getX() < minX || place.getX() > maxX
|| place.getY() < minY || place.getY() > maxY
|| place.getZ() < minZ || place.getZ() > maxZ;
LOG.trace("Test {}, dropper = {}, faraway = {}", place, this, res);
return !res;
}
@Override
public String toString() {
return "FarDropper{" +
"minX=" + minX +
", maxX=" + maxX +
", minY=" + minY +
", maxY=" + maxY +
", minZ=" + minZ +
", maxZ=" + maxZ +
'}';
}
}
private class DistanceComparator implements Comparator<Place> {
private final Collection<Place> centers;
private final HashMap<Place, Double> distances;
private DistanceComparator(Collection<Place> centers) {
this.centers = centers;
distances = new HashMap<>(100);
}
private double getMinDistance(Place place){
Double distance = distances.get(place);
if (distance != null) return distance;
Collection<Double> ds = new LimitedQueue<>(3, Comparator.naturalOrder());
for (Place center : centers) {
double d = center.getDistance(place);
ds.add(d);
}
double dist = 0;
for (Double d : ds) {
dist += d;
}
distances.put(place, dist);
return dist;
}
@Override
public int compare(Place o1, Place o2) {
return Double.compare(getMinDistance(o1), getMinDistance(o2));
}
}
}

View File

@@ -0,0 +1,185 @@
package ru.trader.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
public class StarSystemFilter {
private final static Logger LOG = LoggerFactory.getLogger(StarSystemFilter.class);
private final Collection<DistanceFilter> distances;
private final EnumSet<POWER> powers;
private final EnumSet<POWER_STATE> states;
private final EnumSet<FACTION> factions;
private final EnumSet<GOVERNMENT> governments;
private final Collection<Place> excludes;
public StarSystemFilter() {
this.powers = EnumSet.noneOf(POWER.class);
this.states = EnumSet.noneOf(POWER_STATE.class);
this.factions = EnumSet.noneOf(FACTION.class);
this.governments = EnumSet.noneOf(GOVERNMENT.class);
this.excludes = new ArrayList<>();
this.distances = new ArrayList<>();
}
public Collection<DistanceFilter> getDistanceFilters() {
return distances;
}
public void add(Place center, double radius){
distances.add(new DistanceFilter(center, radius));
}
public void add(DistanceFilter distanceFilter){
distances.add(distanceFilter);
}
public void remove(Place center){
distances.removeIf(d -> d.center.equals(center));
}
public void remove(DistanceFilter distanceFilter){
distances.remove(distanceFilter);
}
public void clearDistanceFilters(){
distances.clear();
}
public Collection<POWER> getPowers(){
return powers;
}
public void add(POWER power){
powers.add(power);
}
public void remove(POWER power){
powers.remove(power);
}
public void clearPower(){
powers.clear();
}
public Collection<POWER_STATE> getPowerStates(){
return states;
}
public void add(POWER_STATE powerState){
states.add(powerState);
}
public void remove(POWER_STATE powerState){
states.remove(powerState);
}
public void clearPowerStates(){
states.clear();
}
public Collection<Place> getExcludes(){
return excludes;
}
public void addExclude(Place starSystem){
excludes.add(starSystem);
}
public void removeExclude(Place starSystem){
excludes.remove(starSystem);
}
public void clearExcludes(){
excludes.clear();
}
public Collection<FACTION> getFactions(){
return factions;
}
public void add(FACTION faction){
factions.add(faction);
}
public void remove(FACTION faction){
factions.remove(faction);
}
public void clearFactions(){
factions.clear();
}
public Collection<GOVERNMENT> getGovernments(){
return governments;
}
public void add(GOVERNMENT government){
governments.add(government);
}
public void remove(GOVERNMENT government){
governments.remove(government);
}
public void clearGovernments(){
governments.clear();
}
public boolean isFiltered(Place starSystem){
for (DistanceFilter distanceFilter : distances) {
if (distanceFilter.isFiltered(starSystem)){
return true;
}
}
if (excludes.contains(starSystem)) return true;
POWER power = starSystem.getPower();
if (power != null && !powers.isEmpty() && !powers.contains(power)) return true;
POWER_STATE state = starSystem.getPowerState();
if (state != null && !states.isEmpty() && !states.contains(state)) return true;
FACTION faction = starSystem.getFaction();
if (faction != null && !factions.isEmpty() && !factions.contains(faction)) return true;
GOVERNMENT government = starSystem.getGovernment();
if (government != null && !governments.isEmpty() && !governments.contains(government)) return true;
return false;
}
@Override
public String toString() {
return "StarSystemFilter{" +
"distances=" + distances +
", powers=" + powers +
", states=" + states +
", factions=" + factions +
", governments=" + governments +
", excludes=" + excludes +
'}';
}
public class DistanceFilter {
private final Place center;
private final double distance;
public DistanceFilter(Place center, double distance) {
this.center = center;
this.distance = distance;
}
public Place getCenter() {
return center;
}
public double getDistance() {
return distance;
}
public boolean isFiltered(Place starSystem){
return center.getDistance(starSystem) <= distance;
}
}
}

View File

@@ -0,0 +1,169 @@
package ru.trader.analysis;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.core.Market;
import ru.trader.core.Place;
import ru.trader.store.simple.Store;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.stream.Collectors;
public class PowerPlayAnalyzatorTest extends Assert {
private final static Logger LOG = LoggerFactory.getLogger(RouteSearcherTest.class);
private Market world;
private Place lhs3262;
private Place aulin;
private Place morgor;
private Place lhs417;
@Before
public void setUp() throws Exception {
InputStream is = getClass().getResourceAsStream("/world.xml");
world = Store.loadFromFile(is);
lhs3262 = world.get("LHS 3262");
aulin = world.get("Aulin");
morgor = world.get("Morgor");
lhs417 = world.get("LHS 417");
}
@Test
public void intersectTest() throws Exception {
Collection<Place> starSystems = world.get();
Collection<Place> controllingLhs3262 = starSystems.stream().filter(p -> p.getDistance(lhs3262) <= 15).collect(Collectors.toList());
Collection<Place> controllingAulin = starSystems.stream().filter(p -> p.getDistance(aulin) <= 15).collect(Collectors.toList());
Collection<Place> controllingMorgor = starSystems.stream().filter(p -> p.getDistance(morgor) <= 15).collect(Collectors.toList());
Collection<Place> expectedIntersect = controllingLhs3262.stream().filter(controllingAulin::contains).collect(Collectors.toList());
Collection<Place> expected3Intersect = controllingLhs3262.stream().filter(controllingAulin::contains).filter(controllingMorgor::contains).collect(Collectors.toList());
PowerPlayAnalyzator analyzator = new PowerPlayAnalyzator(world);
Collection<Place> centers = new ArrayList<>();
centers.add(lhs3262);
Collection<Place> intersects = analyzator.getIntersects(starSystems, centers, 15);
LOG.info("Test intersects by LHS 3262, found {}", intersects.size());
for (Place intersect : intersects) {
assertTrue(lhs3262.getDistance(intersect) <= 15);
}
assertTrue(intersects.containsAll(controllingLhs3262));
assertEquals(controllingLhs3262.size(), intersects.size());
centers.add(aulin);
intersects = analyzator.getIntersects(starSystems, centers, 15);
LOG.info("Test intersects by LHS 3262 and Aulin, found {}", intersects.size());
for (Place intersect : intersects) {
assertTrue(lhs3262.getDistance(intersect) <= 15);
assertTrue(aulin.getDistance(intersect) <= 15);
}
assertTrue(intersects.containsAll(expectedIntersect));
assertEquals(expectedIntersect.size(), intersects.size());
centers.add(morgor);
intersects = analyzator.getIntersects(starSystems, centers, 15);
LOG.info("Test intersects by LHS 3262 and Aulin and Morgor, found {}", intersects.size());
for (Place intersect : intersects) {
assertTrue(lhs3262.getDistance(intersect) <= 15);
assertTrue(aulin.getDistance(intersect) <= 15);
assertTrue(morgor.getDistance(intersect) <= 15);
}
assertTrue(intersects.containsAll(expected3Intersect));
assertEquals(expected3Intersect.size(), intersects.size());
intersects = analyzator.getIntersects(starSystems, centers, 12);
LOG.info("Test intersects by LHS 3262 and Aulin and Morgor, 12 radius, found {}", intersects.size());
for (Place intersect : intersects) {
assertTrue(lhs3262.getDistance(intersect) <= 12);
assertTrue(aulin.getDistance(intersect) <= 12);
assertTrue(morgor.getDistance(intersect) <= 12);
}
assertEquals(0, intersects.size());
}
@Test
public void intersectTest2() throws Exception {
Collection<Place> starSystems = world.get();
Collection<Place> controllingLhs3262 = starSystems.stream().filter(p -> p.getDistance(lhs3262) <= 12).collect(Collectors.toList());
Collection<Place> controllingAulin = starSystems.stream().filter(p -> p.getDistance(aulin) <= 12).collect(Collectors.toList());
Collection<Place> controllingMorgor = starSystems.stream().filter(p -> p.getDistance(morgor) <= 12).collect(Collectors.toList());
Collection<Place> controllingLhs417 = starSystems.stream().filter(p -> p.getDistance(lhs417) <= 12).collect(Collectors.toList());
Collection<Place> expectedIntersect = controllingLhs417.stream().filter(p -> controllingLhs3262.contains(p) || controllingAulin.contains(p)).collect(Collectors.toList());
Collection<Place> expected3Intersect = controllingLhs417.stream().filter(p -> controllingLhs3262.contains(p) || controllingAulin.contains(p) || controllingMorgor.contains(p)).collect(Collectors.toList());
Collection<Place> expected2Intersect = controllingLhs417.stream().filter(p -> controllingAulin.contains(p) || controllingMorgor.contains(p)).collect(Collectors.toList());
PowerPlayAnalyzator analyzator = new PowerPlayAnalyzator(world);
Collection<Place> centers = new ArrayList<>();
centers.add(lhs3262);
centers.add(aulin);
Collection<Place> intersects = analyzator.getIntersects(lhs417, starSystems, centers, 12);
LOG.info("Test LHS 417 intersect LHS 3262 or Aulin, found {}", intersects.size());
for (Place intersect : intersects) {
assertTrue(lhs3262.getDistance(intersect) <= 12 || aulin.getDistance(intersect) <= 12);
assertTrue(lhs417.getDistance(intersect) <= 12);
}
assertTrue(intersects.containsAll(expectedIntersect));
assertEquals(expectedIntersect.size(), intersects.size());
centers.add(morgor);
intersects = analyzator.getIntersects(lhs417, starSystems, centers, 12);
LOG.info("Test LHS 417 intersect LHS 3262 or Aulin or Morgor, found {}", intersects.size());
for (Place intersect : intersects) {
assertTrue(lhs3262.getDistance(intersect) <= 12 || aulin.getDistance(intersect) <= 12 || morgor.getDistance(intersect) <= 12);
assertTrue(lhs417.getDistance(intersect) <= 12);
}
assertTrue(intersects.containsAll(expected3Intersect));
assertEquals(expected3Intersect.size(), intersects.size());
centers.clear();
centers.add(morgor);
intersects = analyzator.getIntersects(lhs417, starSystems, centers, 12);
LOG.info("Test LHS 417 intersect Morgor, found {}", intersects.size());
for (Place intersect : intersects) {
assertTrue(morgor.getDistance(intersect) <= 12);
assertTrue(lhs417.getDistance(intersect) <= 12);
}
assertEquals(0, intersects.size());
centers.add(aulin);
intersects = analyzator.getIntersects(lhs417, starSystems, centers, 12);
LOG.info("Test LHS 417 intersect Aulin or Morgor, found {}", intersects.size());
for (Place intersect : intersects) {
assertTrue(aulin.getDistance(intersect) <= 12 || morgor.getDistance(intersect) <= 12);
assertTrue(lhs417.getDistance(intersect) <= 12);
}
assertTrue(intersects.containsAll(expected2Intersect));
assertEquals(expected2Intersect.size(), intersects.size());
}
@Test
public void nearTest() throws Exception {
Collection<Place> starSystems = world.get();
Collection<Place> controllingLhs3262 = starSystems.stream().filter(p -> p.getDistance(lhs3262) <= 15).collect(Collectors.toList());
Collection<Place> controllingAulin = starSystems.stream().filter(p -> p.getDistance(aulin) <= 15).collect(Collectors.toList());
Collection<Place> controllingMorgor = starSystems.stream().filter(p -> p.getDistance(morgor) <= 15).collect(Collectors.toList());
PowerPlayAnalyzator analyzator = new PowerPlayAnalyzator(world);
Collection<Place> centers = new ArrayList<>();
centers.add(lhs3262);
centers.add(aulin);
Collection<Place> near = analyzator.getNear(starSystems, centers, 15, 30);
LOG.info("Test near by LHS 3262 and Aulin, found {}", near.size());
assertTrue(near.size() > 0);
for (Place place : near) {
Collection<Place> intersect = analyzator.getIntersects(place, starSystems, centers, 15);
assertEquals(0, intersect.size());
}
}
}