void WaypointListDialog::OnPaintItem(Canvas &canvas, const PixelRect rc, unsigned i) { if (waypoint_list.empty()) { assert(i == 0); const UPixelScalar line_height = rc.bottom - rc.top; const Font &name_font = *UIGlobals::GetDialogLook().list.font; canvas.SetTextColor(COLOR_BLACK); canvas.Select(name_font); canvas.DrawText(rc.left + line_height + Layout::FastScale(2), rc.top + line_height / 2 - name_font.GetHeight() / 2, dialog_state.IsDefined() || way_points.IsEmpty() ? _("No Match!") : _("Choose a filter or click here")); return; } assert(i < waypoint_list.size()); const struct WaypointListItem &info = waypoint_list[i]; WaypointListRenderer::Draw(canvas, rc, *info.waypoint, info.GetVector(location), UIGlobals::GetDialogLook(), UIGlobals::GetMapLook().waypoint, CommonInterface::GetMapSettings().waypoint); }
WaypointList WaypointManager::visibleWaypoints(D3DXVECTOR3 target) { WaypointList wps; for(int i=0; i<waypoints.size(); i++) { Ray r(waypoints[i]->_position,target -waypoints[i]->_position); if(!kdTree.doesRayIntersect(r)) wps.push_back(i); } return wps; }
static void FillLastUsedList(WaypointList &list, const WaypointIDList &last_used_ids, const Waypoints &waypoints) { list.clear(); for (auto it = last_used_ids.rbegin(); it != last_used_ids.rend(); it++) { const Waypoint* waypoint = waypoints.LookupId(*it); if (waypoint == NULL) continue; list.push_back(WaypointListItem(*waypoint)); } }
void WaypointManagerWidget::UpdateButtons() { const bool non_empty = !items.empty(); edit_button->SetEnabled(non_empty); delete_button->SetEnabled(non_empty); }
WaypointPtr WaypointManager::nearestVisibleWaypoint(D3DXVECTOR3 target) { WaypointPtr wp; float minDist = 65535; WaypointList seen = visibleWaypoints(target); if(seen.size()==0) return WaypointPtr(); for(int i=0; i<seen.size(); i++) { float d = D3DXVec3Length(&(waypoints[seen[i]]->_position - target)); if(d<minDist) { wp = waypoints[seen[i]]; minDist = d; } } return wp; }
void WaypointListWidget::OnWaypointListEnter() { if (!items.empty()) action_listener.OnAction(mrOK); else filter_widget.GetControl(NAME).BeginEditing(); }
static void OnWaypointListEnter(gcc_unused unsigned i) { if (waypoint_list.size() > 0) dialog->SetModalResult(mrOK); else OnFilterNameButton(*name_button); }
static void UpdateList() { waypoint_list.clear(); if (dialog_state.type_index == TypeFilter::LAST_USED) FillLastUsedList(waypoint_list, LastUsedWaypoints::GetList(), way_points); else FillList(waypoint_list, way_points, location, last_heading, dialog_state); waypoint_list_control->SetLength(std::max(1, (int)waypoint_list.size())); waypoint_list_control->SetOrigin(0); waypoint_list_control->SetCursorIndex(0); waypoint_list_control->Invalidate(); }
static void OnWaypointListEnter() { if (waypoint_list.size() > 0) dialog->SetModalResult(mrOK); else name_control->BeginEditing(); }
void WaypointListWidget::UpdateList() { items.clear(); if (dialog_state.type_index == TypeFilter::LAST_USED) FillLastUsedList(items, LastUsedWaypoints::GetList(), way_points); else FillList(items, way_points, location, last_heading, dialog_state); auto &list = GetList(); list.SetLength(std::max(1u, (unsigned)items.size())); list.SetOrigin(0); list.SetCursorIndex(0); list.Invalidate(); }
const Waypoint* dlgWaypointSelect(SingleWindow &parent, const GeoPoint &_location, OrderedTask *ordered_task, const unsigned ordered_task_index) { dialog = LoadDialog(callback_table, parent, Layout::landscape ? _T("IDR_XML_WAYPOINTSELECT_L") : _T("IDR_XML_WAYPOINTSELECT")); assert(dialog != NULL); #ifdef GNAV dialog->SetKeyDownNotify(FormKeyDown); #endif const DialogLook &dialog_look = UIGlobals::GetDialogLook(); waypoint_list_control = (ListControl*)dialog->FindByName(_T("frmWaypointList")); assert(waypoint_list_control != NULL); waypoint_list_control->SetActivateCallback(OnWaypointListEnter); waypoint_list_control->SetPaintItemCallback(OnPaintListItem); waypoint_list_control->SetItemHeight(WaypointListRenderer::GetHeight(dialog_look)); name_button = (WndButton*)dialog->FindByName(_T("cmdFltName")); name_button->SetOnLeftNotify(OnFilterNameButtonLeft); name_button->SetOnRightNotify(OnFilterNameButtonRight); distance_filter = (WndProperty*)dialog->FindByName(_T("prpFltDistance")); direction_filter = (WndProperty*)dialog->FindByName(_T("prpFltDirection")); type_filter = (WndProperty *)dialog->FindByName(_T("prpFltType")); location = _location; triangle_validator = new FAITrianglePointValidator(ordered_task, ordered_task_index); last_heading = CommonInterface::Calculated().heading; PrepareData(); UpdateList(); dialog->SetTimerNotify(OnTimerNotify); if (dialog->ShowModal() != mrOK) { delete dialog; delete triangle_validator; return NULL; } unsigned index = waypoint_list_control->GetCursorIndex(); delete dialog; delete triangle_validator; const Waypoint* retval = NULL; if (index < waypoint_list.size()) retval = waypoint_list[index].waypoint; return retval; }
void WaypointManagerWidget::UpdateList() { items.clear(); WaypointFilter filter; filter.Clear(); filter.type_index = TypeFilter::USER; WaypointListBuilder builder(filter, GeoPoint::Invalid(), items, nullptr, 0); builder.Visit(way_points); auto &list = GetList(); list.SetLength(items.size()); list.SetOrigin(0); list.SetCursorIndex(0); list.Invalidate(); }
WaypointList* PathFinder::FindPath( WORLD_POSITION src, WORLD_POSITION goal, UINT32 maxCells ) { if (!m_pPathGraph) { RETAILMSG(ZONE_ERROR, "ERROR: PathFinder::FindPath(): m_pPathGraph is NULL\n"); return NULL; } NodeID srcID = WorldPositionToNodeID( src ); NodeID goalID = WorldPositionToNodeID( goal ); // RETAILMSG(ZONE_PATHFINDER, ("FindPath: (%.2f, %.2f, %.2f) [%d] -> (%.2f, %.2f, %.2f) [%d]\n", // src.x, src.y, src.z, srcID, // goal.x, goal.y, goal.z, goalID ); // Find the list of connections from Cell A to Cell B WaypointList *pWaypointList = FindPathAStar( srcID, goalID, maxCells ); if (m_bPathSmoothing) pWaypointList = SmoothWaypointList( pWaypointList ); if (pWaypointList) { for( WaypointList::iterator pWaypoint = pWaypointList->begin(); pWaypoint != pWaypointList->end(); pWaypoint++ ) { if (m_bShowPathFinding && m_pDisplayCallback) { WORLD_POSITION temp = *pWaypoint; temp.x -= 0.5; temp.z -= 0.5; m_pDisplayCallback( temp, PATH_NODE_WAYPOINT ); } } } else { if (m_bShowPathFinding && m_pClearCallback) m_pClearCallback(); } return pWaypointList; }
static void FillList(WaypointList &list, const Waypoints &src, GeoPoint location, Angle heading, const WaypointFilterData &filter) { list.clear(); if (!filter.IsDefined() && src.size() >= 500) return; FilterWaypointVisitor visitor(filter, location, heading, list); if (filter.distance_index > 0) src.VisitWithinRange(location, Units::ToSysDistance( distance_filter_items[filter.distance_index]), visitor); else src.VisitNamePrefix(filter.name, visitor); if (filter.distance_index > 0 || filter.direction_index > 0) std::sort(list.begin(), list.end(), WaypointDistanceCompare(location)); }
static void FillLastUsedList(WaypointList &list, const WaypointIDList &last_used_ids, const Waypoints &waypoints) { for (auto it = last_used_ids.rbegin(); it != last_used_ids.rend(); it++) { const Waypoint* waypoint = waypoints.LookupId(*it); if (waypoint == nullptr) continue; list.emplace_back(*waypoint); } }
void WaypointManagerWidget::OnPaintItem(Canvas &canvas, const PixelRect rc, unsigned i) { assert(i < items.size()); const auto &info = items[i]; WaypointListRenderer::Draw(canvas, rc, *info.waypoint, row_renderer, UIGlobals::GetMapLook().waypoint, CommonInterface::GetMapSettings().waypoint); }
static void UpdateList() { if (filter_data.type_index == TF_LAST_USED) FillLastUsedList(waypoint_list, LastUsedWaypoints::GetList(), way_points); else FillList(waypoint_list, way_points, location, last_heading, filter_data); waypoint_list_control->SetLength(std::max(1, (int)waypoint_list.size())); waypoint_list_control->SetOrigin(0); waypoint_list_control->SetCursorIndex(0); waypoint_list_control->Invalidate(); }
static void FillList(WaypointList &list, const Waypoints &src, GeoPoint location, Angle heading, const WaypointListDialogState &state) { if (!state.IsDefined() && src.size() >= 500) return; WaypointFilter filter; state.ToFilter(filter, heading); WaypointListBuilder builder(filter, location, list, ordered_task, ordered_task_index); builder.Visit(src); if (positive(filter.distance) || !negative(filter.direction.Native())) list.SortByDistance(location); }
const Waypoint* ShowWaypointListDialog(SingleWindow &parent, const GeoPoint &_location, OrderedTask *_ordered_task, unsigned _ordered_task_index) { dialog = LoadDialog(callback_table, parent, Layout::landscape ? _T("IDR_XML_WAYPOINTSELECT_L") : _T("IDR_XML_WAYPOINTSELECT")); assert(dialog != NULL); #ifdef GNAV dialog->SetKeyDownFunction(FormKeyDown); #endif const DialogLook &dialog_look = UIGlobals::GetDialogLook(); WaypointListDialog dialog2; waypoint_list_control = (ListControl*)dialog->FindByName(_T("frmWaypointList")); assert(waypoint_list_control != NULL); waypoint_list_control->SetItemRenderer(&dialog2); waypoint_list_control->SetItemHeight(WaypointListRenderer::GetHeight(dialog_look)); waypoint_list_control->SetCursorHandler(&dialog2); FilterDataFieldListener listener; name_control = (WndProperty *)dialog->FindByName(_T("name")); assert(name_control != nullptr); DataField *name_df = new PrefixDataField(_T(""), WaypointNameAllowedCharacters); name_control->SetDataField(name_df); name_df->SetListener(&listener); distance_filter = (WndProperty*)dialog->FindByName(_T("prpFltDistance")); assert(distance_filter != NULL); distance_filter->GetDataField()->SetListener(&listener); direction_filter = (WndProperty*)dialog->FindByName(_T("prpFltDirection")); assert(direction_filter != NULL); direction_filter->GetDataField()->SetListener(&listener); type_filter = (WndProperty *)dialog->FindByName(_T("prpFltType")); assert(type_filter != NULL); type_filter->GetDataField()->SetListener(&listener); location = _location; ordered_task = _ordered_task; ordered_task_index = _ordered_task_index; last_heading = CommonInterface::Basic().attitude.heading; PrepareData(); UpdateList(); const ScopeGPSListener l(CommonInterface::GetLiveBlackboard(), OnGPSUpdate); if (dialog->ShowModal() != mrOK) { delete dialog; return NULL; } unsigned index = waypoint_list_control->GetCursorIndex(); delete dialog; const Waypoint* retval = NULL; if (index < waypoint_list.size()) retval = waypoint_list[index].waypoint; return retval; }
WaypointList* PathFinder::SmoothWaypointList( WaypointList* pWaypointList ) { if (!pWaypointList) return NULL; if( pWaypointList->size() > 2 ) { WORLD_POSITION newPoint0( 0.0f, 0.0f, 0.0f ); WORLD_POSITION newPoint1( 0.0f, 0.0f, 0.0f ); WaypointList oldList; for( WaypointList::iterator i = pWaypointList->begin(); i != pWaypointList->end(); i++ ) { oldList.push_back( *i ); } pWaypointList->clear(); WORLD_POSITION p0, p1, p2, p3; //First WaypointList::iterator iter = oldList.begin(); p0 = p1 = p2 = *iter; iter++; p3 = *iter; iter++; const int divisions = 5; while( iter != oldList.end() ) { p0 = p1; p1 = p2; p2 = p3; p3 = *iter; for( int count=1; count<divisions+1; count++) { vec3 newPoint = CatmullRom( p0, p1, p2, p3, (float)count/(float)divisions ); if( pWaypointList->size() > 1 ) { vec3 lastDir = newPoint1 - newPoint0; vec3 curDir = newPoint - newPoint1; lastDir.Normalize(); curDir.Normalize(); float dot = lastDir.Dot( curDir ); if( dot > 0.99f ) { pWaypointList->pop_back(); } } newPoint0 = newPoint1; newPoint1 = newPoint; pWaypointList->push_back( newPoint ); } iter++; } //Last p0 = p1; p1 = p2; p2 = p3; p3 = p3; //Redundant, but put here to make it clear what is intended for( int count=1; count<divisions+1; count++) { WORLD_POSITION newPoint = CatmullRom( p0, p1, p2, p3, (float)count/(float)divisions ); if( pWaypointList->size() > 1 ) { vec3 lastDir = newPoint1 - newPoint0; vec3 curDir = newPoint - newPoint1; lastDir.Normalize(); curDir.Normalize(); float dot = lastDir.Dot( curDir ); if( dot > 0.99f ) { pWaypointList->pop_back(); } } newPoint0 = newPoint1; newPoint1 = newPoint; pWaypointList->push_back( newPoint ); } } return pWaypointList; }
void Visit(const Waypoint &waypoint) { if (CompareType(waypoint, type_index) && (filter_data.distance_index == 0 || CompareName(waypoint, name)) && CompareDirection(waypoint, direction_index, location, heading)) waypoint_list.push_back(WaypointListItem(waypoint)); }
WaypointList* PathFinder::FindPathAStar( NodeID srcID, NodeID goalID, UINT32 maxCells ) { if (!m_pPathGraph) { RETAILMSG(ZONE_ERROR, "ERROR: PathFinder::FindPathAStar(): m_pPathGraph is NULL\n"); return NULL; } WaypointList* pWaypointList = NULL; float fExpectedCost; bool bFoundGoal = false; UINT32 numCells = 0; WORLD_POSITION srcPos = NodeIDToWorldPosition( srcID ); WORLD_POSITION goalPos = NodeIDToWorldPosition( goalID ); fExpectedCost = Heuristic( srcID, goalID ); // Add the starting point to open list if (!m_pCurrentConnection) { // Finding a new path; as good a place as any to erase all debug visualization // for the previous path. if (m_bShowPathFinding && m_pClearCallback) m_pClearCallback(); m_pStartConnection = new Connection(); m_pStartConnection->destinationNodeID = srcID; m_pStartConnection->fCost = 0.0f; m_pStartConnection->fCostSoFar = 0.0f; m_pStartConnection->fEstimatedCostToGoal = fExpectedCost; m_pStartConnection->pParentConnection = NULL; m_pStartConnection->parentNodeID = -1; m_pCurrentConnection = m_pStartConnection; m_OpenList.insert( m_pStartConnection ); } while( !m_OpenList.empty() ) { // TEST TEST: validate that the list is sorted! //if (!IsListSorted( &m_OpenList ) ) //{ // RETAILMSG(ZONE_ERROR, "ERROR: m_OpenList is not sorted!\n"); //} // Choose "cheapest" potential connection; first item in OpenList m_pCurrentConnection = *(m_OpenList.begin()); if (!m_pCurrentConnection) { RETAILMSG(ZONE_ERROR, "ERROR: PathFinder::FindPathAStar(): m_pCurrentConnection is NULL"); break; } RETAILMSG(ZONE_PATHFINDER | ZONE_VERBOSE, "Current Connection: %d -> %d (cost=%f) (costSoFar=%f) (estimatedCostToGoal=%f)\n", m_pCurrentConnection->parentNodeID, m_pCurrentConnection->destinationNodeID, m_pCurrentConnection->fCost, m_pCurrentConnection->fCostSoFar, m_pCurrentConnection->fEstimatedCostToGoal); // Is this connection our goal? if (m_pCurrentConnection->destinationNodeID == goalID) { // Done! bFoundGoal = true; break; } // // foreach visibleConnection (m_pCurrentConnection) // ConnectionList* pConnectionList; m_pPathGraph->GetConnections( m_pCurrentConnection->destinationNodeID, &pConnectionList ); if (!pConnectionList) { // No connections from here; should never happen // Starting point may be inside a wall, or off the map; clean up and return RETAILMSG(ZONE_ERROR, "ERROR: pathfinding found an unreachable node. Giving up.\n"); goto Exit; } for (unsigned int i = 0; i < pConnectionList->numConnections; ++i) { Connection* pVisibleConnection = &pConnectionList->connections[ i ]; float fCostForThisConnection = m_pCurrentConnection->fCostSoFar + pVisibleConnection->fCost; // if visibleConnection on closed list if (m_ClosedList.find( pVisibleConnection ) != m_ClosedList.end()) { if ( pVisibleConnection->fCostSoFar <= fCostForThisConnection ) { // current connection not any cheaper; skip continue; } else { m_ClosedList.erase( pVisibleConnection ); DEBUGMSG(ZONE_PATHFINDER | ZONE_VERBOSE, "-Closed List: %d -> %d (cost=%f) (costSoFar=%f) (estimatedCostToGoal=%f)\n", m_pCurrentConnection->parentNodeID, m_pCurrentConnection->destinationNodeID, m_pCurrentConnection->fCost, m_pCurrentConnection->fCostSoFar, m_pCurrentConnection->fEstimatedCostToGoal); } } OpenListType::iterator ppConnection; ppConnection = m_OpenList.find( pVisibleConnection ); if ( ppConnection != m_OpenList.end() && *ppConnection == pVisibleConnection ) { // If visible connection is still cheaper than current connection if (pVisibleConnection->fCostSoFar <= fCostForThisConnection) { continue; // still viable; keep on the open list } } else { // // First time visiting this connection // // Store cost-so-far to visibleConnection pVisibleConnection->fCostSoFar = fCostForThisConnection; // Store parent to visibleConnection pVisibleConnection->parentNodeID = m_pCurrentConnection->destinationNodeID; pVisibleConnection->pParentConnection = m_pCurrentConnection; // Store estimate-total-cost-from-here to visibleConnection pVisibleConnection->fEstimatedCostToGoal = fCostForThisConnection + Heuristic( pVisibleConnection->destinationNodeID, goalID ); // Add to open list m_OpenList.insert( pVisibleConnection ); DEBUGMSG(ZONE_PATHFINDER | ZONE_VERBOSE, "+Open List: %d -> %d (cost=%f) (costSoFar=%f) (estimatedCostToGoal=%f)\n", pVisibleConnection->parentNodeID, pVisibleConnection->destinationNodeID, pVisibleConnection->fCost, pVisibleConnection->fCostSoFar, pVisibleConnection->fEstimatedCostToGoal); // TEST TEST: validate that the list is sorted! //if (!IsListSorted( &m_OpenList ) ) //{ // RETAILMSG(ZONE_ERROR, "ERROR: m_OpenList is not sorted!\n"); //} } } // END considering each connection from current node // Done sorting all connections from current node into open (viable) and closed (too expensive) // remove m_pCurrentConnection from open list m_OpenList.erase( m_pCurrentConnection ); DEBUGMSG(ZONE_PATHFINDER | ZONE_VERBOSE, "-Open List: %d -> %d (cost=%f) (costSoFar=%f) (estimatedCostToGoal=%f)\n", m_pCurrentConnection->parentNodeID, m_pCurrentConnection->destinationNodeID, m_pCurrentConnection->fCost, m_pCurrentConnection->fCostSoFar, m_pCurrentConnection->fEstimatedCostToGoal); // put m_pCurrentConnection on closed list m_ClosedList.insert( m_pCurrentConnection ); DEBUGMSG(ZONE_PATHFINDER | ZONE_VERBOSE, "+Closed List: %d -> %d (cost=%f) (costSoFar=%f) (estimatedCostToGoal=%f)\n", m_pCurrentConnection->parentNodeID, m_pCurrentConnection->destinationNodeID, m_pCurrentConnection->fCost, m_pCurrentConnection->fCostSoFar, m_pCurrentConnection->fEstimatedCostToGoal); // If we've run too long, abort the search // Will resume where we left off on the next call to PathFindAStar(). if (++numCells >= maxCells) break; } // END while( open list ) Exit: // // Display the Open and Closed lists for debugging // if (m_bShowPathFinding && m_pDisplayCallback) { ClosedListType::iterator ppClosedConnection; for (ppClosedConnection = m_ClosedList.begin(); ppClosedConnection != m_ClosedList.end(); ++ppClosedConnection) { Connection* pConnection = *ppClosedConnection; m_pDisplayCallback( NodeIDToWorldPosition( pConnection->destinationNodeID ), PATH_NODE_CLOSED ); } OpenListType::iterator ppOpenConnection; for (ppOpenConnection = m_OpenList.begin(); ppOpenConnection != m_OpenList.end(); ++ppOpenConnection) { Connection* pConnection = *ppOpenConnection; m_pDisplayCallback( NodeIDToWorldPosition( pConnection->destinationNodeID ), PATH_NODE_OPEN ); } } // If we got here, the open list is empty, or we ran out of time for this frame // if (m_pCurrentConnection->destinationNodeID != goalID) if (!bFoundGoal && m_OpenList.empty() ) { if ( !m_OpenList.empty() ) { DEBUGMSG(ZONE_PATHFINDER | ZONE_VERBOSE, "Halting search until next frame.\n"); } else { DEBUGMSG(ZONE_PATHFINDER, "Found NO path to goalID!\n"); CleanUp(); } } else { DEBUGMSG(ZONE_PATHFINDER, "Found path to goalID.\n"); // Walk back the connection list // Convert each connection into a Waypoint pWaypointList = new WaypointList(); // while( m_pCurrentConnection ) while( m_pCurrentConnection && m_pCurrentConnection->fCost > 0.0f ) { pWaypointList->push_front( NodeIDToWorldPosition( m_pCurrentConnection->destinationNodeID ) ); m_pCurrentConnection = m_pCurrentConnection->pParentConnection; } CleanUp(); } return pWaypointList; }
const Waypoint *GetCursorObject() const { return items.empty() ? nullptr : items[GetList().GetCursorIndex()].waypoint; }