Added: Command to search and target closest user landmark.

--HG--
branch : develop
This commit is contained in:
Nimetu 2018-05-04 15:12:00 +03:00
parent 11150e6b79
commit 923084a818
3 changed files with 186 additions and 5 deletions

View file

@ -2493,6 +2493,33 @@ class CAHTarget : public IActionHandler
};
REGISTER_ACTION_HANDLER (CAHTarget, "target");
// ***************************************************************************
class CAHTargetLandmark : public IActionHandler
{
virtual void execute (CCtrlBase * /* pCaller */, const string &Params)
{
string search = getParam(Params, "search");
if (search.empty()) return;
bool startsWith = false;
if (search.size() > 0 && (search[0] == '\'' || search[0] == '"') && search[0] == search[search.size()-1])
{
startsWith = true;
search = trimQuotes(search);
}
const std::string mapid = "ui:interface:map:content:map_content:actual_map";
CGroupMap* cgMap = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId(mapid));
if (cgMap)
{
if (!cgMap->targetLandmarkByName(search, startsWith))
{
CInterfaceManager::getInstance()->displaySystemInfo(CI18N::get("uiTargetErrorCmd"));
}
}
}
};
REGISTER_ACTION_HANDLER (CAHTargetLandmark, "target_landmark");
class CAHAddShape : public IActionHandler

View file

@ -100,6 +100,12 @@ const uint32 ISLAND_PIXEL_PER_METER = 2;
static void setupFromZoom(CViewBase *pVB, CContLandMark::TContLMType t, float fMeterPerPixel);
// calculate distance (squared) between two points
static float distsqr(const CVector2f a, const CVector2f b)
{
return pow(a.x - b.x, 2) + pow(a.y - b.y, 2);
}
// popup the landmark name dialog
static void popupLandMarkNameDialog()
@ -2671,21 +2677,38 @@ void CGroupMap::updateLandMarkButton(CLandMarkButton *lmb, const CLandMarkOption
}
//============================================================================================================
bool CGroupMap::filterLandmark(const ucstring &title) const
bool CGroupMap::filterLandmark(const ucstring &title, const std::vector<ucstring> filter, bool startsWith) const
{
if (_LandmarkFilter.size() > 0)
if (filter.size() > 0)
{
ucstring lcTitle = toLower(title);
for(uint i = 0; i< _LandmarkFilter.size(); ++i) {
if (lcTitle.find(_LandmarkFilter[i]) == ucstring::npos) {
if (startsWith)
{
if (lcTitle.find(filter[0]) != 0)
{
return false;
}
}
else
{
for(uint i = 0; i< filter.size(); ++i)
{
if (lcTitle.find(filter[i]) == ucstring::npos)
{
return false;
}
}
}
}
return true;
}
//============================================================================================================
bool CGroupMap::filterLandmark(const ucstring &title) const
{
return filterLandmark(title, _LandmarkFilter);
}
//============================================================================================================
void CGroupMap::addLandMark(TLandMarkButtonVect &destList, const NLMISC::CVector2f &pos, const ucstring &title, const CLandMarkOptions &options)
{
@ -3186,6 +3209,129 @@ void CGroupMap::targetLandmarkResult(uint32 index)
}
}
//=========================================================================================================
CGroupMap::CLandMarkButton* CGroupMap::findClosestLandmark(const CVector2f &center, const ucstring &search, bool startsWith, const TLandMarkButtonVect &landmarks, float &closest) const
{
CLandMarkButton *ret = NULL;
std::vector<ucstring> keywords;
if (startsWith)
keywords.push_back(search);
else
splitUCString(toLower(search), ucstring(" "), keywords);
closest = std::numeric_limits<float>::max();
for(TLandMarkButtonVect::const_iterator it = landmarks.begin(); it != landmarks.end(); ++it)
{
ucstring lc;
(*it)->getContextHelp(lc);
if(filterLandmark(lc, keywords, startsWith)) {
CVector2f pos;
mapToWorld(pos, (*it)->Pos);
float dist = distsqr(center, pos);
if (dist < closest)
{
ret = (*it);
closest = dist;
}
}
}
return ret;
}
//=========================================================================================================
CGroupMap::CLandMarkText* CGroupMap::findClosestLandmark(const CVector2f &center, const ucstring &search, bool startsWith, const TLandMarkTextVect &landmarks, float &closest) const
{
CLandMarkText *ret = NULL;
std::vector<ucstring> keywords;
if (startsWith)
keywords.push_back(search);
else
splitUCString(toLower(search), ucstring(" "), keywords);
closest = std::numeric_limits<float>::max();
for(TLandMarkTextVect::const_iterator it = landmarks.begin(); it != landmarks.end(); ++it)
{
ucstring lc;
lc = (*it)->getText();
if(filterLandmark(lc, keywords, startsWith)) {
CVector2f pos;
mapToWorld(pos, (*it)->Pos);
float dist = distsqr(center, pos);
if (dist < closest)
{
ret = (*it);
closest = dist;
}
}
}
return ret;
}
bool CGroupMap::targetLandmarkByName(const ucstring &search, bool startsWith) const
{
CCompassTarget ct;
CLandMarkButton* lm;
float dist;
float closest = std::numeric_limits<float>::max();
bool found = false;
CVector2f center;
mapToWorld(center, _PlayerPos);
lm = findClosestLandmark(center, search, startsWith, _UserLM, dist);
if (lm && dist < closest)
{
ct.setType(CCompassTarget::UserLandMark);
mapToWorld(ct.Pos, lm->Pos);
lm->getContextHelp(ct.Name);
closest = dist;
found = true;
}
// only check other types if user landmark was not found
if (!found)
{
lm = findClosestLandmark(center, search, startsWith, _ContinentLM, dist);
if (lm && dist < closest)
{
ct.setType(CCompassTarget::ContinentLandMark);
mapToWorld(ct.Pos, lm->Pos);
lm->getContextHelp(ct.Name);
closest = dist;
found = true;
}
CLandMarkText* lmt;
lmt = findClosestLandmark(center, search, startsWith, _ContinentText, dist);
if (lmt && dist < closest)
{
ct.setType(CCompassTarget::ContinentLandMark);
mapToWorld(ct.Pos, lmt->Pos);
ct.Name = lmt->getText();
closest = dist;
found = true;
}
}
if (found)
{
CInterfaceManager *im = CInterfaceManager::getInstance();
CGroupCompas *gc = dynamic_cast<CGroupCompas *>(CWidgetManager::getInstance()->getElementFromId(_CompassId));
if (gc)
{
gc->setActive(true);
gc->setTarget(ct);
gc->blink();
CWidgetManager::getInstance()->setTopWindow(gc);
}
}
return found;
}
//=========================================================================================================
void CGroupMap::getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos)
{

View file

@ -192,6 +192,8 @@ public:
// target the given landmark
void targetLandmark(CCtrlButton *lm);
void targetLandmarkResult(uint32 index);
// search matching landmark and target it. return true if landmark was targeted
bool targetLandmarkByName(const ucstring &search, bool startsWith) const;
// get the world position of a landmark or return vector Null if not found
void getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos);
@ -551,6 +553,12 @@ private:
// Test title against landmark filter
bool filterLandmark(const ucstring &title) const;
bool filterLandmark(const ucstring &title, const std::vector<ucstring> filter, bool startsWith = false) const;
// return closest landmark which matches (case insensitive) search string
// center position must be in world coordindates
CLandMarkButton* findClosestLandmark(const NLMISC::CVector2f &center, const ucstring &search, bool startsWith, const TLandMarkButtonVect &landmarks, float &closest) const;
CLandMarkText* findClosestLandmark(const NLMISC::CVector2f &center, const ucstring &search, bool startsWith, const TLandMarkTextVect &landmarks, float &closest) const;
// update the scale depending on the window size and the user scale
void updateScale();