package scd_micro;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* The constructor runs and the instance lives in the persistent detector scope. The state table
* passed to it lives in the persistent detector scope. The thread runs in transient detector
* scope. The frame (currentFrame) lives in immortal memory.
*
* The real collision detection starts here.
*/
public class TransientDetectorScopeEntry implements Runnable {
private StateTable state;
private float voxelSize;
private RawFrame currentFrame;
public TransientDetectorScopeEntry(final StateTable s, final float voxelSize) {
state = s;
this.voxelSize = voxelSize;
}
public void run() {
if (Constants.SYNCHRONOUS_DETECTOR || Constants.DEBUG_DETECTOR) {
dumpFrame("CD-PROCESSING-FRAME (indexed as received): ");
}
final Reducer reducer = new Reducer(voxelSize);
final List collisions = lookForCollisions(reducer, createMotions());
int numberOfCollisions = collisions.size();
if (ImmortalEntry.recordedRuns < ImmortalEntry.maxDetectorRuns) {
ImmortalEntry.detectedCollisions[ ImmortalEntry.recordedRuns ] = numberOfCollisions;
}
if (Constants.SYNCHRONOUS_DETECTOR || Constants.DEBUG_DETECTOR) {
System.out.println("CD detected "+numberOfCollisions+" collisions.");
int colIndex = 0;
for(final Iterator iter = collisions.iterator(); iter.hasNext();) {
Collision col = (Collision) iter.next();
List aircraft = col.getAircraftInvolved();
System.out.println("CD collision "+colIndex+" occured at location "+col.getLocation() + " with "+aircraft.size()+" involved aircraft.");
for(final Iterator aiter = aircraft.iterator(); aiter.hasNext();) {
Aircraft a = (Aircraft) aiter.next();
System.out.println("CD collision "+colIndex+" includes aircraft "+a);
}
colIndex++;
}
System.out.println("");
}
/*
if (Constants.SYNCHRONOUS_DETECTOR) {
FrameSynchronizer.consumeFrame();
}
*/
}
public List lookForCollisions(final Reducer reducer, final List motions) {
final List check = reduceCollisionSet(reducer, motions);
final CollisionCollector c = new CollisionCollector();
int suspectedSize = check.size();
if (ImmortalEntry.recordedRuns < ImmortalEntry.maxDetectorRuns) {
ImmortalEntry.suspectedCollisions[ ImmortalEntry.recordedRuns ] = suspectedSize;
}
if ((Constants.SYNCHRONOUS_DETECTOR || Constants.DEBUG_DETECTOR) && !check.isEmpty()) {
System.out.println("CD found "+suspectedSize+" potential collisions");
int i=0;
for(final Iterator iter = check.iterator(); iter.hasNext();) {
final List col = (List)iter.next();
for(final Iterator aiter = col.iterator(); aiter.hasNext();) {
final Motion m = (Motion)aiter.next();
System.out.println("CD: potential collision "+i+" (of "+col.size()+" aircraft) includes motion "+m);
}
i++;
}
}
for (final Iterator iter = check.iterator(); iter.hasNext();)
c.addCollisions(determineCollisions((List) iter.next()));
return c.getCollisions();
}
/**
* Takes a List of Motions and returns an List of Lists of Motions, where the inner lists implement RandomAccess.
* Each Vector of Motions that is returned represents a set of Motions that might have collisions.
*/
public List reduceCollisionSet(final Reducer it, final List motions) {
final HashMap voxel_map = new HashMap();
final HashMap graph_colors = new HashMap();
for (final Iterator iter = motions.iterator(); iter.hasNext();)
it.performVoxelHashing((Motion) iter.next(), voxel_map, graph_colors);
final List ret = new LinkedList();
for (final Iterator iter = voxel_map.values().iterator(); iter.hasNext();) {
final List cur_set = (List) iter.next();
if (cur_set.size() > 1) ret.add(cur_set);
}
return ret;
}
public List determineCollisions(final List motions) {
final List ret = new LinkedList();
for (int i = 0; i < motions.size() - 1; i++) {
final Motion one = (Motion) motions.get(i);
for (int j = i + 1; j < motions.size(); j++) {
final Motion two = (Motion) motions.get(j);
final Vector3d vec = one.findIntersection(two);
if (vec != null) ret.add(new Collision(one.getAircraft(), two.getAircraft(), vec));
}
}
return ret;
}
public void dumpFrame( String debugPrefix ) {
String prefix = debugPrefix + frameno + " ";
int offset = 0;
for (int i=0;i<currentFrame.planeCnt;i++) {
int cslen = currentFrame.lengths[i];
System.out.println(prefix+new String( currentFrame.callsigns, offset, cslen )+" "+
currentFrame.positions[3*i]+" "+
currentFrame.positions[3*i+1]+" "+
currentFrame.positions[3*i+2]+" ");
offset += cslen;
}
}
int frameno=-1; // just for debug
public void setFrame(final RawFrame f) {
if (Constants.DEBUG_DETECTOR || Constants.DUMP_RECEIVED_FRAMES || Constants.SYNCHRONOUS_DETECTOR) {
frameno++;
}
currentFrame = f;
if (Constants.DUMP_RECEIVED_FRAMES) {
dumpFrame( "CD-R-FRAME: ");
}
}
/**
*
* This method computes the motions and current positions of the aircraft
*
* Afterwards, it stores the positions of the aircrafts into the StateTable in the persistentScope
*
* @return
*/
public List createMotions() {
final List ret = new LinkedList();
final HashSet poked = new HashSet();
Aircraft craft;
Vector3d new_pos;
for (int i = 0, pos = 0; i < currentFrame.planeCnt; i++) {
final float x = currentFrame.positions[3*i], y = currentFrame.positions[3*i + 1], z = currentFrame.positions[3*i + 2];
final byte[] cs = new byte[currentFrame.lengths[i]];
for (int j = 0; j < cs.length; j++)
cs[j] = currentFrame.callsigns[pos + j];
pos += cs.length;
craft = new Aircraft(cs);
new_pos = new Vector3d(x, y, z);
poked.add(craft);
// get the last known position of this aircraft
final Vector3d old_pos = state.get(mkCallsignInPersistentScope(craft.getCallsign()));
if (old_pos == null) {
// Ales : we have detected a new aircraft
//here, we create a new callsign and store the aircraft into the state table.
state.put(mkCallsignInPersistentScope(craft.getCallsign()), new_pos.x, new_pos.y, new_pos.z);
final Motion m = new Motion(craft, new_pos);
if (Constants.DEBUG_DETECTOR || Constants.SYNCHRONOUS_DETECTOR) {
System.out.println("createMotions: old position is null, adding motion: " + m);
}
ret.add(m);
} else {
// this is already detected aircraft, we we need to update its position
final Vector3d save_old_position = new Vector3d(old_pos.x, old_pos.y, old_pos.z);
//updating position in the StateTable
old_pos.set(new_pos.x, new_pos.y, new_pos.z);
final Motion m = new Motion(craft, save_old_position, new_pos);
if (Constants.DEBUG_DETECTOR || Constants.SYNCHRONOUS_DETECTOR) {
System.out.println("createMotions: adding motion: " + m);
}
ret.add(m);
}
}
return ret;
}
/**
*
* This Runnable enters the StateTable in order to allocate the callsign in the PersistentScope
*
*
* @author Ales
*
*/
static class R implements Runnable {
CallSign c;
byte[] cs;
public void run() {
final byte[] b = new byte[cs.length];
for (int i = 0; i < b.length; i++)
b[i] = cs[i];
c = new CallSign(b);
}
}
private final R r = new R();
CallSign mkCallsignInPersistentScope(final byte[] cs) {
r.cs = cs;
//MemoryArea.getMemoryArea(state).executeInArea(r);
r.run();
return r.c;
}
}