在地图上添加POI
使用Tangram的Marker, 可以在地图上做各种标记, 效果图:
Tangram是通过Marker在地图上添加标记的,Marker分Point, Polyline和Polygon三种, 分别对应点、线、面三种几何体。
Tangram使用统一的Marker接口来管理Marker:
namespace Tangram { class Map { public: // Add a marker object to the map and return an ID for it; an ID of 0 indicates an invalid marker; // the marker will not be drawn until both styling and geometry are set using the functions below. MarkerID markerAdd(); // Remove a marker object from the map; returns true if the marker ID was found and successfully // removed, otherwise returns false. bool markerRemove(MarkerID _marker); // Set the styling for a marker object; _styling is a string of YAML that specifies a 'draw rule' // according to the scene file syntax; returns true if the marker ID was found and successfully // updated, otherwise returns false. bool markerSetStyling(MarkerID _marker, const char* _styling); // Set a bitmap to use as the image for a point marker; _data is a buffer of RGBA pixel data with // length of _width * _height; pixels are in row-major order beginning from the bottom-left of the // image; returns true if the marker ID was found and successfully updated, otherwise returns false. bool markerSetBitmap(MarkerID _marker, int _width, int _height, const unsigned int* _data); // Set the geometry of a marker to a point at the given coordinates; markers can have their // geometry set multiple times with possibly different geometry types; returns true if the // marker ID was found and successfully updated, otherwise returns false. bool markerSetPoint(MarkerID _marker, LngLat _lngLat); // Set the geometry of a marker to a point at the given coordinates; if the marker was previously // set to a point, this eases the position over the given duration in seconds with the given EaseType; // returns true if the marker ID was found and successfully updated, otherwise returns false. bool markerSetPointEased(MarkerID _marker, LngLat _lngLat, float _duration, EaseType _ease); // Set the geometry of a marker to a polyline along the given coordinates; _coordinates is a // pointer to a sequence of _count LngLats; markers can have their geometry set multiple times // with possibly different geometry types; returns true if the marker ID was found and // successfully updated, otherwise returns false. bool markerSetPolyline(MarkerID _marker, LngLat* _coordinates, int _count); // Set the geometry of a marker to a polygon with the given coordinates; _counts is a pointer // to a sequence of _rings integers and _coordinates is a pointer to a sequence of LngLats with // a total length equal to the sum of _counts; for each integer n in _counts, a polygon is created // by taking the next n LngLats from _coordinates, with winding order and internal polygons // behaving according to the GeoJSON specification; markers can have their geometry set multiple // times with possibly different geometry types; returns true if the marker ID was found and // successfully updated, otherwise returns false. bool markerSetPolygon(MarkerID _marker, LngLat* _coordinates, int* _counts, int _rings); // Set the visibility of a marker object; returns true if the marker ID was found and successfully // updated, otherwise returns false. bool markerSetVisible(MarkerID _marker, bool _visible); // Set the ordering of point marker object relative to other markers; higher values are drawn 'above'; // returns true if the marker ID was found and successfully updated, otherwise returns false. bool markerSetDrawOrder(MarkerID _marker, int _drawOrder); // Remove all marker objects from the map; Any marker IDs previously returned from 'markerAdd' // are invalidated after this. void markerRemoveAll(); };
}
我觉得使用统一的接口来处理Marker在易用性有些欠缺, 因此决定使用单独的class来处理: Marker, Polyline, Polygon.
Tangram使用各种style来处理Marker的显示效果, 可能是对Tangram的实现还没有了解清楚, 暂时没有发现直接给一个Marker加上label的方法, 只好采用了一个hack的方法: 同时生成两个Tangram::Marker, 一个用来显示icon, 另一个用来显示label。
头文件:
class MarkerImpl: public Marker { public: MarkerImpl(Tangram::Map* map); ~MarkerImpl(); // Mark interface private: virtual void setImage(const std::string &iconURI) override; virtual void setTitle(const std::string &title) override; private: Tangram::Map* m_map; Tangram::MarkerID m_iconID; //use this marker to show icon Tangram::MarkerID m_labelID; //use this marker to show label };
实现
void MarkerImpl::setImage(const std::string &iconURI) { QImage img(QString(iconURI.c_str())); int width = img.width(); int height = img.height(); auto argb = new unsigned int [width * height]; for(int h=height-1; h>-1; --h){ for(int w=0; w<width; ++w){ int pix = img.pixelColor(w, h).rgba(); int pb = (pix >> 16) & 0xff; int pr = (pix << 16) & 0x00ff0000; int pix1 = (pix & 0xff00ff00) | pr | pb; argb[w + h*width] = pix1; } } m_map->markerSetBitmap(m_iconID, width, height, argb); const char* MARKER_ICON_STYLE = "{ style: 'points', color: 'white', size: [%1px, %1px], order: 100, collide: false }"; QString iconStyle = QString(MARKER_ICON_STYLE).arg(width).arg(height); m_map->markerSetStyling(m_iconID, iconStyle.toStdString().c_str()); delete[] argb; } void MarkerImpl::setTitle(const std::string &title) { const char* MARKER_TEXT_STYLE = "{ style: 'text', text_source: 'function(){ return \"%1\"}', offset: [0px, 24px], text_wrap: false}"; QString labelStyle = QString(MARKER_TEXT_STYLE).arg(title.c_str()); m_map->markerSetStyling(m_labelID, labelStyle.toStdString().c_str()); }
Tangram的核心特性是可配置性, 通过一个YAML scene文件, 定义不同的style, 可以配置几乎所有的显示效果。 这是一个很大的话题, 以后单独分析