9#include <simgear/debug/logstream.hxx>
10#include <simgear/math/SGGeod.hxx>
20 double w = max.getLatitudeDeg() - min.getLatitudeDeg();
21 double h = max.getLongitudeDeg() - min.getLongitudeDeg();
24 index.resize(SGRect<double>(min.getLatitudeDeg(), min.getLongitudeDeg(), w, h));
28 double INDEX_SIZE_DEG = 1;
29 double minLat = airport->getLatitude() - INDEX_SIZE_DEG/2;
30 double minLon = airport->getLongitude() - INDEX_SIZE_DEG/2;
31 SG_LOG(SG_ATC, SG_DEBUG,
"Creating AirportGroundRadar for " << airport->getId());
32 AirportGroundRadar::airport = airport;
33 index.resize(SGRect<double>(minLat, minLon, INDEX_SIZE_DEG, INDEX_SIZE_DEG));
40 bool ret = index.add(aiObject);
42 SG_LOG(SG_ATC, SG_DEBUG,
"Added Aircraft " << aiObject->getCallsign() <<
"(" << aiObject->getId() <<
")" <<
" Leg : " << aiObject->getLeg() <<
" " << aiObject->getPos() );
45 double distM = SGGeodesy::distanceM(aiObject->getPos(), airport->geod());
46 SG_LOG(SG_ATC, SG_ALERT,
"Couldn't add Aircraft " << aiObject->getCallsign() <<
"(" << aiObject->getId() <<
") to " << airport->getId() <<
" Dist " << distM <<
"m Leg " << aiObject->getLeg() );
53 bool ret = index.move(newPos, aiObject);
55 SG_LOG(SG_ATC, SG_DEBUG,
"Couldn't move Aircraft " << aiObject->getCallsign() <<
"(" << aiObject->getId() <<
") to " << airport->getId() <<
" Leg " << aiObject->getLeg() );
63 SG_LOG(SG_ATC, SG_ALERT,
"Couldn't remove aiObject null" );
67 bool ret = index.remove(aiObject);
69 SG_LOG(SG_ATC, SG_DEV_ALERT,
"Couldn't remove " << aiObject->getCallsign() <<
"(" << aiObject->getId() <<
")");
71 SG_LOG(SG_ATC, SG_DEBUG,
"Removed Aircraft " << aiObject->getCallsign() <<
"(" << aiObject->getId() <<
")");
79 int speedCorrection = (*aiObject).getSpeed()!=0?std::abs(5*(*aiObject).getSpeed()):20;
80 return std::abs((*aiObject).getRadius() + speedCorrection);
85 const double courseTowardOther = SGGeodesy::courseDeg(aiObject->getPos(), other->getPos());
86 const double turningRate = aiObject->getHeadingDiff();
88 const double distM = SGGeodesy::distanceM(aiObject->getPos(), other->getPos());
89 const double headingDiff = SGMiscd::normalizePeriodic(-180, 180, aiObject->getHeading() - courseTowardOther - turningRate);
90 const double otherHeadingDiff = SGMiscd::normalizePeriodic(-180, 180, other->getHeading() - courseTowardOther);
91 const double threshold = getSize(aiObject) + getSize(other);
92 SG_LOG(SG_ATC, SG_BULK,
"Search Id : " << aiObject->getId() <<
" Found Id : " << other->getId() <<
" Dist \t" << distM <<
"m Threshold " << threshold <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff <<
" courseTowardOther " << courseTowardOther <<
" Turning " << aiObject->getHeadingDiff() <<
" Speeds : " << aiObject->getSpeed() <<
"/" << other->getSpeed() <<
" " << (other->getSpeed() == 0 ?
"Other Stopped" :
""));
94 && aiObject->getSpeed() >= 0 &&
abs(headingDiff) < 90
95 &&
abs(otherHeadingDiff) > 90
98 SG_LOG(SG_ATC, SG_BULK, aiObject->getId() <<
" blocked by " << other->getId() <<
" Dist " << distM <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff);
101 if (aiObject->getSpeed() < 0 &&
abs(headingDiff) > 90) {
103 SG_LOG(SG_ATC, SG_BULK, aiObject->getId() <<
" blocked reversing by " << other->getId() <<
" Dist " << distM <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff);
106 if (other->getSpeed() == 0 &&
abs(headingDiff) < 20 &&
abs(otherHeadingDiff) > 90) {
108 SG_LOG(SG_ATC, SG_WARN, aiObject->getId() <<
" blocked by stopped opposing " << other->getId() <<
" Dist " << distM <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff);
111 if (other->getSpeed() >= 0 &&
abs(headingDiff) < 20 &&
abs(otherHeadingDiff) < 30) {
113 SG_LOG(SG_ATC, SG_BULK, aiObject->getId() <<
" blocked by stopped pointing away" << other->getId() <<
" Dist " << distM <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff);
121 auto values = std::vector<FGTrafficRef>();
122 const SGRectd queryBox(aiObject->getPos().getLatitudeDeg()-QUERY_BOX_SIZE/2,
123 aiObject->getPos().getLongitudeDeg()-QUERY_BOX_SIZE/2,
126 SG_LOG(SG_ATC, SG_BULK,
"Rect : ( " << queryBox.x() <<
"," << queryBox.y() <<
"x" << queryBox.width() <<
"," << queryBox.height() <<
")");
127 index.query(queryBox, values);
128 SG_LOG(SG_ATC, SG_BULK,
"Search Id : " << aiObject->getCallsign() <<
"(" << aiObject->getId() <<
") Index Size : " << index.size() <<
" Result Size : " << values.size() );
130 double distM = SGGeodesy::distanceM(aiObject->getPos(), other->getPos());
131 if (other->getId()!=aiObject->getId()){
133 const double courseTowardOther = SGGeodesy::courseDeg(aiObject->getPos(), other->getPos());
135 const double headingDiff = SGMiscd::normalizePeriodic(-180, 180, aiObject->getHeading() - courseTowardOther);
136 const double otherHeadingDiff = SGMiscd::normalizePeriodic(-180, 180, other->getHeading() - courseTowardOther);
137 SG_LOG(SG_ATC, SG_BULK,
"Found " << other->getCallsign() <<
"(" << other->getId() <<
") " << other->getPos().getLatitudeDeg() << other->getPos().getLongitudeDeg() <<
"Dist " << distM <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff <<
" courseTowardOther " << courseTowardOther);
138 const int threshold = getSize(aiObject) + getSize(other) + SEPARATION;
139 if ( distM < threshold ) {
140 if (headingDiff < 0 && aiObject->getSpeed() > 0 && abs(headingDiff) < 90){
142 SG_LOG(SG_ATC, SG_BULK, aiObject->getId() <<
" blocked by " << other->getId() <<
" Dist " << distM <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff <<
" Heading " << aiObject->getHeading() <<
" Other Heading " << other->getHeading());
145 if (headingDiff < 0 && aiObject->getSpeed() < 0 && abs(headingDiff) > 90){
147 SG_LOG(SG_ATC, SG_BULK, aiObject->getId() <<
" blocked by " << other->getId() <<
" while reversing Dist " << distM <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff);
150 if (other->getSpeed() == 0 && abs(headingDiff) < 5) {
152 SG_LOG(SG_ATC, SG_BULK, aiObject->getId() <<
" blocked by stopped " << other->getId() <<
" Dist " << distM <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff);
159 SG_LOG(SG_ATC, SG_ALERT, aiObject->getCallsign() <<
"(" << aiObject->getId() <<
") is not near it's shadow in index " << other->getId() <<
" Dist " << distM );
173 auto values = std::vector<FGTrafficRef>();
174 const SGRectd queryBox(aiObject->getPos().getLatitudeDeg()-QUERY_BOX_SIZE/2,
175 aiObject->getPos().getLongitudeDeg()-QUERY_BOX_SIZE/2,
178 SG_LOG(SG_ATC, SG_BULK,
"Rect : ( " << queryBox.x() <<
"," << queryBox.y() <<
"x" << queryBox.width() <<
"," << queryBox.height() <<
")");
179 index.query(queryBox, values);
180 SG_LOG(SG_ATC, SG_BULK,
"Search Id : " << aiObject->getId() <<
" Index Size : " << index.size() <<
" Result Size : " << values.size() );
182 if (other->getId()!=aiObject->getId()){
183 double distM = SGGeodesy::distanceM(aiObject->getPos(), other->getPos());
185 const double courseTowardOther = SGGeodesy::courseDeg(aiObject->getPos(), other->getPos());
187 const double headingDiff = SGMiscd::normalizePeriodic(-180, 180, aiObject->getHeading() - courseTowardOther);
188 const double otherHeadingDiff = SGMiscd::normalizePeriodic(-180, 180, other->getHeading() - courseTowardOther);
191 const int threshold = 2 * getSize(aiObject) + 2 * getSize(other) + SEPARATION;
192 SG_LOG(SG_ATC, SG_BULK,
"Search Id : " << aiObject->getId() <<
" Found Id : " << other->getId() <<
" Dist \t" << distM <<
"m Threshold " << threshold <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff <<
" courseTowardOther " << courseTowardOther <<
" Turning " << aiObject->getHeadingDiff() <<
" Speeds : " << aiObject->getSpeed() <<
"/" << other->getSpeed() <<
" " << (other->getSpeed()==0?
"Other Stopped":
""));
194 if ( distM < threshold && (abs(headingDiff) > 135) ){
196 SG_LOG(SG_ATC, SG_BULK, aiObject->getCallsign() <<
"(" << aiObject->getId() <<
") blocked for pushback by " << other->getCallsign() <<
"(" << other->getId() <<
")");
206 auto values = std::vector<FGTrafficRef>();
207 const SGRectd queryBox(aiObject->getPos().getLatitudeDeg()-QUERY_BOX_SIZE/2,
208 aiObject->getPos().getLongitudeDeg()-QUERY_BOX_SIZE/2,
211 SG_LOG(SG_ATC, SG_BULK,
"Rect : ( " << queryBox.x() <<
"," << queryBox.y() <<
"x" << queryBox.width() <<
"," << queryBox.height() <<
")");
212 index.query(queryBox, values);
213 SG_LOG(SG_ATC, SG_BULK,
"Search Id : " << aiObject->getId() <<
" Index Size : " << index.size() <<
" Result Size : " << values.size() );
215 double nearestDist = HUGE_VAL;
217 double distM = SGGeodesy::distanceM(aiObject->getPos(), other->getPos());
218 const double threshold = getSize(aiObject) + getSize(other);
219 if (other->getId() != aiObject->getId()) {
220 if (distM < 20 && aiObject->getSpeed() != 0) {
221 const double courseTowardOther = SGGeodesy::courseDeg(aiObject->getPos(), other->getPos());
222 const double headingDiff = SGMiscd::normalizePeriodic(-180, 180, aiObject->getHeading() - courseTowardOther);
223 const double otherHeadingDiff = SGMiscd::normalizePeriodic(-180, 180, other->getHeading() - courseTowardOther);
225 SG_LOG(SG_ATC, SG_ALERT, aiObject->getCallsign() <<
"(" << aiObject->getId() <<
") running into " << other->getCallsign() <<
"(" << other->getId() <<
") Dist " << distM <<
" Heading " << aiObject->getHeading() <<
" Other Heading " << other->getHeading() <<
" Headingdiff " << headingDiff <<
" Other heading diff " << otherHeadingDiff <<
" courseTowardOther " << courseTowardOther <<
" Speeds : " << aiObject->getSpeed() <<
"/" << other->getSpeed() <<
" Turning: " << aiObject->getHeadingDiff() <<
" Legs: " << aiObject->getLeg() <<
"/" << other->getLeg() <<
" Threshold : " << threshold <<
" = " << getSize(aiObject) <<
" + " << getSize(other));
226 if (aiObject->getAircraft() !=
nullptr && other->getAircraft() !=
nullptr) {
227 SG_LOG(SG_ATC, SG_ALERT,
"Offending type " << aiObject->getAircraft()->getAcType() <<
" " << aiObject->getAircraft()->getCompany() <<
" " << aiObject->getAircraft()->getPerformance()->decelerationOnGround());
228 SG_LOG(SG_ATC, SG_ALERT,
"Speeds " << aiObject->getSpeed() <<
" " << other->getAircraft()->getSpeed());
231 if (distM < threshold && distM < nearestDist) {
232 if (blocking(aiObject, other)) {
234 nearestTrafficRecord = other;
239 SG_LOG(SG_ATC, SG_ALERT, aiObject->getCallsign() <<
"(" << aiObject->getId() <<
") is not near it's shadow in index Leg : " << aiObject->getLeg() <<
"/" << other->getLeg() <<
" Dist " << distM);
243 return nearestTrafficRecord;
SGSharedPtr< FGTrafficRecord > FGTrafficRef
SGSharedPtr< FGAirport > FGAirportRef
bool remove(FGTrafficRef aiObject)
bool isBlockedForPushback(FGTrafficRef aiObject)
Check if the aircraft could push back.
bool add(FGTrafficRef aiObject)
bool move(const SGRectd &newPos, FGTrafficRef aiObject)
static SGRect< double > getBox(FGTrafficRef aiObject)
Function implementing calculation of dimension for Quadtree.
static bool equal(FGTrafficRef o, FGTrafficRef o2)
Function implementing equals for Quadtree.
const FGTrafficRef getBlockedBy(FGTrafficRef aiObject)
Returns which AI object is blocking this traffic.
bool isBlocked(FGTrafficRef aiObject)
Returns if this AI object is blocked by any other "known" aka visible to the Radar.
AirportGroundRadar(SGGeod min, SGGeod max)