23#define ASTAR_ALLOW_XOVER false
32 NavPointRef(
NavPoint *nav,
float v) : mPoint(nav), mKey(nav->getScore() + v) { }
33 NavPoint *getPoint()
const {
return mPoint; }
34 NavPoint *operator->()
const {
return mPoint; }
35 bool operator<(
const NavPointRef &that)
const {
return mKey >= that.mKey; }
43 constexpr static const float mTurnCostPer45Degrees = 1.0f / 1024.0f;
48 const std::vector<Point_25>& violations()
const {
return mViolationLocs; }
53 std::vector<float> mLayerCost;
54 uint16_t mRouteMask{NAV_POINT_FLAGS_TRACKS_BLOCKED};
59 std::vector<Point_25> mViolationLocs;
62 int getApproxBlockageSearchArea(
const Pin *)
const;
63 int _search(
NavPoint *source,
int maxVisits);
65 void initEndPoint(
const Point_2&,
int z[2],
bool dst,
bool save);
66 void finiEndPoint(
const Point_2&,
int z[2]);
68 void addViolation(
const NavPoint *, Real radius);
72 void writePoint(
const Point_25&, uint16_t add, uint16_t clr,
bool save);
77AStar::AStar(
NavGrid &nav,
const AStarCosts &costs) : mNav(nav), mCostParams(costs)
84inline void AStar::writePoint(
const Point_25 &v, uint16_t add, uint16_t clr,
bool save)
86 NavPoint *x = mNav.getPoint(v);
92inline void AStar::initEndPoint(
const Point_2 &v,
int Z[2],
bool dst,
bool save)
94 const uint w = dst ? NAV_POINT_FLAG_TARGET : NAV_POINT_FLAG_SOURCE;
95 const uint m = dst ? NAV_POINT_FLAG_SOURCE : NAV_POINT_FLAG_TARGET;
97 const uint u = (Z[0] == Z[1]) ? NAV_POINT_FLAGS_TRACK_CLEARANCE : NAV_POINT_FLAGS_CLEARANCE;
98 for (
int z = Z[0]; z <= Z[1]; ++z)
99 writePoint(Point_25(v, z), w, NAV_POINT_FLAG_BLOCKED_TEMPORARY | u | m, save);
105inline void AStar::finiEndPoint(
const Point_2 &v,
int Z[2])
107 for (
int z = Z[0]; z <= Z[1]; ++z)
108 mNav.getPoint(v, z)->restoreFlags();
111float AStar::heuristic(
const NavPoint &A)
114 float d = geo::distance45(A.getRefPoint(&mNav), mTargetXY);
117 if (A.getLayer() < mTargetZ[0])
118 dz = mTargetZ[0] - A.getLayer();
119 else if (A.getLayer() > mTargetZ[1])
120 dz = A.getLayer() - mTargetZ[1];
122 if (!A.getBackDirection().isVertical())
124 d += mViaCost * 0.5f * dz;
136 std::lock_guard wlock(mNav.getPCB().getLock());
138 assert(!route.hasTracks() && !route.isRouted());
140 const NavPoint *head = mTarget;
141 for (
auto next = head->getBackEdge(mNav); next->hasFlags(NAV_POINT_FLAG_TARGET); next = next->getBackEdge(mNav))
143 Track *T = route.newTrack(head->getRefPoint25(&mNav));
144 const NavPoint *node = head;
145 DEBUG(
"AStar " << node->str(&mNav));
146 GridDirection d = node->getBackDirection();
147 while (!node->hasFlags(NAV_POINT_FLAG_SOURCE)) {
148 node = node->getBackEdge(mNav);
149 if (!node->canRoute())
150 addViolation(node, T->defaultWidth());
151 DEBUG(
"AStar " << node->str(&mNav));
152 if (node->getBackDirection() == d && node->getLayer() == head->getLayer() && !node->hasFlags(NAV_POINT_FLAG_SOURCE))
155 T->_append(head->getSegmentTo(*node, &mNav));
157 d = node->getBackDirection();
159 assert(head == node);
160 T->_setEnd(node->getRefPoint25(&mNav));
162 T->autocreateVias(T->end() == node->getRefPoint25(&mNav) ? T->end() : route.target());
167void AStar::addViolation(
const NavPoint *node, Real radius)
169 const auto v = node->getRefPoint25(&mNav);
170 if (mViolationLocs.empty() ||
171 mViolationLocs.back().z() != v.z() ||
172 CGAL::squared_distance(v.xy(), mViolationLocs.back().xy()) > radius)
173 mViolationLocs.push_back(v);
176int AStar::getApproxBlockageSearchArea(
const Pin *T)
const
178 const auto e = mNav.EdgeLen;
181 const int nx = int((T->getBbox().xmax() - T->getBbox().xmin() + e) / e);
182 const int ny = int((T->getBbox().xmax() - T->getBbox().xmin() + e) / e);
183 const int nA = nx * ny;
184 return std::max(384, std::min(nA * 8, 1024));
189 auto moveCost = dst->getCost(0);
192 if (dst->hasFlags(NAV_POINT_FLAG_SOURCE))
195 if (d.isVertical()) {
196 moveCost *= mViaCost;
198 if (src->getBackDirection().isVertical())
201 moveCost *= mLayerCost[dst->getLayer()];
203 moveCost *= std::sqrt(2.0f);
204 if (dst->hasFlags(NAV_POINT_FLAG_ROUTE_TRACK_CLEARANCE))
205 moveCost *= mViolationCost;
206 moveCost += mTurnCostPer45Degrees * math::squared(d.opposite().get45DegreeStepsBetween(src->getBackDirection()));
213 auto e = ref->getEdge(mNav, d);
214 return (e && !e->hasFlags(mRouteMask)) ? e : 0;
218 if (!ref->canPlaceVia())
220 auto e = ref->getEdge(mNav, d);
221 return (e && ref->canAddVia(*e)) ? e : 0;
224#define PERF_COUNTER_T(i) auto __t##i = std::chrono::high_resolution_clock::now()
225#define PERF_COUNTER_D(a, b) std::chrono::duration_cast<std::chrono::nanoseconds>(__t##b - __t##a).count()
229 DEBUG(
"A* from " << route.source() <<
" to " << route.target());
231 if (route.hasTracks() || route.isRouted())
232 throw std::runtime_error(
"Connection pass to A* must have an empty track.");
235 auto target = mNav.getPoint(route.source());
236 auto source = mNav.getPoint(route.target());
237 if (!target || !source || source == target)
243 sourceZ[0] = route.targetPin() ? route.targetPin()->minLayer() : source->getLayer();
244 targetZ[0] = route.sourcePin() ? route.sourcePin()->minLayer() : target->getLayer();
245 sourceZ[1] = route.targetPin() ? route.targetPin()->maxLayer() : source->getLayer();
246 targetZ[1] = route.sourcePin() ? route.sourcePin()->maxLayer() : target->getLayer();
249 initEndPoint(target->getRefPoint(&mNav), targetZ, 0,
true);
250 initEndPoint(source->getRefPoint(&mNav), sourceZ, 1,
true);
251 auto rv = _search(target, source, getApproxBlockageSearchArea(route.sourcePin()));
253 initEndPoint(source->getRefPoint(&mNav), sourceZ, 0,
false);
254 initEndPoint(target->getRefPoint(&mNav), targetZ, 1,
false);
255 rv = _search(source, target, std::numeric_limits<int>::max());
257 DEBUG(
"A* " << ((rv > 0) ?
"finished" :
"failed") <<
" after " << ((rv > 0) ? (std::numeric_limits<int>::max() - rv) : -rv) <<
" nodes.");
259 auto ret = (rv > 0) && reconstruct(route);
261 std::lock_guard wlock(mNav.getPCB().getLock());
264 finiEndPoint(source->getRefPoint(&mNav), sourceZ);
265 finiEndPoint(target->getRefPoint(&mNav), targetZ);
270 assert(source && target && source != target);
271 mTargetXY = target->getRefPoint(&mNav);
272 mSourceXY = source->getRefPoint(&mNav);
273 return _search(source, maxVisits);
275int AStar::_search(
NavPoint *source,
int maxVisits)
277 const uint seq = mNav.nextSearchSeq();
280 source->setBackDirection(GridDirection::Z().n());
281 source->getVisits().setOpen(seq);
283 std::priority_queue<NavPointRef> openList;
284 openList.push(NavPointRef(source, heuristic(*source)));
285 while (!openList.empty()) {
286 auto current = openList.top().getPoint();
288 if (!current->getVisits().isOpen(seq))
290 if (current->hasFlags(NAV_POINT_FLAG_TARGET)) {
296 current->getVisits().setDone(seq);
305 NavPoint *edges[GridDirection::Count];
306 edges[GridDirection::U().n()] = checkHEdge(current, GridDirection::U());
307 edges[GridDirection::D().n()] = checkHEdge(current, GridDirection::D());
308 edges[GridDirection::L().n()] = checkHEdge(current, GridDirection::L());
309 edges[GridDirection::R().n()] = checkHEdge(current, GridDirection::R());
310 edges[GridDirection::UR().n()] = ((edges[GridDirection::U().n()] && edges[GridDirection::R().n()]) || ASTAR_ALLOW_XOVER) ? checkHEdge(current, GridDirection::UR()) : 0;
311 edges[GridDirection::DR().n()] = ((edges[GridDirection::D().n()] && edges[GridDirection::R().n()]) || ASTAR_ALLOW_XOVER) ? checkHEdge(current, GridDirection::DR()) : 0;
312 edges[GridDirection::DL().n()] = ((edges[GridDirection::D().n()] && edges[GridDirection::L().n()]) || ASTAR_ALLOW_XOVER) ? checkHEdge(current, GridDirection::DL()) : 0;
313 edges[GridDirection::UL().n()] = ((edges[GridDirection::U().n()] && edges[GridDirection::L().n()]) || ASTAR_ALLOW_XOVER) ? checkHEdge(current, GridDirection::UL()) : 0;
314 edges[GridDirection::A().n()] = checkVEdge(current, GridDirection::A());
315 edges[GridDirection::V().n()] = checkVEdge(current, GridDirection::V());
316 const auto backd = current->getBackDirection();
318 edges[backd.n()] = 0;
320 edges[backd.rotatedCcw45().n()] = 0;
321 edges[backd.rotatedCw45().n()] = 0;
324 for (
auto d = GridDirection::begin(); d != (current->canPlaceVia() ? GridDirection::vend() : GridDirection::hend()); ++d) {
325 NavPoint *node = edges[d.n()];
328 const auto score = current->getScore() + computeCost(current, node, d);
329 if (node->getVisits().isSeen(seq) && score >= node->getScore())
331 node->setBackDirection(d.opposite());
332 node->setScore(score);
333 node->getVisits().setOpen(seq);
334 openList.push(NavPointRef(node, heuristic(*node)));
337 mNav.getPCB().setChanged(PCB_CHANGED_NAV_GRID);
338 UserSettings::get().sleepForActionDelay();
346 assert(mCostParams.valid());
347 const uint dirMask = (!X.hasNet() || !X.net()->isGroundOrPower()) ? 0x1 : 0x0;
349 mLayerCost.resize(mNav.getSize(2), 0.0f);
350 for (uint z = 0; z < mLayerCost.size(); ++z) {
351 if (!X.canRouteOnLayer(z))
352 mLayerCost[z] = mCostParams.MaskedLayer;
353 else if (z & dirMask)
354 mLayerCost[z] = mCostParams.WrongDirection;
356 mLayerCost[z] = 1.0f;
358 mViaCost = mCostParams.Via * X.defaultViaDiameter();
359 mViolationCost = mCostParams.Violation;
361 if (std::isinf(mCostParams.Violation))
362 mRouteMask |= NAV_POINT_FLAG_ROUTE_TRACK_CLEARANCE;
364 mRouteMask &= ~NAV_POINT_FLAG_ROUTE_TRACK_CLEARANCE;
Definition Connection.hpp:17
Definition GridDirection.hpp:6
The grid-representation of the board.
Definition NavGrid.hpp:61
Definition NavPoint.hpp:116
Definition Geometry.hpp:131
Definition NavGrid.hpp:47