PointI C_Window::GetCursorPos() { POINT pt; if(::GetCursorPos(&pt)) { return PointI(pt.x, pt.y); } return PointI(0, 0); }
PointI C_Window::GetPosition() { RECT rect; if(GetWindowRect(m_handle, &rect)) { return PointI(rect.left, rect.top); } return PointI(0,0); }
// Going to a bookmark within current file scrolls to a given page. // Going to a bookmark in another file, loads the file and scrolls to a page // (similar to how invoking one of the recently opened files works) static void GoToFavorite(WindowInfo* win, DisplayState* f, Favorite* fn) { CrashIf(!f || !fn); if (!f || !fn) { return; } WindowInfo* existingWin = FindWindowInfoByFile(f->filePath, true); if (existingWin) { int pageNo = fn->pageNo; uitask::Post([=] { GoToFavorite(existingWin, pageNo); }); return; } if (!HasPermission(Perm_DiskAccess)) { return; } // When loading a new document, go directly to selected page instead of // first showing last seen page stored in file history // A hacky solution because I don't want to add even more parameters to // LoadDocument() and LoadDocumentInto() int pageNo = fn->pageNo; DisplayState* ds = gFileHistory.Find(f->filePath); if (ds && !ds->useDefaultState && gGlobalPrefs->rememberStatePerDocument) { ds->pageNo = fn->pageNo; ds->scrollPos = PointI(-1, -1); // don't scroll the page pageNo = -1; } LoadArgs args(f->filePath, win); win = LoadDocument(args); if (win) { uitask::Post([=] { (win, pageNo); }); } }
bool IsCursorOverWindow(HWND hwnd) { POINT pt; GetCursorPos(&pt); WindowRect rcWnd(hwnd); return rcWnd.Contains(PointI(pt.x, pt.y)); }
OsmAnd::Model::Road::Road( const std::shared_ptr<Road>& that, int insertIdx, uint32_t x31, uint32_t y31 ) : _ref(that) , _id(0) , _points(_ref->_points.size() + 1) , subsection(_ref->subsection) , id(_ref->_id) , names(_ref->_names) , points(_points) , types(_ref->_types) , pointsTypes(_pointsTypes) , restrictions(_ref->_restrictions) { int pointIdx = 0; for(; pointIdx < insertIdx; pointIdx++) { _points[pointIdx] = _ref->_points[pointIdx]; if(!_ref->_pointsTypes.isEmpty()) _pointsTypes.insert(pointIdx, _ref->_pointsTypes[pointIdx]); } _points[pointIdx] = PointI(x31, y31); for(pointIdx += 1; pointIdx < _points.size(); pointIdx++) { _points[pointIdx] = _ref->_points[pointIdx - 1]; if(!_ref->_pointsTypes.isEmpty()) _pointsTypes.insert(pointIdx, _ref->_pointsTypes[pointIdx]); } }
static LRESULT CALLBACK WndProcFavBox(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { WindowInfo* win = FindWindowInfoByHwnd(hwnd); if (!win) return CallWindowProc(DefWndProcFavBox, hwnd, message, wParam, lParam); switch (message) { case WM_SIZE: LayoutTreeContainer(win->favLabelWithClose, win->hwndFavTree); break; case WM_COMMAND: if (LOWORD(wParam) == IDC_FAV_LABEL_WITH_CLOSE) ToggleFavorites(win); break; case WM_NOTIFY: if (LOWORD(wParam) == IDC_FAV_TREE) { LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam; LRESULT res = OnFavTreeNotify(win, pnmtv); if (res != -1) return res; } break; case WM_CONTEXTMENU: if (win->hwndFavTree == (HWND)wParam) { OnFavTreeContextMenu(win, PointI(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam))); return 0; } break; } return CallWindowProc(DefWndProcFavBox, hwnd, message, wParam, lParam); }
TerrainRenderer::PointF TerrainRenderer::GetBAround(const MapPoint pt, const unsigned char triangle, const unsigned char dir) { PointI ptNb = GetPointAround(PointI(pt), dir); Point<int> offset; MapPoint t = ConvertCoords(ptNb, &offset); return GetB(t, triangle) + PointF(offset); }
TerrainRenderer::PointF TerrainRenderer::GetTerrainAround(MapPoint pt, const unsigned dir) { PointI ptNb = GetPointAround(PointI(pt), dir); PointI offset; MapPoint t = ConvertCoords(ptNb, &offset); return GetTerrain(t) + PointF(offset); }
PointI OsmAndMapView::getPixelPoint(int32_t x31, int32_t y31) const{ int cx = getCenterPointX(); int cy = getCenterPointY(); auto pw = OsmAnd::Utilities::getPowZoom(31 - getZoom()); float diffxTile = x31 / pw - getXTile(); float diffyTile = y31 / pw - getYTile(); int newX = (int) (calcDiffPixelX(diffxTile, diffyTile) + cx); int newY = (int) (calcDiffPixelY(diffxTile, diffyTile) + cy); return PointI(newX, newY); }
bool GetCursorPosInHwnd(HWND hwnd, PointI& posOut) { POINT pt; if (!GetCursorPos(&pt)) return false; if (!ScreenToClient(hwnd, &pt)) return false; posOut = PointI(pt.x, pt.y); return true; }
// Actual window procedure that will handle saving window size/position and moving // the controls whilst the window sizes. static LRESULT CALLBACK SizingProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { DialogData *pdd = (DialogData *)GetProp(hwnd, DIALOG_DATA_PROPERTY); if (!pdd) return DefWindowProc(hwnd, msg, wParam, lParam); switch (msg) { case WM_ERASEBKGND: { LRESULT lr = CallWindowProc(pdd->wndProc, hwnd, msg, wParam, lParam); pdd->DrawGripper((HDC)wParam); return lr; } case WM_SIZE: { if (wParam != SIZE_MINIMIZED) { pdd->bMaximised = wParam == SIZE_MAXIMIZED; UpdateWindowSize(pdd, LOWORD(lParam), HIWORD(lParam), hwnd); } } break; case WM_NCHITTEST: { // If the gripper is enabled then perform a simple hit test on our gripper area. POINT pt = { LOWORD(lParam), HIWORD(lParam) }; ScreenToClient(hwnd, &pt); if (pdd->InsideGripper(PointI(pt.x, pt.y))) return HTBOTTOMRIGHT; } break; case WM_GETMINMAXINFO: { // Our opportunity to say that we do not want the dialog to grow or shrink any more. LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; lpmmi->ptMinTrackSize = pdd->ptSmallest; } return 0; case WM_DESTROY: { WNDPROC wndProc = pdd->wndProc; delete pdd; return CallWindowProc(wndProc, hwnd, msg, wParam, lParam); } } return CallWindowProc(pdd->wndProc, hwnd, msg, wParam, lParam); }
void ChmModel::UpdateDisplayState(DisplayState *ds) { if (!ds->filePath || !str::EqI(ds->filePath, fileName)) str::ReplacePtr(&ds->filePath, fileName); ds->useDefaultState = !gGlobalPrefs->rememberStatePerDocument; str::ReplacePtr(&ds->displayMode, prefs::conv::FromDisplayMode(GetDisplayMode())); prefs::conv::FromZoom(&ds->zoom, GetZoomVirtual(), ds); ds->pageNo = CurrentPageNo(); ds->scrollPos = PointI(); }
static bool IsTileVisible(DisplayModel *dm, int pageNo, int rotation, float zoom, TilePosition tile, float fuzz=0) { if (!dm) return false; PageInfo *pageInfo = dm->GetPageInfo(pageNo); if (!dm->engine || !pageInfo) return false; RectI tileOnScreen = GetTileOnScreen(dm->engine, pageNo, rotation, zoom, tile, pageInfo->pageOnScreen); // consider nearby tiles visible depending on the fuzz factor tileOnScreen.x -= (int)(tileOnScreen.dx * fuzz * 0.5); tileOnScreen.dx = (int)(tileOnScreen.dx * (fuzz + 1)); tileOnScreen.y -= (int)(tileOnScreen.dy * fuzz * 0.5); tileOnScreen.dy = (int)(tileOnScreen.dy * (fuzz + 1)); RectI screen(PointI(), dm->viewPort.Size()); return !tileOnScreen.Intersect(screen).IsEmpty(); }
LRESULT CALLBACK NotificationWnd::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { NotificationWnd *wnd = (NotificationWnd *)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (WM_ERASEBKGND == msg) { // do nothing, helps to avoid flicker return TRUE; } if (WM_TIMER == msg && TIMEOUT_TIMER_ID == wParam) { if (wnd->notificationCb) wnd->notificationCb->RemoveNotification(wnd); else delete wnd; return 0; } if (WM_PAINT == msg && wnd) { NotificationWndOnPaint(hwnd, wnd); return 0; } if (WM_SETCURSOR == msg && wnd->hasCancel) { PointI pt; if (GetCursorPosInHwnd(hwnd, pt) && GetCancelRect(hwnd).Contains(pt)) { SetCursor(IDC_HAND); return TRUE; } } if (WM_LBUTTONUP == msg && wnd->hasCancel) { if (GetCancelRect(hwnd).Contains(PointI(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))) { if (wnd->notificationCb) wnd->notificationCb->RemoveNotification(wnd); else delete wnd; return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam); }
void Map::updateNodes() { for (int x = 0; x < m_worldWidthTiles; ++x) { for (int y = 0; y < m_worldHeightTiles; ++y) { TileNode& tileNode = m_tileNodes[getTileNodeIndex(x, y)]; tileNode.m_type = getTileType(x, y); tileNode.m_pos = PointI(x, y); tileNode.m_transition = TileNode::Transition(); tileNode.m_isWaypoint = false; // TODO - cars, etc... } } for (const auto& waypoint : m_world->getWaypoints()) { TileNode& tileNode = m_tileNodes[getTileNodeIndex(waypoint[0], waypoint[1])]; tileNode.m_isWaypoint = true; } }
OsmAnd::MapRenderer::MapRenderer() : _taskHostBridge(this) , currentConfiguration(_currentConfiguration) , _currentConfigurationInvalidatedMask(0xFFFFFFFF) , currentState(_currentState) , _currentStateInvalidated(true) , _invalidatedRasterLayerResourcesMask(0) , _invalidatedElevationDataResources(false) , tiledResources(_tiledResources) , _renderThreadId(nullptr) , _workerThreadId(nullptr) , renderAPI(_renderAPI) { _tileRequestsThreadPool.setMaxThreadCount(4); // Create all tiled resources for(auto resourceType = 0u; resourceType < TiledResourceTypesCount; resourceType++) { auto collection = new TiledResources(static_cast<TiledResourceType>(resourceType)); _tiledResources[resourceType].reset(collection); } // Fill-up default state for(auto layerId = 0u; layerId < RasterMapLayersCount; layerId++) setRasterLayerOpacity(static_cast<RasterMapLayerId>(layerId), 1.0f); setElevationDataScaleFactor(1.0f, true); setFieldOfView(16.5f, true); setDistanceToFog(400.0f, true); setFogOriginFactor(0.36f, true); setFogHeightOriginFactor(0.05f, true); setFogDensity(1.9f, true); setFogColor(FColorRGB(1.0f, 0.0f, 0.0f), true); setSkyColor(FColorRGB(140.0f / 255.0f, 190.0f / 255.0f, 214.0f / 255.0f), true); setAzimuth(0.0f, true); setElevationAngle(45.0f, true); const auto centerIndex = 1u << (ZoomLevel::MaxZoomLevel - 1); setTarget(PointI(centerIndex, centerIndex), true); setZoom(0, true); }
void OsmAnd::ObfRoutingSectionReader_P::readRoad( const std::unique_ptr<ObfReader_P>& reader, const std::shared_ptr<const ObfRoutingSubsectionInfo>& subsection, const QList<uint64_t>& idsTable, uint32_t& internalId, const std::shared_ptr<Model::Road>& road ) { auto cis = reader->_codedInputStream.get(); for(;;) { auto tag = cis->ReadTag(); switch(gpb::internal::WireFormatLite::GetTagFieldNumber(tag)) { case 0: return; case OBF::RouteData::kPointsFieldNumber: { gpb::uint32 length; cis->ReadVarint32(&length); auto oldLimit = cis->PushLimit(length); auto dx = subsection->_area31.left >> ShiftCoordinates; auto dy = subsection->_area31.top >> ShiftCoordinates; while(cis->BytesUntilLimit() > 0) { const uint32_t x = ObfReaderUtilities::readSInt32(cis) + dx; const uint32_t y = ObfReaderUtilities::readSInt32(cis) + dy; road->_points.push_back(qMove(PointI( x << ShiftCoordinates, y << ShiftCoordinates ))); dx = x; dy = y; } cis->PopLimit(oldLimit); } break; case OBF::RouteData::kPointTypesFieldNumber: { gpb::uint32 length; cis->ReadVarint32(&length); auto oldLimit = cis->PushLimit(length); while(cis->BytesUntilLimit() > 0) { gpb::uint32 pointIdx; cis->ReadVarint32(&pointIdx); gpb::uint32 innerLength; cis->ReadVarint32(&innerLength); auto innerOldLimit = cis->PushLimit(innerLength); auto& pointTypes = road->_pointsTypes.insert(pointIdx, QVector<uint32_t>()).value(); while(cis->BytesUntilLimit() > 0) { gpb::uint32 pointType; cis->ReadVarint32(&pointType); pointTypes.push_back(pointType); } cis->PopLimit(innerOldLimit); } cis->PopLimit(oldLimit); } break; case OBF::RouteData::kTypesFieldNumber: { gpb::uint32 length; cis->ReadVarint32(&length); auto oldLimit = cis->PushLimit(length); while(cis->BytesUntilLimit() > 0) { gpb::uint32 type; cis->ReadVarint32(&type); road->_types.push_back(type); } cis->PopLimit(oldLimit); } break; case OBF::RouteData::kRouteIdFieldNumber: { gpb::uint32 id; cis->ReadVarint32(&id); internalId = id; if(id < idsTable.size()) road->_id = idsTable[id]; else road->_id = id; } break; case OBF::RouteData::kStringNamesFieldNumber: { gpb::uint32 length; cis->ReadVarint32(&length); auto oldLimit = cis->PushLimit(length); while(cis->BytesUntilLimit() > 0) { gpb::uint32 stringTag; cis->ReadVarint32(&stringTag); gpb::uint32 stringId; cis->ReadVarint32(&stringId); road->_names.insert(stringTag, ObfReaderUtilities::encodeIntegerToString(stringId)); } cis->PopLimit(oldLimit); } break; default: ObfReaderUtilities::skipUnknownField(cis, tag); break; } } }
// -scroll x,y static void ParseScrollValue(PointI *scroll, const WCHAR *txt) { int x, y; if (str::Parse(txt, L"%d,%d%$", &x, &y)) *scroll = PointI(x, y); }
void OsmAnd::RoutePlanner::attachRouteSegments( OsmAnd::RoutePlannerContext::CalculationContext* context, const QVector< std::shared_ptr<RouteSegment> >& route, const QVector< std::shared_ptr<RouteSegment> >::const_iterator& itSegment, uint32_t pointIdx, bool isIncrement) { const auto& segment = *itSegment; const auto& nextL = pointIdx < segment->road->points.size() - 1 ? segment->road->points[pointIdx + 1] : PointI(); const auto& prevL = pointIdx > 0 ? segment->road->points[pointIdx - 1] : PointI(); // by default make same as this road id auto previousRoadId = segment->road->id; if (pointIdx == segment->startPointIndex && itSegment != route.cbegin()) { // attach additional roads to represent more information about the route const auto& previousResult = *(itSegment - 1); previousRoadId = previousResult->road->id; if (previousRoadId != segment->road->id) { std::shared_ptr<RouteSegment> attachedSegment; if (previousResult->startPointIndex < previousResult->endPointIndex && previousResult->endPointIndex < previousResult->road->points.size() - 1) attachedSegment.reset(new RouteSegment(previousResult->road, previousResult->endPointIndex, previousResult->road->points.size() - 1)); else if (previousResult->startPointIndex > previousResult->endPointIndex && previousResult->endPointIndex > 0) attachedSegment.reset(new RouteSegment(previousResult->road, previousResult->endPointIndex, 0)); if (attachedSegment) segment->_attachedRoutes[qAbs(static_cast<int64_t>(pointIdx) - static_cast<int64_t>(segment->_startPointIndex))].push_back(qMove(attachedSegment)); } } // Try to attach all segments except with current id const auto& p31 = segment->road->points[pointIdx]; auto rt = OsmAnd::RoutePlanner::loadRouteCalculationSegment(context->owner, p31.x, p31.y); while(rt) { if (rt->road->id != segment->road->id && rt->road->id != previousRoadId) { std::shared_ptr<RouteSegment> attachedSegment; //TODO:GC:checkAndInitRouteRegion(ctx, rt->road); // TODO restrictions can be considered as well auto direction = context->owner->profileContext->getDirection(rt->road); if ((direction == Model::RoadDirection::TwoWay || direction == Model::RoadDirection::OneWayReverse) && rt->pointIndex < rt->road->points.size() - 1) { const auto& otherPoint = rt->road->points[rt->pointIndex + 1]; if (otherPoint != nextL && otherPoint != prevL) { // if way contains same segment (nodes) as different way (do not attach it) attachedSegment.reset(new RouteSegment(rt->road, rt->pointIndex, rt->road->points.size() - 1)); } } if ((direction == Model::RoadDirection::TwoWay || direction == Model::RoadDirection::OneWayForward) && rt->pointIndex > 0) { const auto& otherPoint = rt->road->points[rt->pointIndex - 1]; if (otherPoint != nextL && otherPoint != prevL) { // if way contains same segment (nodes) as different way (do not attach it) attachedSegment.reset(new RouteSegment(rt->road, rt->pointIndex, 0)); } } if (attachedSegment) segment->_attachedRoutes[qAbs(static_cast<int64_t>(pointIdx) - static_cast<int64_t>(segment->_startPointIndex))].push_back(qMove(attachedSegment)); } rt = rt->next; } }
void OsmAnd::MapRasterizer_P::rasterizePolygon( const Context& context, SkCanvas& canvas, const std::shared_ptr<const MapPrimitiviser::Primitive>& primitive) { const auto& points31 = primitive->sourceObject->points31; const auto& area31 = context.area31; assert(points31.size() > 2); assert(primitive->sourceObject->isClosedFigure()); assert(primitive->sourceObject->isClosedFigure(true)); ////////////////////////////////////////////////////////////////////////// //if ((primitive->sourceObject->id >> 1) == 9223372032559801460u) //{ // int i = 5; //} ////////////////////////////////////////////////////////////////////////// SkPaint paint = _defaultPaint; if (!updatePaint(context, paint, primitive->evaluationResult, PaintValuesSet::Layer_1, true)) return; // Construct and test geometry against bbox area SkPath path; bool containsAtLeastOnePoint = false; int pointIdx = 0; PointF vertex; Utilities::CHValue prevChValue; QVector< PointI > outerPoints; const auto pointsCount = points31.size(); auto pPoint = points31.constData(); for (auto pointIdx = 0; pointIdx < pointsCount; pointIdx++, pPoint++) { const auto& point = *pPoint; calculateVertex(context, point, vertex); // Hit-test if (!containsAtLeastOnePoint) { if (area31.contains(point)) containsAtLeastOnePoint = true; else outerPoints.push_back(point); const auto chValue = Utilities::computeCohenSutherlandValue(point, area31); if (Q_LIKELY(pointIdx > 0)) { // Check if line crosses area (reject only if points are on the same side) const auto intersectedChValue = prevChValue & chValue; if (static_cast<unsigned int>(intersectedChValue) != 0) containsAtLeastOnePoint = true; } prevChValue = chValue; } // Plot vertex if (pointIdx == 0) path.moveTo(vertex.x, vertex.y); else path.lineTo(vertex.x, vertex.y); } ////////////////////////////////////////////////////////////////////////// //if ((primitive->sourceObject->id >> 1) == 9223372032559801460u) //{ // int i = 5; //} ////////////////////////////////////////////////////////////////////////// if (!containsAtLeastOnePoint) { // Check area is inside polygon bool ok = true; ok = ok || containsHelper(outerPoints, area31.topLeft); ok = ok || containsHelper(outerPoints, area31.bottomRight); ok = ok || containsHelper(outerPoints, PointI(0, area31.bottom())); ok = ok || containsHelper(outerPoints, PointI(area31.right(), 0)); if (!ok) return; } ////////////////////////////////////////////////////////////////////////// //if ((primitive->sourceObject->id >> 1) == 95692962u) //{ // int i = 5; //} ////////////////////////////////////////////////////////////////////////// if (!primitive->sourceObject->innerPolygonsPoints31.isEmpty()) { path.setFillType(SkPath::kEvenOdd_FillType); for (const auto& polygon : constOf(primitive->sourceObject->innerPolygonsPoints31)) { pointIdx = 0; for (auto itVertex = cachingIteratorOf(constOf(polygon)); itVertex; ++itVertex, pointIdx++) { const auto& point = *itVertex; calculateVertex(context, point, vertex); if (pointIdx == 0) path.moveTo(vertex.x, vertex.y); else path.lineTo(vertex.x, vertex.y); } } } canvas.drawPath(path, paint); if (updatePaint(context, paint, primitive->evaluationResult, PaintValuesSet::Layer_2, false)) canvas.drawPath(path, paint); }
bool OsmAnd::MapPrimitivesProvider_P::obtainData( const TileId tileId, const ZoomLevel zoom, std::shared_ptr<MapPrimitivesProvider::Data>& outTiledData, MapPrimitivesProvider_Metrics::Metric_obtainData* const metric_, const IQueryController* const queryController) { #if OSMAND_PERFORMANCE_METRICS MapPrimitivesProvider_Metrics::Metric_obtainData localMetric; const auto metric = metric_ ? metric_ : &localMetric; #else const auto metric = metric_; #endif const Stopwatch totalStopwatch(metric != nullptr); std::shared_ptr<TileEntry> tileEntry; for (;;) { // Try to obtain previous instance of tile _tileReferences.obtainOrAllocateEntry(tileEntry, tileId, zoom, [] (const TiledEntriesCollection<TileEntry>& collection, const TileId tileId, const ZoomLevel zoom) -> TileEntry* { return new TileEntry(collection, tileId, zoom); }); // If state is "Undefined", change it to "Loading" and proceed with loading if (tileEntry->setStateIf(TileState::Undefined, TileState::Loading)) break; // In case tile entry is being loaded, wait until it will finish loading if (tileEntry->getState() == TileState::Loading) { QReadLocker scopedLcoker(&tileEntry->loadedConditionLock); // If tile is in 'Loading' state, wait until it will become 'Loaded' while (tileEntry->getState() != TileState::Loaded) REPEAT_UNTIL(tileEntry->loadedCondition.wait(&tileEntry->loadedConditionLock)); } if (!tileEntry->dataIsPresent) { // If there was no data, return same outTiledData.reset(); return true; } else { // Otherwise, try to lock tile reference outTiledData = tileEntry->dataWeakRef.lock(); // If successfully locked, just return it if (outTiledData) return true; // Otherwise consider this tile entry as expired, remove it from collection (it's safe to do that right now) // This will enable creation of new entry on next loop cycle _tileReferences.removeEntry(tileId, zoom); tileEntry.reset(); } } const Stopwatch totalTimeStopwatch( #if OSMAND_PERFORMANCE_METRICS true #else metric != nullptr #endif // OSMAND_PERFORMANCE_METRICS ); // Obtain map objects data tile std::shared_ptr<IMapObjectsProvider::Data> dataTile; std::shared_ptr<Metric> submetric; owner->mapObjectsProvider->obtainData( tileId, zoom, dataTile, metric ? &submetric : nullptr, nullptr); if (metric && submetric) metric->addOrReplaceSubmetric(submetric); if (!dataTile) { // Store flag that there was no data and mark tile entry as 'Loaded' tileEntry->dataIsPresent = false; tileEntry->setState(TileState::Loaded); // Notify that tile has been loaded { QWriteLocker scopedLcoker(&tileEntry->loadedConditionLock); tileEntry->loadedCondition.wakeAll(); } outTiledData.reset(); return true; } // Get primitivised objects std::shared_ptr<MapPrimitiviser::PrimitivisedObjects> primitivisedObjects; if (owner->mode == MapPrimitivesProvider::Mode::AllObjectsWithoutPolygonFiltering) { primitivisedObjects = owner->primitiviser->primitiviseAllMapObjects( zoom, dataTile->mapObjects, //NOTE: So far it's safe to turn off this cache. But it has to be rewritten. Since lock/unlock occurs too often, this kills entire performance //NOTE: Maybe a QuadTree-based cache with leaf-only locking will save up much. Or use supernodes, like DataBlock nullptr, //_primitiviserCache, nullptr, metric ? metric->findOrAddSubmetricOfType<MapPrimitiviser_Metrics::Metric_primitiviseAllMapObjects>().get() : nullptr); } else if (owner->mode == MapPrimitivesProvider::Mode::AllObjectsWithPolygonFiltering) { primitivisedObjects = owner->primitiviser->primitiviseAllMapObjects( Utilities::getScaleDivisor31ToPixel(PointI(owner->tileSize, owner->tileSize), zoom), zoom, dataTile->mapObjects, //NOTE: So far it's safe to turn off this cache. But it has to be rewritten. Since lock/unlock occurs too often, this kills entire performance //NOTE: Maybe a QuadTree-based cache with leaf-only locking will save up much. Or use supernodes, like DataBlock nullptr, //_primitiviserCache, nullptr, metric ? metric->findOrAddSubmetricOfType<MapPrimitiviser_Metrics::Metric_primitiviseAllMapObjects>().get() : nullptr); } else if (owner->mode == MapPrimitivesProvider::Mode::WithoutSurface) { primitivisedObjects = owner->primitiviser->primitiviseWithoutSurface( Utilities::getScaleDivisor31ToPixel(PointI(owner->tileSize, owner->tileSize), zoom), zoom, dataTile->mapObjects, //NOTE: So far it's safe to turn off this cache. But it has to be rewritten. Since lock/unlock occurs too often, this kills entire performance //NOTE: Maybe a QuadTree-based cache with leaf-only locking will save up much. Or use supernodes, like DataBlock nullptr, //_primitiviserCache, nullptr, metric ? metric->findOrAddSubmetricOfType<MapPrimitiviser_Metrics::Metric_primitiviseWithoutSurface>().get() : nullptr); } else // if (owner->mode == MapPrimitivesProvider::Mode::WithSurface) { const auto tileBBox31 = Utilities::tileBoundingBox31(tileId, zoom); primitivisedObjects = owner->primitiviser->primitiviseWithSurface( tileBBox31, PointI(owner->tileSize, owner->tileSize), zoom, dataTile->tileSurfaceType, dataTile->mapObjects, //NOTE: So far it's safe to turn off this cache. But it has to be rewritten. Since lock/unlock occurs too often, this kills entire performance //NOTE: Maybe a QuadTree-based cache with leaf-only locking will save up much. Or use supernodes, like DataBlock nullptr, //_primitiviserCache, nullptr, metric ? metric->findOrAddSubmetricOfType<MapPrimitiviser_Metrics::Metric_primitiviseWithSurface>().get() : nullptr); } // Create tile const std::shared_ptr<MapPrimitivesProvider::Data> newTiledData(new MapPrimitivesProvider::Data( tileId, zoom, dataTile, primitivisedObjects, new RetainableCacheMetadata(tileEntry, dataTile->retainableCacheMetadata))); // Publish new tile outTiledData = newTiledData; // Store weak reference to new tile and mark it as 'Loaded' tileEntry->dataIsPresent = true; tileEntry->dataWeakRef = newTiledData; tileEntry->setState(TileState::Loaded); // Notify that tile has been loaded { QWriteLocker scopedLcoker(&tileEntry->loadedConditionLock); tileEntry->loadedCondition.wakeAll(); } if (metric) metric->elapsedTime = totalStopwatch.elapsed(); #if OSMAND_PERFORMANCE_METRICS #if OSMAND_PERFORMANCE_METRICS <= 1 LogPrintf(LogSeverityLevel::Info, "%d polygons, %d polylines, %d points primitivised from %dx%d@%d in %fs", primitivisedObjects->polygons.size(), primitivisedObjects->polylines.size(), primitivisedObjects->polygons.size(), tileId.x, tileId.y, zoom, totalStopwatch.elapsed()); #else LogPrintf(LogSeverityLevel::Info, "%d polygons, %d polylines, %d points primitivised from %dx%d@%d in %fs:\n%s", primitivisedObjects->polygons.size(), primitivisedObjects->polylines.size(), primitivisedObjects->polygons.size(), tileId.x, tileId.y, zoom, totalStopwatch.elapsed(), qPrintable(metric ? metric->toString(QLatin1String("\t - ")) : QLatin1String("(null)"))); #endif // OSMAND_PERFORMANCE_METRICS <= 1 #endif // OSMAND_PERFORMANCE_METRICS return true; }
// returns true if the double-click was handled and false if it wasn't bool OnInverseSearch(WindowInfo *win, int x, int y) { if (!HasPermission(Perm_DiskAccess) || gPluginMode) return false; if (!win->IsDocLoaded() || win->dm->engineType != Engine_PDF) return false; // Clear the last forward-search result win->fwdSearchMark.rects.Reset(); InvalidateRect(win->hwndCanvas, NULL, FALSE); // On double-clicking error message will be shown to the user // if the PDF does not have a synchronization file if (!win->pdfsync) { int err = Synchronizer::Create(win->loadedFilePath, static_cast<PdfEngine *>(win->dm->engine), &win->pdfsync); if (err == PDFSYNCERR_SYNCFILE_NOTFOUND) { // We used to warn that "No synchronization file found" at this // point if gGlobalPrefs->enableTeXEnhancements is set; we no longer // so do because a double-click has several other meanings // (selecting a word or an image, navigating quickly using links) // and showing an unrelated warning in all those cases seems wrong return false; } if (err != PDFSYNCERR_SUCCESS) { ShowNotification(win, _TR("Synchronization file cannot be opened")); return true; } gGlobalPrefs->enableTeXEnhancements = true; } int pageNo = win->dm->GetPageNoByPoint(PointI(x, y)); if (!win->dm->ValidPageNo(pageNo)) return false; PointI pt = win->dm->CvtFromScreen(PointI(x, y), pageNo).Convert<int>(); ScopedMem<WCHAR> srcfilepath; UINT line, col; int err = win->pdfsync->DocToSource(pageNo, pt, srcfilepath, &line, &col); if (err != PDFSYNCERR_SUCCESS) { ShowNotification(win, _TR("No synchronization info at this position")); return true; } WCHAR *inverseSearch = gGlobalPrefs->inverseSearchCmdLine; if (!inverseSearch) // Detect a text editor and use it as the default inverse search handler for now inverseSearch = AutoDetectInverseSearchCommands(); ScopedMem<WCHAR> cmdline; if (inverseSearch) cmdline.Set(win->pdfsync->PrepareCommandline(inverseSearch, srcfilepath, line, col)); if (!str::IsEmpty(cmdline.Get())) { // resolve relative paths with relation to SumatraPDF.exe's directory ScopedMem<WCHAR> appDir(GetExePath()); if (appDir) appDir.Set(path::GetDir(appDir)); ScopedHandle process(LaunchProcess(cmdline, appDir)); if (!process) ShowNotification(win, _TR("Cannot start inverse search command. Please check the command line in the settings.")); } else if (gGlobalPrefs->enableTeXEnhancements) ShowNotification(win, _TR("Cannot start inverse search command. Please check the command line in the settings.")); if (inverseSearch != gGlobalPrefs->inverseSearchCmdLine) free(inverseSearch); return true; }
static void GeomTest() { PointD ptD(12.4, -13.6); utassert(ptD.x == 12.4 && ptD.y == -13.6); PointI ptI = ptD.ToInt(); utassert(ptI.x == 12 && ptI.y == -14); ptD = ptI.Convert<double>(); utassert(PointD(12, -14) == ptD); utassert(PointD(12.4, -13.6) != ptD); SizeD szD(7.7, -3.3); utassert(szD.dx == 7.7 && szD.dy == -3.3); SizeI szI = szD.ToInt(); utassert(szI.dx == 8 && szI.dy == -3); szD = szI.Convert<double>(); utassert(SizeD(8, -3) == szD); utassert(!szD.IsEmpty() && !szI.IsEmpty()); utassert(SizeI().IsEmpty() && SizeD().IsEmpty()); struct SRIData { int x1s, x1e, y1s, y1e; int x2s, x2e, y2s, y2e; bool intersect; int i_xs, i_xe, i_ys, i_ye; int u_xs, u_xe, u_ys, u_ye; } testData[] = { { 0,10, 0,10, 0,10, 0,10, true, 0,10, 0,10, 0,10, 0,10 }, /* complete intersect */ { 0,10, 0,10, 20,30,20,30, false, 0, 0, 0, 0, 0,30, 0,30 }, /* no intersect */ { 0,10, 0,10, 5,15, 0,10, true, 5,10, 0,10, 0,15, 0,10 }, /* { | } | */ { 0,10, 0,10, 5, 7, 0,10, true, 5, 7, 0,10, 0,10, 0,10 }, /* { | | } */ { 0,10, 0,10, 5, 7, 5, 7, true, 5, 7, 5, 7, 0,10, 0,10 }, { 0,10, 0,10, 5, 15,5,15, true, 5,10, 5,10, 0,15, 0,15 }, }; for (size_t i = 0; i < dimof(testData); i++) { struct SRIData *curr = &testData[i]; RectI rx1(curr->x1s, curr->y1s, curr->x1e - curr->x1s, curr->y1e - curr->y1s); RectI rx2 = RectI::FromXY(curr->x2s, curr->y2s, curr->x2e, curr->y2e); RectI isect = rx1.Intersect(rx2); if (curr->intersect) { utassert(!isect.IsEmpty()); utassert(isect.x == curr->i_xs && isect.y == curr->i_ys); utassert(isect.x + isect.dx == curr->i_xe && isect.y + isect.dy == curr->i_ye); } else { utassert(isect.IsEmpty()); } RectI urect = rx1.Union(rx2); utassert(urect.x == curr->u_xs && urect.y == curr->u_ys); utassert(urect.x + urect.dx == curr->u_xe && urect.y + urect.dy == curr->u_ye); /* if we swap rectangles, the results should be the same */ std::swap(rx1, rx2); isect = rx1.Intersect(rx2); if (curr->intersect) { utassert(!isect.IsEmpty()); utassert(isect.x == curr->i_xs && isect.y == curr->i_ys); utassert(isect.x + isect.dx == curr->i_xe && isect.y + isect.dy == curr->i_ye); } else { utassert(isect.IsEmpty()); } urect = rx1.Union(rx2); utassert(RectI::FromXY(curr->u_xs, curr->u_ys, curr->u_xe, curr->u_ye) == urect); utassert(!rx1.Contains(PointI(-2, -2))); utassert(rx1.Contains(rx1.TL())); utassert(!rx1.Contains(PointI(rx1.x, INT_MAX))); utassert(!rx1.Contains(PointI(INT_MIN, rx1.y))); } }
void OsmAnd::Utilities::scanlineFillPolygon(const unsigned int verticesCount, const PointF* vertices, std::function<void(const PointI&)> fillPoint) { // Find min-max of Y float yMinF, yMaxF; yMinF = yMaxF = vertices[0].y; for(auto idx = 1u; idx < verticesCount; idx++) { const auto& y = vertices[idx].y; if (y > yMaxF) yMaxF = y; if (y < yMinF) yMinF = y; } const auto rowMin = qFloor(yMinF); const auto rowMax = qFloor(yMaxF); // Build set of edges struct Edge { const PointF* v0; int startRow; const PointF* v1; int endRow; float xOrigin; float slope; int nextRow; }; QVector<Edge*> edges; edges.reserve(verticesCount); auto edgeIdx = 0u; for(auto idx = 0u, prevIdx = verticesCount - 1; idx < verticesCount; prevIdx = idx++) { auto v0 = &vertices[prevIdx]; auto v1 = &vertices[idx]; if (v0->y == v1->y) { // Horizontal edge auto edge = new Edge(); edge->v0 = v0; edge->v1 = v1; edge->startRow = qFloor(edge->v0->y); edge->endRow = qFloor(edge->v1->y); edge->xOrigin = edge->v0->x; edge->slope = 0; edge->nextRow = qFloor(edge->v0->y) + 1; edges.push_back(edge); //LogPrintf(LogSeverityLevel::Debug, "Edge %p y(%d %d)(%f %f), next row = %d", edge, edge->startRow, edge->endRow, edge->v0->y, edge->v1->y, edge->nextRow); continue; } const PointF* pLower = nullptr; const PointF* pUpper = nullptr; if (v0->y < v1->y) { // Up-going edge pLower = v0; pUpper = v1; } else if (v0->y > v1->y) { // Down-going edge pLower = v1; pUpper = v0; } // Fill edge auto edge = new Edge(); edge->v0 = pLower; edge->v1 = pUpper; edge->startRow = qFloor(edge->v0->y); edge->endRow = qFloor(edge->v1->y); edge->slope = (edge->v1->x - edge->v0->x) / (edge->v1->y - edge->v0->y); edge->xOrigin = edge->v0->x - edge->slope * (edge->v0->y - qFloor(edge->v0->y)); edge->nextRow = qFloor(edge->v1->y) + 1; for(auto vertexIdx = 0u; vertexIdx < verticesCount; vertexIdx++) { const auto& v = vertices[vertexIdx]; if (v.y > edge->v0->y && qFloor(v.y) < edge->nextRow) edge->nextRow = qFloor(v.y); } //LogPrintf(LogSeverityLevel::Debug, "Edge %p y(%d %d)(%f %f), next row = %d", edge, edge->startRow, edge->endRow, edge->v0->y, edge->v1->y, edge->nextRow); edges.push_back(edge); } // Sort edges by ascending Y qSort(edges.begin(), edges.end(), [](Edge* l, Edge* r) -> bool { return l->v0->y > r->v0->y; }); // Loop in [yMin .. yMax] QVector<Edge*> aet; aet.reserve(edges.size()); for(auto rowIdx = rowMin; rowIdx <= rowMax;) { //LogPrintf(LogSeverityLevel::Debug, "------------------ %d -----------------", rowIdx); // Find active edges int nextRow = rowMax; for(const auto& edge : constOf(edges)) { const auto isHorizontal = (edge->startRow == edge->endRow); if (nextRow > edge->nextRow && edge->nextRow > rowIdx && !isHorizontal) nextRow = edge->nextRow; if (edge->startRow != rowIdx) continue; if (isHorizontal) { // Fill horizontal edge const auto xMin = qFloor(qMin(edge->v0->x, edge->v1->x)); const auto xMax = qFloor(qMax(edge->v0->x, edge->v1->x)); /*for(auto x = xMin; x <= xMax; x++) fillPoint(PointI(x, rowIdx));*/ continue; } //LogPrintf(LogSeverityLevel::Debug, "line %d. Adding edge %p y(%f %f)", rowIdx, edge, edge->v0->y, edge->v1->y); aet.push_back(edge); continue; } // If there are no active edges, we've finished filling if (aet.isEmpty()) break; assert(aet.size() % 2 == 0); // Sort aet by X qSort(aet.begin(), aet.end(), [](Edge* l, Edge* r) -> bool { return l->v0->x > r->v0->x; }); // Find next row for(; rowIdx < nextRow; rowIdx++) { const unsigned int pairsCount = aet.size() / 2; auto itEdgeL = aet.cbegin(); auto itEdgeR = itEdgeL + 1; for(auto pairIdx = 0u; pairIdx < pairsCount; pairIdx++, itEdgeL = ++itEdgeR, ++itEdgeR) { auto lEdge = *itEdgeL; auto rEdge = *itEdgeR; // Fill from l to r auto lXf = lEdge->xOrigin + (rowIdx - lEdge->startRow + 0.5f) * lEdge->slope; auto rXf = rEdge->xOrigin + (rowIdx - rEdge->startRow + 0.5f) * rEdge->slope; auto xMinF = qMin(lXf, rXf); auto xMaxF = qMax(lXf, rXf); auto xMin = qFloor(xMinF); auto xMax = qFloor(xMaxF); LogPrintf(LogSeverityLevel::Debug, "line %d from %d(%f) to %d(%f)", rowIdx, xMin, xMinF, xMax, xMaxF); /*for(auto x = xMin; x <= xMax; x++) fillPoint(PointI(x, rowIdx));*/ } } // Deactivate those edges that have end at yNext for(auto itEdge = aet.begin(); itEdge != aet.end();) { auto edge = *itEdge; if (edge->endRow <= nextRow) { // When we're done processing the edge, fill it Y-by-X auto startCol = qFloor(edge->v0->x); auto endCol = qFloor(edge->v1->x); auto revSlope = 1.0f / edge->slope; auto yOrigin = edge->v0->y - revSlope * (edge->v0->x - qFloor(edge->v0->x)); auto xMax = qMax(startCol, endCol); auto xMin = qMin(startCol, endCol); for(auto colIdx = xMin; colIdx <= xMax; colIdx++) { auto yf = yOrigin + (colIdx - startCol + 0.5f) * revSlope; auto y = qFloor(yf); LogPrintf(LogSeverityLevel::Debug, "col %d(s%d) added Y = %d (%f)", colIdx, colIdx - startCol, y, yf); fillPoint(PointI(colIdx, y)); } ////////////////////////////////////////////////////////////////////////// auto yMax = qMax(edge->startRow, edge->endRow); auto yMin = qMin(edge->startRow, edge->endRow); for(auto rowIdx_ = yMin; rowIdx_ <= yMax; rowIdx_++) { auto xf = edge->xOrigin + (rowIdx_ - edge->startRow + 0.5f) * edge->slope; auto x = qFloor(xf); LogPrintf(LogSeverityLevel::Debug, "row %d(s%d) added Y = %d (%f)", rowIdx_, rowIdx_ - edge->startRow, x, xf); fillPoint(PointI(x, rowIdx_)); } ////////////////////////////////////////////////////////////////////////// //LogPrintf(LogSeverityLevel::Debug, "line %d. Removing edge %p y(%f %f)", rowIdx, edge, edge->v0->y, edge->v1->y); itEdge = aet.erase(itEdge); } else ++itEdge; } } // Cleanup for(const auto& edge : constOf(edges)) delete edge; }
LRESULT CALLBACK NotificationWnd::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\ { NotificationWnd *wnd = (NotificationWnd *)GetWindowLongPtr(hwnd, GWLP_USERDATA); if (WM_ERASEBKGND == message) { // do nothing, helps to avoid flicker return TRUE; } if (WM_TIMER == message && TIMEOUT_TIMER_ID == wParam) { if (wnd->notificationCb) wnd->notificationCb->RemoveNotification(wnd); else delete wnd; return 0; } if (WM_PAINT == message && wnd) { PAINTSTRUCT ps; HDC hdcWnd = BeginPaint(hwnd, &ps); ClientRect rect(hwnd); DoubleBuffer buffer(hwnd, rect); HDC hdc = buffer.GetDC(); HFONT oldfnt = SelectFont(hdc, wnd->font); RECT rTmp = rect.ToRECT(); DrawFrameControl(hdc, &rTmp, DFC_BUTTON, DFCS_BUTTONPUSH); if (wnd->highlight) { SetBkMode(hdc, OPAQUE); SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT)); } else { SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); } rect.Inflate(-PADDING, -PADDING); RectI rectMsg = rect; if (wnd->hasProgress) rectMsg.dy -= PROGRESS_HEIGHT + PADDING / 2; if (wnd->hasCancel) rectMsg.dx -= 20; ScopedMem<WCHAR> text(win::GetText(hwnd)); rTmp = rectMsg.ToRECT(); DrawText(hdc, text, -1, &rTmp, DT_SINGLELINE | DT_NOPREFIX); if (wnd->hasCancel) { rTmp = GetCancelRect(hwnd).ToRECT(); DrawFrameControl(hdc, &rTmp, DFC_CAPTION, DFCS_CAPTIONCLOSE | DFCS_FLAT); } if (wnd->hasProgress) { rect.dx = wnd->progressWidth; rect.y += rectMsg.dy + PADDING / 2; rect.dy = PROGRESS_HEIGHT; PaintRect(hdc, rect); rect.x += 2; rect.dx = (wnd->progressWidth - 3) * wnd->progress / 100; rect.y += 2; rect.dy -= 3; HBRUSH brush = GetStockBrush(BLACK_BRUSH); rTmp = rect.ToRECT(); FillRect(hdc, &rTmp, brush); DeleteObject(brush); } SelectFont(hdc, oldfnt); buffer.Flush(hdcWnd); EndPaint(hwnd, &ps); return 0; } if (WM_SETCURSOR == message && wnd->hasCancel) { POINT pt; if (GetCursorPosInHwnd(hwnd, pt) && GetCancelRect(hwnd).Contains(PointI(pt.x, pt.y))) { SetCursor(LoadCursor(NULL, IDC_HAND)); return TRUE; } } if (WM_LBUTTONUP == message && wnd->hasCancel) { if (GetCancelRect(hwnd).Contains(PointI(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))) { if (wnd->notificationCb) wnd->notificationCb->RemoveNotification(wnd); else delete wnd; return 0; } } return DefWindowProc(hwnd, message, wParam, lParam); }
* Author: bruno */ #include "Camera.hpp" #include <sstream> Box2D Camera::geometry = Box2D(0, 0, 640, 480); PointF Camera::lockedPosition = PointF(0, 0); bool Camera::fullScreen = true; bool Camera::scrollingX = false; bool Camera::scrollingY = false; bool Camera::lockedX = false; bool Camera::lockedY = false; bool Camera::lockedRange = false; bool Camera::translating = false; PointI Camera::beginRangeLock = PointI(0, 0); PointI Camera::endRangeLock = PointI(0, 0); Camera::Camera() { } Camera::~Camera() { } PointF Camera::getPosition() { return PointF(geometry.getLeftSide(), geometry.getTopSide()); } PointI Camera::getResolution() { return PointI(geometry.getWidth(), geometry.getHeight());
void OsmAnd::SymbolRasterizer_P::rasterize( const std::shared_ptr<const MapPrimitiviser::PrimitivisedObjects>& primitivisedObjects, QList< std::shared_ptr<const RasterizedSymbolsGroup> >& outSymbolsGroups, const FilterByMapObject filter, const std::shared_ptr<const IQueryController>& queryController) const { const auto& env = primitivisedObjects->mapPresentationEnvironment; for (const auto& symbolGroupEntry : rangeOf(constOf(primitivisedObjects->symbolsGroups))) { if (queryController && queryController->isAborted()) return; const auto& mapObject = symbolGroupEntry.key(); const auto& symbolsGroup = symbolGroupEntry.value(); ////////////////////////////////////////////////////////////////////////// //if (mapObject->toString().contains("1333827773")) //{ // int i = 5; //} ////////////////////////////////////////////////////////////////////////// // Apply filter, if it's present if (filter && !filter(mapObject)) continue; // Create group const std::shared_ptr<RasterizedSymbolsGroup> group(new RasterizedSymbolsGroup( mapObject)); // Total offset allows several symbols to stack into column. Offset specifies center of symbol bitmap. // This offset is computed only in case symbol is not on-path and not along-path PointI totalOffset; for (const auto& symbol : constOf(symbolsGroup->symbols)) { if (queryController && queryController->isAborted()) return; if (const auto& textSymbol = std::dynamic_pointer_cast<const MapPrimitiviser::TextSymbol>(symbol)) { TextRasterizer::Style style; if (!textSymbol->drawOnPath && textSymbol->shieldResourceName.isEmpty()) style.wrapWidth = textSymbol->wrapWidth; QList< std::shared_ptr<const SkBitmap> > backgroundLayers; if (!textSymbol->shieldResourceName.isEmpty()) { std::shared_ptr<const SkBitmap> shield; env->obtainTextShield(textSymbol->shieldResourceName, shield); if (shield) backgroundLayers.push_back(shield); } if (!textSymbol->underlayIconResourceName.isEmpty()) { std::shared_ptr<const SkBitmap> icon; env->obtainMapIcon(textSymbol->underlayIconResourceName, icon); if (icon) backgroundLayers.push_back(icon); } style.backgroundBitmap = SkiaUtilities::mergeBitmaps(backgroundLayers); if (!qFuzzyCompare(textSymbol->scaleFactor, 1.0f) && style.backgroundBitmap) { style.backgroundBitmap = SkiaUtilities::scaleBitmap( style.backgroundBitmap, textSymbol->scaleFactor, textSymbol->scaleFactor); } style .setBold(textSymbol->isBold) .setItalic(textSymbol->isItalic) .setColor(textSymbol->color) .setSize(static_cast<int>(textSymbol->size)); if (textSymbol->shadowRadius > 0) { style .setHaloColor(textSymbol->shadowColor) .setHaloRadius(textSymbol->shadowRadius); } float lineSpacing; float symbolExtraTopSpace; float symbolExtraBottomSpace; QVector<SkScalar> glyphsWidth; const auto rasterizedText = owner->textRasterizer->rasterize( textSymbol->value, style, textSymbol->drawOnPath ? &glyphsWidth : nullptr, &symbolExtraTopSpace, &symbolExtraBottomSpace, &lineSpacing); if (!rasterizedText) continue; #if OSMAND_DUMP_SYMBOLS { QDir::current().mkpath("text_symbols"); std::unique_ptr<SkImageEncoder> encoder(CreatePNGImageEncoder()); QString filename; filename.sprintf("%s\\text_symbols\\%p.png", qPrintable(QDir::currentPath()), rasterizedText.get()); encoder->encodeFile(qPrintable(filename), *rasterizedText.get(), 100); } #endif // OSMAND_DUMP_SYMBOLS if (textSymbol->drawOnPath) { // Publish new rasterized symbol const std::shared_ptr<RasterizedOnPathSymbol> rasterizedSymbol(new RasterizedOnPathSymbol( group, textSymbol)); rasterizedSymbol->bitmap = qMove(rasterizedText); rasterizedSymbol->order = textSymbol->order; rasterizedSymbol->contentType = RasterizedSymbol::ContentType::Text; rasterizedSymbol->content = textSymbol->value; rasterizedSymbol->languageId = textSymbol->languageId; rasterizedSymbol->minDistance = textSymbol->minDistance; rasterizedSymbol->glyphsWidth = glyphsWidth; group->symbols.push_back(qMove(rasterizedSymbol)); } else { // Calculate local offset. Since offset specifies center, it's a sum of // - vertical offset // - extra top space (which should be in texture, but not rendered, since transparent) // - height / 2 // This calculation is used only if this symbol is not first. Otherwise only following is used: // - vertical offset PointI localOffset; localOffset.y += textSymbol->verticalOffset; if (!group->symbols.isEmpty() && !textSymbol->drawAlongPath) { localOffset.y += symbolExtraTopSpace; localOffset.y += rasterizedText->height() / 2; } // Increment total offset if (!textSymbol->drawAlongPath) totalOffset += localOffset; // Publish new rasterized symbol const std::shared_ptr<RasterizedSpriteSymbol> rasterizedSymbol(new RasterizedSpriteSymbol(group, textSymbol)); rasterizedSymbol->bitmap = rasterizedText; rasterizedSymbol->order = textSymbol->order; rasterizedSymbol->contentType = RasterizedSymbol::ContentType::Text; rasterizedSymbol->content = textSymbol->value; rasterizedSymbol->languageId = textSymbol->languageId; rasterizedSymbol->minDistance = textSymbol->minDistance; rasterizedSymbol->location31 = textSymbol->location31; rasterizedSymbol->offset = textSymbol->drawAlongPath ? localOffset : totalOffset; rasterizedSymbol->drawAlongPath = textSymbol->drawAlongPath; if (!qIsNaN(textSymbol->intersectionSizeFactor)) { rasterizedSymbol->intersectionBBox = AreaI::fromCenterAndSize(PointI(), PointI( static_cast<int>(textSymbol->intersectionSizeFactor * rasterizedText->width()), static_cast<int>(textSymbol->intersectionSizeFactor * rasterizedText->height()))); } else if (!qIsNaN(textSymbol->intersectionSize)) { rasterizedSymbol->intersectionBBox = AreaI::fromCenterAndSize(PointI(), PointI( static_cast<int>(textSymbol->intersectionSize), static_cast<int>(textSymbol->intersectionSize))); } else if (!qIsNaN(textSymbol->intersectionMargin)) { rasterizedSymbol->intersectionBBox = AreaI::fromCenterAndSize(PointI(), PointI( rasterizedText->width() + static_cast<int>(textSymbol->intersectionMargin), rasterizedText->height() + static_cast<int>(textSymbol->intersectionMargin))); } else { rasterizedSymbol->intersectionBBox = AreaI::fromCenterAndSize(PointI(), PointI( static_cast<int>(rasterizedText->width()), static_cast<int>(rasterizedText->height()))); rasterizedSymbol->intersectionBBox.top() -= static_cast<int>(symbolExtraTopSpace); rasterizedSymbol->intersectionBBox.bottom() += static_cast<int>(symbolExtraBottomSpace); } group->symbols.push_back(qMove(std::shared_ptr<const RasterizedSymbol>(rasterizedSymbol))); // Next symbol should also take into account: // - height / 2 // - extra bottom space (which should be in texture, but not rendered, since transparent) // - spacing between lines if (!textSymbol->drawAlongPath) { totalOffset.y += rasterizedText->height() / 2; totalOffset.y += symbolExtraBottomSpace; totalOffset.y += qCeil(lineSpacing); } } } else if (const auto& iconSymbol = std::dynamic_pointer_cast<const MapPrimitiviser::IconSymbol>(symbol)) { std::shared_ptr<const SkBitmap> iconBitmap; if (!env->obtainMapIcon(iconSymbol->resourceName, iconBitmap) || !iconBitmap) continue; if (!qFuzzyCompare(iconSymbol->scaleFactor, 1.0f)) { iconBitmap = SkiaUtilities::scaleBitmap( iconBitmap, iconSymbol->scaleFactor, iconSymbol->scaleFactor); } std::shared_ptr<const SkBitmap> backgroundBitmap; if (!iconSymbol->shieldResourceName.isEmpty()) { env->obtainIconShield(iconSymbol->shieldResourceName, backgroundBitmap); if (!qFuzzyCompare(iconSymbol->scaleFactor, 1.0f) && backgroundBitmap) { backgroundBitmap = SkiaUtilities::scaleBitmap( backgroundBitmap, iconSymbol->scaleFactor, iconSymbol->scaleFactor); } } QList< std::shared_ptr<const SkBitmap> > layers; if (backgroundBitmap) layers.push_back(backgroundBitmap); for (const auto& overlayResourceName : constOf(iconSymbol->underlayResourceNames)) { std::shared_ptr<const SkBitmap> underlayBitmap; if (!env->obtainMapIcon(overlayResourceName, underlayBitmap) || !underlayBitmap) continue; layers.push_back(underlayBitmap); } layers.push_back(iconBitmap); for (const auto& overlayResourceName : constOf(iconSymbol->overlayResourceNames)) { std::shared_ptr<const SkBitmap> overlayBitmap; if (!env->obtainMapIcon(overlayResourceName, overlayBitmap) || !overlayBitmap) continue; layers.push_back(overlayBitmap); } // Compose final image const auto rasterizedIcon = SkiaUtilities::mergeBitmaps(layers); #if OSMAND_DUMP_SYMBOLS { QDir::current().mkpath("icon_symbols"); std::unique_ptr<SkImageEncoder> encoder(CreatePNGImageEncoder()); QString filename; filename.sprintf("%s\\icon_symbols\\%p.png", qPrintable(QDir::currentPath()), rasterizedIcon.get()); encoder->encodeFile(qPrintable(filename), *rasterizedIcon, 100); } #endif // OSMAND_DUMP_SYMBOLS // Calculate local offset. Since offset specifies center, it's a sum of // - height / 2 // This calculation is used only if this symbol is not first. Otherwise nothing is used. PointI localOffset; if (!qFuzzyIsNull(iconSymbol->offsetFactor.x)) localOffset.x = qRound(iconSymbol->offsetFactor.x * rasterizedIcon->width()); if (!qFuzzyIsNull(iconSymbol->offsetFactor.y)) localOffset.y = qRound(iconSymbol->offsetFactor.y * rasterizedIcon->height()); if (!group->symbols.isEmpty() && !iconSymbol->drawAlongPath) localOffset.y += rasterizedIcon->height() / 2; // Increment total offset if (!iconSymbol->drawAlongPath) totalOffset += localOffset; // Publish new rasterized symbol const std::shared_ptr<RasterizedSpriteSymbol> rasterizedSymbol(new RasterizedSpriteSymbol(group, iconSymbol)); rasterizedSymbol->bitmap = rasterizedIcon; rasterizedSymbol->order = iconSymbol->order; rasterizedSymbol->contentType = RasterizedSymbol::ContentType::Icon; rasterizedSymbol->content = iconSymbol->resourceName; rasterizedSymbol->languageId = LanguageId::Invariant; rasterizedSymbol->minDistance = iconSymbol->minDistance; rasterizedSymbol->location31 = iconSymbol->location31; rasterizedSymbol->offset = iconSymbol->drawAlongPath ? localOffset : totalOffset; rasterizedSymbol->drawAlongPath = iconSymbol->drawAlongPath; if (!qIsNaN(iconSymbol->intersectionSizeFactor)) { rasterizedSymbol->intersectionBBox = AreaI::fromCenterAndSize(PointI(), PointI( static_cast<int>(iconSymbol->intersectionSizeFactor * rasterizedIcon->width()), static_cast<int>(iconSymbol->intersectionSizeFactor * rasterizedIcon->height()))); } else if (!qIsNaN(iconSymbol->intersectionSize)) { rasterizedSymbol->intersectionBBox = AreaI::fromCenterAndSize(PointI(), PointI( static_cast<int>(iconSymbol->intersectionSize), static_cast<int>(iconSymbol->intersectionSize))); } else if (!qIsNaN(iconSymbol->intersectionMargin)) { rasterizedSymbol->intersectionBBox = AreaI::fromCenterAndSize(PointI(), PointI( rasterizedIcon->width() + static_cast<int>(iconSymbol->intersectionMargin), rasterizedIcon->height() + static_cast<int>(iconSymbol->intersectionMargin))); } else { rasterizedSymbol->intersectionBBox = AreaI::fromCenterAndSize(PointI(), PointI( static_cast<int>(rasterizedIcon->width()), static_cast<int>(rasterizedIcon->height()))); } group->symbols.push_back(qMove(std::shared_ptr<const RasterizedSymbol>(rasterizedSymbol))); // Next symbol should also take into account: // - height / 2 if (!iconSymbol->drawAlongPath) totalOffset.y += rasterizedIcon->height() / 2; } } // Add group to output outSymbolsGroups.push_back(qMove(group)); } }
PointI Camera::getResolution() { return PointI(geometry.getWidth(), geometry.getHeight()); }
std::shared_ptr<OsmAnd::MapSymbolsGroup> OsmAnd::MapMarker_P::inflateSymbolsGroup() const { QReadLocker scopedLocker(&_lock); bool ok; // Construct new map symbols group for this marker const std::shared_ptr<MapSymbolsGroup> symbolsGroup(new LinkedMapSymbolsGroup( std::const_pointer_cast<MapMarker_P>(shared_from_this()))); symbolsGroup->presentationMode |= MapSymbolsGroup::PresentationModeFlag::ShowAllOrNothing; int order = owner->baseOrder; if (owner->isAccuracyCircleSupported) { // Add a circle that represent precision circle const std::shared_ptr<AccuracyCircleMapSymbol> accuracyCircleSymbol(new AccuracyCircleMapSymbol( symbolsGroup)); accuracyCircleSymbol->order = order++; accuracyCircleSymbol->position31 = _position; VectorMapSymbol::generateCirclePrimitive(*accuracyCircleSymbol, owner->accuracyCircleBaseColor.withAlpha(0.25f)); accuracyCircleSymbol->isHidden = _isHidden && !_isAccuracyCircleVisible; accuracyCircleSymbol->scale = _accuracyCircleRadius; accuracyCircleSymbol->scaleType = VectorMapSymbol::ScaleType::InMeters; accuracyCircleSymbol->direction = Q_SNAN; symbolsGroup->symbols.push_back(accuracyCircleSymbol); // Add a ring-line that represent precision circle const std::shared_ptr<AccuracyCircleMapSymbol> precisionRingSymbol(new AccuracyCircleMapSymbol( symbolsGroup)); precisionRingSymbol->order = order++; precisionRingSymbol->position31 = _position; VectorMapSymbol::generateRingLinePrimitive(*precisionRingSymbol, owner->accuracyCircleBaseColor.withAlpha(0.4f)); precisionRingSymbol->isHidden = _isHidden && !_isAccuracyCircleVisible; precisionRingSymbol->scale = _accuracyCircleRadius; precisionRingSymbol->scaleType = VectorMapSymbol::ScaleType::InMeters; precisionRingSymbol->direction = Q_SNAN; symbolsGroup->symbols.push_back(precisionRingSymbol); } // Set of OnSurfaceMapSymbol from onMapSurfaceIcons for (const auto& itOnMapSurfaceIcon : rangeOf(constOf(owner->onMapSurfaceIcons))) { const auto key = itOnMapSurfaceIcon.key(); const auto& onMapSurfaceIcon = itOnMapSurfaceIcon.value(); std::shared_ptr<SkBitmap> iconClone(new SkBitmap()); ok = onMapSurfaceIcon->deepCopyTo(iconClone.get()); assert(ok); // Get direction float direction = 0.0f; const auto citDirection = _directions.constFind(key); if (citDirection != _directions.cend()) direction = *citDirection; const std::shared_ptr<KeyedOnSurfaceRasterMapSymbol> onMapSurfaceIconSymbol(new KeyedOnSurfaceRasterMapSymbol( key, symbolsGroup)); onMapSurfaceIconSymbol->order = order++; onMapSurfaceIconSymbol->bitmap = iconClone; onMapSurfaceIconSymbol->size = PointI(iconClone->width(), iconClone->height()); onMapSurfaceIconSymbol->content = QString().sprintf("markerGroup(%p:%p)->onMapSurfaceIconBitmap:%p", this, symbolsGroup.get(), iconClone->getPixels()); onMapSurfaceIconSymbol->languageId = LanguageId::Invariant; onMapSurfaceIconSymbol->position31 = _position; onMapSurfaceIconSymbol->direction = direction; onMapSurfaceIconSymbol->isHidden = _isHidden; symbolsGroup->symbols.push_back(onMapSurfaceIconSymbol); } // SpriteMapSymbol with pinIconBitmap as an icon if (owner->pinIcon) { std::shared_ptr<SkBitmap> pinIcon(new SkBitmap()); ok = owner->pinIcon->deepCopyTo(pinIcon.get()); assert(ok); const std::shared_ptr<BillboardRasterMapSymbol> pinIconSymbol(new BillboardRasterMapSymbol( symbolsGroup)); pinIconSymbol->order = order++; pinIconSymbol->bitmap = pinIcon; pinIconSymbol->size = PointI(pinIcon->width(), pinIcon->height()); pinIconSymbol->content = QString().sprintf("markerGroup(%p:%p)->pinIconBitmap:%p", this, symbolsGroup.get(), pinIcon->getPixels()); pinIconSymbol->languageId = LanguageId::Invariant; pinIconSymbol->position31 = _position; pinIconSymbol->offset = PointI(0, -pinIcon->height() / 2); pinIconSymbol->isHidden = _isHidden; pinIconSymbol->modulationColor = _pinIconModulationColor; symbolsGroup->symbols.push_back(pinIconSymbol); } return symbolsGroup; }
err_t JpegDecoder::readImage(Image& image) { JpegLibrary& jpeg = reinterpret_cast<JpegCodecProvider*>(_provider)->_jpegLibrary; FOG_ASSERT(jpeg.err == ERR_OK); err_t err = ERR_OK; struct jpeg_decompress_struct cinfo; MyJpegSourceMgr srcmgr; MyJpegErrorMgr jerr; JSAMPROW rowptr[1]; uint32_t format = IMAGE_FORMAT_RGB24; int bpp = 3; // Create a decompression structure and load the header. cinfo.err = jpeg.std_error(&jerr.errmgr); jerr.errmgr.error_exit = MyJpegErrorExit; jerr.errmgr.output_message = MyJpegMessage; if (setjmp(jerr.escape)) { // Error condition. jpeg.destroy_decompress(&cinfo); return ERR_IMAGE_LIBJPEG_ERROR; } jpeg.create_decompress(&cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct)); cinfo.src = (struct jpeg_source_mgr *)&srcmgr; srcmgr.pub.init_source = MyJpegInitSource; srcmgr.pub.fill_input_buffer = MyJpegFillInputBuffer; srcmgr.pub.skip_input_data = MyJpegSkipInputData; srcmgr.pub.resync_to_restart = jpeg.resync_to_restart; srcmgr.pub.term_source = MyJpegTermSource; srcmgr.pub.next_input_byte = srcmgr.buffer; srcmgr.pub.bytes_in_buffer = 0; srcmgr.stream = &_stream; jpeg.read_header(&cinfo, true); jpeg.calc_output_dimensions(&cinfo); _size.w = cinfo.output_width; _size.h = cinfo.output_height; _planes = 1; _actualFrame = 0; _framesCount = 1; // Check whether the image size is valid. if (!checkImageSize()) { err = ERR_IMAGE_INVALID_SIZE; goto _End; } jpeg.start_decompress(&cinfo); // Set 8 or 24-bit output. if (cinfo.out_color_space == JCS_GRAYSCALE) { if (cinfo.output_components != 1) { err = ERR_IMAGEIO_UNSUPPORTED_FORMAT; goto _End; } format = IMAGE_FORMAT_I8; bpp = 1; } else if (cinfo.out_color_space == JCS_RGB) { if (cinfo.output_components != 3) { err = ERR_IMAGEIO_UNSUPPORTED_FORMAT; goto _End; } } else { cinfo.out_color_space = JCS_RGB; cinfo.quantize_colors = false; } // Create the image. if (FOG_IS_ERROR(err = image.create(_size, format))) goto _End; if (format == IMAGE_FORMAT_I8) { image.setPalette(ImagePalette::fromGreyscale(256)); uint8_t* pixels = image.getFirstX(); ssize_t stride = image.getStride(); while (cinfo.output_scanline < cinfo.output_height) { rowptr[0] = (JSAMPROW)(pixels + (ssize_t)cinfo.output_scanline * stride); jpeg.read_scanlines(&cinfo, rowptr, (JDIMENSION)1); if ((cinfo.output_scanline & 15) == 0) updateProgress(cinfo.output_scanline, cinfo.output_height); } } else { ImageConverter converter; err = converter.create( ImageFormatDescription::getByFormat(format), ImageFormatDescription::fromArgb(24, IMAGE_FD_NONE, 0, FOG_JPEG_RGB24_RMASK, FOG_JPEG_RGB24_GMASK, FOG_JPEG_RGB24_BMASK)); if (FOG_IS_ERROR(err)) goto _End; ImageConverterClosure closure; converter.setupClosure(&closure, PointI(0, 0)); uint8_t* pixels = image.getFirstX(); ssize_t stride = image.getStride(); while (cinfo.output_scanline < cinfo.output_height) { rowptr[0] = (JSAMPROW)(pixels + (ssize_t)cinfo.output_scanline * stride); jpeg.read_scanlines(&cinfo, rowptr, (JDIMENSION)1); if (!converter.isCopy()) converter.getBlitFn()((uint8_t*)rowptr[0], (uint8_t*)rowptr[0], _size.w, &closure); if ((cinfo.output_scanline & 15) == 0) updateProgress(cinfo.output_scanline, cinfo.output_height); closure.ditherOrigin.y++; } } jpeg.finish_decompress(&cinfo); _End: jpeg.destroy_decompress(&cinfo); image._modified(); return err; }