During precomputation, we store the minimal cellrays by target and sort them according to niceness.
find_ray now simply picks the first non-blocked ray to a target, which means looping through the 10 or so minimal cellrays with that target – this should be a lot more efficient. (An extended findray test went from 150s to 40s (debug) and 40s to 26s (profile)).
The interface to find_ray has changed: cycle_dir=-1,0,1 was changed to cyle=false/true since we never cycle in the other direction anyway. find_shortest was removed: all rays to a target had the same length all along, but now we also return the straightest one automatically.
The change also eliminates the duplicate corner-cutting code between ray_def::advance and find_ray as imbalance calculation now relies on ray_def::advance.
DTLSPUE47XI4YC3QWKTBWJOWBU52GXPGXFEEBG374I4JAYVM7KZAC BLJ6YULKT57MKKU3KUKMS7HITS2CDUFPZ4U6EQHBGLGQ7O7GUSLAC 3MCIHHM7HEXQPZHF2MZBUV3STJHRMVSUTWENFM3KUYIQXI5FJ2GAC 6KANK4BOEJYMBUWOZURH57BZJ52YJRGBXN4TMKO27B3JFIP6MHSQC IFYZSFWJRTV6JM46H6U4CMTQX46VT562EAM64Y6UYU3F6RDWRRYQC TZNURHCLTLE3A55EPNU66BU6NX7LOBA7EFG4NAJJBUKZLOAEFU4AC KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC QNDI5MFPHZZXZOJFF2IELF2LIHWVY2HGFRCJWYEFN4WL4ICYZUYQC 5X6QOOUFVHPEEHOSLZ5RUTNRD5LH4BSGIIFWNEDJJBVJJNM7MBZQC 4FBWCGO5NTT2KBBTYTYVR2AOBI5LHSP7L3TB3ESYF6OFLMEJQESQC ACZYEIX7WMPIIODKCATBCUE626AJ4ZGGBOMVC6BGXM27EQU2RECAC B5ED3LZM7H6NMC7HBVUWKE4AODTQSKF4EOKZ7KZBZVOCGBZ3XMGQC YGPAMROCZY2O2N4PJONW6NMFUNOFHAGT5ZA4APCXKFXQUHLEIN2AC WY3Q6JZ3HTBF2CYFJOUVG4MMFINBK4PI2DJ625CVKMJ5BPMXAW2AC UFMQQPYCBI6Z576P7PH4ZAPC7L7P3D4H66NJMFQKP6WRAPIK2NOQC W2JKSN3BG7JHORONWK6J53OOEJ3EBVKY5QTBG4ITNVORLWRZNU5QC ZJBFGI5FGCP7WGFKEUTLWZK4ATGB35Q4I5IB4BKJTHVKS2HDR5LQC 5KZF63OICCGFAZ5E3TRS5GKZJLKQYWLGKOA7IYV4X3C6AOXB4MMAC ICVDXXH2Z5MV7BLYVWQNLQSV63THIB4E6NVORIDBB7D6TBEHBXOAC MRKWHW7QPSB7BBOLKP5OZTYKAARQGLSQCOEFKGS64JK5BAODT5OQC KMF52RF3NIY2ABMHEZABT3GOG3KCHEJD55NBJ3IPAOHBKF2WPKQAC QY27OCPL2PEW4TRTMKEOK2IJRQFUQX2A2YF2FHEFI52EE7WU43CQC STVGTZVV4C2DWFZTJS5MSXCG7CALIDQXUXQITH2IP3U75LBVLKRQC 3ORZZ66JXYWJUO4W5YP2JRKKZ6ZNMHU7QWAF2QMKH4LFWNNMPM7QC PEWNWU7TD3LETUMWCCI365KH7PVV2XCUOIFTPBH2LK2ZPGS4URZAC PHJ2TT2CQ2IRXOB5KAV2664KKTPYFPFUIBEGAOQBGB4SAZ7PKNHAC DUUH7Q4YH3XJUQDOCWBCGRPVJAOJBENZ2B3LR5N6ALZRPRELAI4AC 2MVY3CA2SGUEQDDHIFOLAJ7N532M4ZYZT7LSCPWZR7VKPMRX2CQAC T7CCGLOZ25B7BQKKGR6IA6LWBRKUWTXLTIRXUQ4YKQRVAA7AHZKQC JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC XCL4GC6RUWUK57HONM5CRUEOCCECR4NYAI5KLPJKCYM5OURU3AYQC VD4KDTGHVKCN35AWREYB4TEOUMCTW7SAUPAMTMF5ABC7VBHVKP4AC ASLW3Z5PAVZSWJEMMMVZT226P44EKSAD47QS72JIFJESAI3RPN3AC DDYDJKL5CGSTC3NGTOBCNKHDTG5LX5F4U7VNZN2YAK5ANLT7UO5AC 6DNNPEMZGBQDMA7YG4LCTQUVZ7LYPC3R4A2XBYT5SDQ65GYOLJVAC cellray(const los_ray& r, int l) : ray(r), length(l) {}
cellray(const los_ray& r, unsigned int e): ray(r), end(e), imbalance(-1), slope_diff(-1){}// The end-point's index inside ray_coord.int index() const { return (ray.start + end); }// The end-point.coord_def target() const { return ray_coords[index()]; }
int index() const { return ray.start + length; }coord_def end() const { return ray_coords[index()]; }
// XXX: Currently ray/cellray[0] is the first point outside the origin.coord_def operator[](unsigned int i){ASSERT(0 <= i && i <= end);return ray_coords[ray.start+i];}// Parameters used in find_ray. These need to be calculated// only for the minimal cellrays.int imbalance;double slope_diff;void calc_params();
// Compare two cellrays to the same target.// This determines which ray is considered better by find_ray,// used with list::sort.// Returns true if a is strictly better than b, false else.bool _is_better(const cellray& a, const cellray& b){// Only compare cellrays with equal target.ASSERT(a.target() == b.target());// calc_params() has been called.ASSERT(a.imbalance >= 0 && b.imbalance >= 0);if (a.imbalance < b.imbalance)return (true);else if (a.imbalance > b.imbalance)return (false);elsereturn (a.slope_diff < b.slope_diff);}
for (min_it = minima(*qi).begin(); min_it != minima(*qi).end(); min_it++)
{std::list<cellray>& min = minima(*qi);for (min_it = min.begin(); min_it != min.end(); min_it++){// Calculate imbalance and slope difference for sorting.min_it->calc_params();
// Determine nonduplicated rays and store their end points.std::vector<int> min_cellrays = _find_minimal_cellrays();const int n_min_rays = min_cellrays.size();
// Determine minimal cellrays and store their indices in ray_coords.std::vector<int> min_indices = _find_minimal_cellrays();const int n_min_rays = min_indices.size();
}static int _cyclic_offset(int i, int cycle_dir, int startpoint,int maxvalue){if (startpoint < 0)return i;switch (cycle_dir){case 1:return (i + startpoint + 1) % maxvalue;case -1:return (i - 1 - startpoint + maxvalue) % maxvalue;case 0:default:return i;}
}static bool _superior_ray(int imbalance, int rayimbalance,double slope_diff, double ray_slope_diff){if (imbalance != rayimbalance)return (imbalance > rayimbalance);return (slope_diff > ray_slope_diff);
// Compute the imbalance, defined as the// number of consecutive diagonal or orthogonal moves// in the ray. This is a reasonable measure of deviation from// the Bresenham line between our selected source and// destination.static int _imbalance(const std::vector<coord_def>& ray)
static int _imbalance(ray_def ray, const coord_def& target)
bool found = false;int imbalance = INFINITE_DISTANCE;const double want_slope = _calc_slope(target.x, target.y);double slope_diff = VERTICAL_SLOPE * 10.0;double ray_slope_diff = slope_diff;std::vector<coord_def> unaliased_ray;
const std::vector<cellray> &min = min_cellrays(target);ASSERT(min.size() > 0);cellray c = min[0]; // XXX: const cellray &c ?unsigned int index = 0;
for (unsigned int fray = 0; fray < fullrays.size(); ++fray){const int fullray = _cyclic_offset(fray, cycle_dir, ray.fullray_idx,fullrays.size());los_ray lray = fullrays[fullray];
#ifdef DEBUG_DIAGNOSTICSif (cycle)mprf(MSGCH_DIAGNOSTICS, "cycling from %d (total %d), ignores_solid=%d",ray.cycle_idx, min.size(), ignore_solid);#endif
for (unsigned int cellray = 0; cellray < lray.length; ++cellray){if (lray[cellray] != target)continue;
unsigned int start = cycle ? ray.cycle_idx + 1 : 0;ASSERT(0 <= start && start <= min.size());
if (find_best)
if (ignore_solid){index = start % min.size();c = min[index];}else{bool blocked = true;for (unsigned int i = start; blocked && (i < start + min.size()); i++){index = i % min.size();c = min[index];blocked = false;// Check all inner points.for (unsigned int j = 0; j < c.end && !blocked; j++)
// Check if we're blocked so far.bool blocked = false;coord_def c1, c3;for (unsigned int inray = 0; inray <= cellray; ++inray){c3 = ray_coords[inray + fullrays[fray].start];if (inray < cellray && !ignore_solid&& grid_is_solid(grd(t.transform(c3)))){blocked = true;break;}if (find_best){// We've moved at least two steps if inray > 0.if (inray){// Check for a perpendicular corner on the ray and// pretend that it's a diagonal.if ((c3 - c1).abs() == 2){// c2 was a dud move, pop it offunaliased_ray.pop_back();}}unaliased_ray.push_back(c3);c1 = unaliased_ray[unaliased_ray.size() - 2];}}// If this ray is a candidate for shortest, calculate// the imbalance.int cimbalance = 0;if (!blocked && find_best){cimbalance = _imbalance(unaliased_ray);ray_slope_diff = fabs(_slope_factor(lray) - want_slope);}if (blocked || (find_best &&!_superior_ray(imbalance, cimbalance,slope_diff, ray_slope_diff))){continue;}// Success!found = true;ray = lray;ray.fullray_idx = fullray;imbalance = cimbalance;slope_diff = ray_slope_diff;if (!find_best)return (true);