void SE_Renderer::DrawSymbol(SE_RenderPrimitiveList& symbol, const SE_Matrix& xform, double angleRad, bool excludeRegion) { RS_Bounds extents(DBL_MAX, DBL_MAX, DBL_MAX, -DBL_MAX, -DBL_MAX, -DBL_MAX); unsigned int nprims = symbol.size(); for (unsigned int i=0; i<nprims; ++i) { SE_RenderPrimitive* primitive = symbol[i]; if (primitive->type == SE_RenderPrimitive_Polygon || primitive->type == SE_RenderPrimitive_Polyline) { SE_RenderPolyline* rp = (SE_RenderPolyline*)primitive; LineBuffer* lb = rp->geometry->xf_buffer(); // update the extents with this primitive RS_Bounds lbnds; lb->ComputeBounds(lbnds); extents.add_bounds(lbnds); if (m_bSelectionMode) { if (primitive->type == SE_RenderPrimitive_Polygon) DrawScreenPolygon(lb, &xform, m_selFillColor); m_selLineStroke.cap = rp->lineStroke.cap; m_selLineStroke.join = rp->lineStroke.join; m_selLineStroke.miterLimit = rp->lineStroke.miterLimit; DrawScreenPolyline(lb, &xform, m_selLineStroke); } else { if (primitive->type == SE_RenderPrimitive_Polygon) DrawScreenPolygon(lb, &xform, ((SE_RenderPolygon*)primitive)->fill); DrawScreenPolyline(lb, &xform, rp->lineStroke); } } else if (primitive->type == SE_RenderPrimitive_Text) { SE_RenderText* tp = (SE_RenderText*)primitive; // update the extents with this primitive's bounds for (int j=0; j<4; ++j) extents.add_point(primitive->bounds[j]); // get position and angle to use double x, y; xform.transform(tp->position[0], tp->position[1], x, y); RS_TextDef tdef = tp->tdef; tdef.rotation() += angleRad * M_180PI; if (m_bSelectionMode) { tdef.textcolor() = m_textForeColor; tdef.ghostcolor() = m_textBackColor; // tdef.framecolor() = m_textBackColor; // tdef.opaquecolor() = m_textBackColor; } // Here we cannot use the cached RS_TextMetrics in the SE_RenderText object. // We must recalculate the text metrics with the new tdef before we can call DrawScreenText. RS_TextMetrics tm; if (this->GetRSFontEngine()->GetTextMetrics(tp->content, tdef, tm, false)) DrawScreenText(tm, tdef, x, y, NULL, 0, 0.0); } else if (primitive->type == SE_RenderPrimitive_Raster) { SE_RenderRaster* rp = (SE_RenderRaster*)primitive; if (m_bSelectionMode) { // if the raster symbol is selected, then draw the mask selection polygon only LineBuffer *lb = LineBufferPool::NewLineBuffer(m_pPool, 5); std::auto_ptr<LineBuffer> spLB(lb); lb->MoveTo(rp->bounds[3].x, rp->bounds[3].y); for (int i = 0; i < 4; ++i) { lb->LineTo(rp->bounds[i].x, rp->bounds[i].y); } DrawScreenPolygon(lb, &xform, m_selFillColor); DrawScreenPolyline(lb, &xform, m_selLineStroke); LineBufferPool::FreeLineBuffer(m_pPool, spLB.release()); } else { ImageData& imgData = rp->imageData; if (imgData.data != NULL) { // update the extents with this primitive's bounds for (int j=0; j<4; ++j) extents.add_point(primitive->bounds[j]); // get position and angle to use double x, y; xform.transform(rp->position[0], rp->position[1], x, y); double angleDeg = (rp->angleRad + angleRad) * M_180PI; DrawScreenRaster(imgData.data, imgData.size, imgData.format, imgData.width, imgData.height, x, y, rp->extent[0], rp->extent[1], angleDeg, rp->opacity); } } } } if (nprims > 0) { // always compute the last symbol extent xform.transform(extents.minx, extents.miny, m_lastSymbolExtent[0].x, m_lastSymbolExtent[0].y); xform.transform(extents.maxx, extents.miny, m_lastSymbolExtent[1].x, m_lastSymbolExtent[1].y); xform.transform(extents.maxx, extents.maxy, m_lastSymbolExtent[2].x, m_lastSymbolExtent[2].y); xform.transform(extents.minx, extents.maxy, m_lastSymbolExtent[3].x, m_lastSymbolExtent[3].y); if (excludeRegion) AddExclusionRegion(m_lastSymbolExtent, 4); } else { // symbol contains no primitives - update last symbol extent assuming // zero symbol extent, but don't add any exclusion region xform.transform(0.0, 0.0, m_lastSymbolExtent[0].x, m_lastSymbolExtent[0].y); m_lastSymbolExtent[1].x = m_lastSymbolExtent[2].x = m_lastSymbolExtent[3].x = m_lastSymbolExtent[0].x; m_lastSymbolExtent[1].y = m_lastSymbolExtent[2].y = m_lastSymbolExtent[3].y = m_lastSymbolExtent[0].y; } }
/////////////////////////////////////////////////////////////////////////////// // Called when applying an area style on a feature geometry. Area styles can // can only be applied to polygon feature geometry types. void SE_Renderer::ProcessArea(SE_ApplyContext* ctx, SE_RenderAreaStyle* style) { // the feature geometry we're applying the style on... LineBuffer* featGeom = ctx->geometry; // can't apply an area style to point and linestring geometry types switch (featGeom->geom_type()) { case GeometryType_Point: case GeometryType_MultiPoint: case GeometryType_LineString: case GeometryType_MultiLineString: case GeometryType_CurveString: case GeometryType_MultiCurveString: return; } SE_Matrix w2s; GetWorldToScreenTransform(w2s); //-------------------------------------------------------------- // special code to handle simple solid fill styles //-------------------------------------------------------------- if (style->solidFill) { // just draw it and bail out of the layout function SE_RenderPolygon* rp = (SE_RenderPolygon*)style->symbol[0]; if (m_bSelectionMode) DrawScreenPolygon(featGeom, &w2s, m_selFillColor); else DrawScreenPolygon(featGeom, &w2s, rp->fill); return; } // transform the feature geometry to rendering space LineBuffer* xfgeom = LineBufferPool::NewLineBuffer(m_pPool, featGeom->point_count()); std::auto_ptr<LineBuffer> spLB(xfgeom); *xfgeom = *featGeom; int size = featGeom->point_count(); for (int i=0; i<size; ++i) w2s.transform(xfgeom->x_coord(i), xfgeom->y_coord(i)); // recompute the bounds RS_Bounds& bounds = const_cast<RS_Bounds&>(xfgeom->bounds()); bounds.minx = bounds.miny = bounds.minz = +DBL_MAX; bounds.maxx = bounds.maxy = bounds.maxz = -DBL_MAX; xfgeom->ComputeBounds(bounds); // account for any viewport rotation SE_AreaPositioning ap(xfgeom, style, GetWorldToScreenRotation()); double baserot = ap.PatternRotation(); SE_Matrix xform; SE_Matrix xformbase = *ctx->xform; xformbase.rotate(baserot); for (const Point2D* pos = ap.NextLocation(); pos != NULL; pos = ap.NextLocation()) { xform = xformbase; xform.translate(pos->x, pos->y); DrawSymbol(style->symbol, xform, baserot, style->addToExclusionRegion); } LineBufferPool::FreeLineBuffer(m_pPool, spLB.release()); }