void VolumeSample::demonstrate(const int width, const int height, const Crystal::Graphics::ICamera<float>& camera) { glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); LegacyRenderer renderer; PointBuffer buffer; buffer.add(*volume); renderer.render(camera, buffer); LineBuffer lineBuffer; lineBuffer.add(*polygon, ColorRGBA<float>(1.0, 0.0, 0.0, 1.0)); renderer.render(camera, lineBuffer); }
void SE_PositioningAlgorithms::PathLabels(SE_ApplyContext* applyCtx, SE_RenderStyle* rstyle) { SE_Renderer* se_renderer = applyCtx->renderer; LineBuffer* geometry = applyCtx->geometry; // path labeling only applies to linestring feature geometry switch (geometry->geom_type()) { case GeometryType_LineString: case GeometryType_MultiLineString: case GeometryType_CurveString: case GeometryType_MultiCurveString: break; default: return; } // in the case of a point style, just use the default placement algorithm if (rstyle->type == SE_RenderStyle_Point) return SE_PositioningAlgorithms::Default(applyCtx, rstyle); // path labeling using an area style is not supported if (rstyle->type == SE_RenderStyle_Area) return; // the style needs to contain at least one primitive SE_RenderPrimitiveList& prims = rstyle->symbol; if (prims.size() == 0) return; // If the symbol contains just a single text element then add the // text as a regular path label (non-symbol). Use 0.5 as the // default value for the scale limit. if (prims.size() == 1 && prims[0]->type == SE_RenderPrimitive_Text) { SE_RenderText* rt = (SE_RenderText*)prims[0]; RS_LabelInfo info(0.0, 0.0, 0.0, 0.0, RS_Units_Device, rt->tdef); RS_OverpostType overpostType = rstyle->checkExclusionRegion? RS_OverpostType_AllFit : RS_OverpostType_All; return se_renderer->ProcessLabelGroup(&info, 1, rt->content, overpostType, rstyle->addToExclusionRegion, geometry, 0.5); } se_renderer->ProcessLineLabels(geometry, (SE_RenderLineStyle*)rstyle); }
void clear() { for (PointBufferMap::iterator it = pointmap.begin(); it != pointmap.end(); ++it) it->second.clear(); lines.clear(); lineIndices.clear(); }
void Shell::executeCommand(const LineBuffer& line){ _out << '\n'; _modules.commandExecute(line.line(), *this); const auto executionResult = handleExecuteCommand(line); _modules.commandExecuted(executionResult, line.line(), *this); switch (executionResult.status()) { case Status::NoMatch: _out << "Command not found [" << line.firstWord() << "]\n"; case Status::Ok: prompt(); break; case Status::Incomplete: _function.parse(":prompt_feed", _out, true); _column = _cursor.position().x; break; } }
explicit ContigPair(LineBuffer &source) : count(0) { auto const line = source.get(); if (line.first == nullptr) return; auto n = 0; for (auto i = line.first, end = i; ; ++end) { if (end == line.second || *end == '\t') { switch (n) { case 0: first.ref = unsigned(references[std::string(i, end)]); break; case 1: if (!string_to_i(first.start, i, end)) goto CONVERSION_ERROR; break; case 2: if (!string_to_i(first.end, i, end)) goto CONVERSION_ERROR; break; case 3: second.ref = unsigned(references[std::string(i, end)]); break; case 4: if (!string_to_i(second.start, i, end)) goto CONVERSION_ERROR; break; case 5: if (!string_to_i(second.end, i, end)) goto CONVERSION_ERROR; break; case 6: group = unsigned(groups[std::string(i, end)]); break; case 7: std::cerr << "extra data in record: " << std::string(line.first, line.second) << std::endl; return; } ++n; if (end == line.second) break; i = end + 1; } } if (n < 6) { std::cerr << "truncated record: " << std::string(line.first, line.second) << std::endl; return; } if (n < 7) group = groups[""]; count = 1; return; CONVERSION_ERROR: std::cerr << "error parsing record: " << std::string(line.first, line.second) << std::endl; return; }
void LegacyRenderer::render(const Matrix4d<float>& projectionMatrix, const Matrix4d<float>& modelviewMatrix, const LineBuffer& buffer, const GLfloat width) { const auto& positions = buffer.getPosition().get();// buffers[0].get(); const auto& colors = buffer.getColor().get(); const auto& indices = buffer.getIds(); if (positions.empty()) { return; } glLineWidth(width); glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glLoadMatrixf(projectionMatrix.toArray().data()); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glLoadMatrixf(modelviewMatrix.toArray().data()); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, positions.data()); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_FLOAT, 0, colors.data()); assert(glGetError() == GL_NO_ERROR); //glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(positions.size()) / 3); glDrawElements(GL_LINES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, indices.data()); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_DEPTH_TEST); glLineWidth(1); }
ParseResult Shell::handleExecuteCommand(const LineBuffer& line){ _buffer += line.line(); const ParseResult executionResult { _commands.parse(_buffer, _out, true)}; switch (executionResult.status()) { case Status::Incomplete: _buffer += '\n'; break; default: _buffer.clear(); break; } return executionResult; }
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 a line style on a feature geometry. Line styles can // only be applied to linestring and polygon feature geometry types. void SE_Renderer::ProcessLine(SE_ApplyContext* ctx, SE_RenderLineStyle* style) { // the feature geometry we're applying the style on... LineBuffer* featGeom = ctx->geometry; // can't apply a line style to point geometry types switch (featGeom->geom_type()) { case GeometryType_Point: case GeometryType_MultiPoint: return; } //-------------------------------------------------------------- // special code to handle simple straight solid line styles //-------------------------------------------------------------- if (style->solidLine) { // just draw it and bail out of the layout function SE_RenderPolyline* rp = (SE_RenderPolyline*)style->symbol[0]; SE_Matrix w2s; GetWorldToScreenTransform(w2s); if (m_bSelectionMode) { m_selLineStroke.cap = rp->lineStroke.cap; m_selLineStroke.join = rp->lineStroke.join; m_selLineStroke.miterLimit = rp->lineStroke.miterLimit; DrawScreenPolyline(featGeom, &w2s, m_selLineStroke); } else DrawScreenPolyline(featGeom, &w2s, rp->lineStroke); return; } //-------------------------------------------------------------- // handle the case repeat <= 0 - here we ignore vertex control //-------------------------------------------------------------- if (style->repeat <= 0.0) { // this can be handled using the overlap direct algorithm with: // - repeat set to larger than each contour length // - vertex angle limit set to >180 degrees double old_val = style->vertexAngleLimit; double old_rep = style->repeat; style->vertexAngleLimit = M_PI + 1.0; // any value greater than M_PI style->repeat = DBL_MAX; ProcessLineOverlapDirect(featGeom, style); style->vertexAngleLimit = old_val; style->repeat = old_rep; return; } //-------------------------------------------------------------- // check the vertex control type and call the appropriate helper //-------------------------------------------------------------- if (style->vertexControl == SE_VertexControl_OverlapNone) ProcessLineOverlapNone(featGeom, style); else if (style->vertexControl == SE_VertexControl_OverlapDirect) ProcessLineOverlapDirect(featGeom, style); else ProcessLineOverlapWrap(featGeom, style); }
/////////////////////////////////////////////////////////////////////////////// // 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()); }
void PointAdapter::Stylize(Renderer* renderer, RS_FeatureReader* features, bool initialPass, SE_Evaluator* eval, LineBuffer* geometry, MdfModel::FeatureTypeStyle* style, const MdfModel::MdfString* tooltip, const MdfModel::MdfString* url, RS_ElevationSettings* elevSettings, CSysTransformer* /*layer2mapxformer*/) { m_eval = eval; // no need to do anything if the style is not a point style, so quit if (FeatureTypeStyleVisitor::DetermineFeatureTypeStyle(style) != FeatureTypeStyleVisitor::ftsPoint) return; //------------------------------------------------------- // determine the rule for the feature //------------------------------------------------------- MdfModel::RuleCollection* prc = style->GetRules(); MdfModel::PointRule* rule = NULL; for (int i=0; i<prc->GetCount(); ++i) { rule = static_cast<MdfModel::PointRule*>(prc->GetAt(i)); // apply any filter on the rule - if it fails move to the next rule if (!ExecFilter(&rule->GetFilter())) { // don't stylize with failed rule rule = NULL; continue; } break; } if (!rule) return; MdfModel::PointSymbolization2D* psym = rule->GetSymbolization(); MdfModel::PointTypeStyle* pfs = (MdfModel::PointTypeStyle*)style; //------------------------------------------------------- // prepare the geometry on which to apply the style //------------------------------------------------------- // NOTE: clipping of geometry for rendering (the RequiresClipping // option) does not need to be done for points. Points // outside the map extents already get clipped away as part // of the FDO query. LineBuffer* lb = geometry; std::auto_ptr<LineBuffer> spClipLB; if (renderer->RequiresClipping()) { // clip geometry to given extents // NOTE: point styles do not require a clip offset LineBuffer* lbc = lb->Clip(renderer->GetBounds(), LineBuffer::ctAGF, m_lbPool); if (lbc != lb) { // if the clipped buffer is NULL (completely clipped) just move on to // the next feature if (!lbc) return; // otherwise continue processing with the clipped buffer lb = lbc; if (lb != geometry) spClipLB.reset(lb); } } //------------------------------------------------------- // do the StartFeature notification //------------------------------------------------------- RS_String tip; //TODO: this should be quick since we are not assigning RS_String eurl; const RS_String &theme = rule->GetLegendLabel(); if (tooltip && !tooltip->empty()) EvalString(*tooltip, tip); if (url && !url->empty()) EvalString(*url, eurl); // elevation settings RS_ElevationType elevType = RS_ElevationType_RelativeToGround; double zOffset = 0.0; double zExtrusion = 0.0; GetElevationParams(elevSettings, zOffset, zExtrusion, elevType); renderer->StartFeature(features, initialPass, tip.empty()? NULL : &tip, eurl.empty()? NULL : &eurl, theme.empty()? NULL : &theme, zOffset, zExtrusion, elevType); //------------------------------------------------------- // apply the style to the geometry using the renderer //------------------------------------------------------- // Process point symbol, if any. If there is no point symbol, there may // be a label which we will use as a symbol instead. This one does not // obey overposting, it is always there. The marker specified in the rule // is the one that does overposting. double mdefW = 0.01; double mdefH = 0.01; RS_Units mdefU = RS_Units_Device; double mdefRot = 0.0; // the actual position used for the marker by the renderer // may be returned in this structure to help place labels better RS_Bounds bounds = RS_Bounds(1.0, 1.0, 0.0, 0.0); // init invalid if (psym && psym->GetSymbol()) { // quick check if style is already cached RS_MarkerDef* cachedStyle = m_hPointSymCache[psym]; if (cachedStyle) { mdefW = cachedStyle->width(); mdefH = cachedStyle->height(); mdefU = cachedStyle->units(); mdefRot = cachedStyle->rotation(); renderer->ProcessMarker(lb, *cachedStyle, pfs->IsAllowOverpost(), &bounds); } else { RS_MarkerDef mdef; ObtainStyle(psym, mdef); mdefW = mdef.width(); mdefH = mdef.height(); mdefU = mdef.units(); mdefRot = mdef.rotation(); renderer->ProcessMarker(lb, mdef, pfs->IsAllowOverpost(), &bounds); } } //------------------------------------------------------- // do labeling if needed //------------------------------------------------------- MdfModel::Label* label = rule->GetLabel(); if (label && label->GetSymbol()) { // NOTE: clipping of geometry for labeling (the RequiresLabelClipping // option) does not need to be done for points. // TODO: compute label position double cx = std::numeric_limits<double>::quiet_NaN(); double cy = std::numeric_limits<double>::quiet_NaN(); double dummy; // multi should work for simple polygons also lb->Centroid(LineBuffer::ctPoint, &cx, &cy, &dummy); if (!_isnan(cx) && !_isnan(cy)) { // if there was no point symbol, the label is the symbol, // so we send without overposting and at the center point if (!psym || !psym->GetSymbol() || pfs->IsDisplayAsText()) { AddLabel(cx, cy, 0.0, false, label, RS_OverpostType_All, !pfs->IsAllowOverpost(), renderer, lb); } else { MdfModel::TextSymbol* text = label->GetSymbol(); RS_String txt; EvalString(text->GetText(), txt); if (!txt.empty()) { RS_TextDef def; ConvertTextDef(text, def); // if there's a symbol there are 8 possible positions to place the label // around the symbol // NOTE: at this point we know that mdef has been initialized with // whatever was in psym->GetSymbol() and that expressions have // been evaluated double op_pts[16]; // offset the label from the symbol's edge double offset = 0.001 * POINT_LABEL_OFFSET_MM; // in meters if (def.rotation() != 0.0) { // if the text label has rotation put the text at least half the font height // away, so that it doesn't intersect with the marker at the worst-case (45 // degree) rotation. offset += 0.5*def.font().height(); } // in case of mapping space we need to scale by map scale if (mdefU != RS_Units_Device) offset *= renderer->GetMapScale(); // compute how far label needs to be offset from center point of symbol double w = 0.5 * mdefW; double h = 0.5 * mdefH; double ch = 0; // vertical center point double cw = 0; // horizontal center point w += offset; h += offset; bool useBounds = bounds.IsValid(); if (useBounds) { bounds.maxx += offset; bounds.maxy += offset; bounds.minx -= offset; bounds.miny -= offset; ch = 0.5*(bounds.maxy + bounds.miny); cw = 0.5*(bounds.maxx + bounds.minx); } // take into account rotation of the symbol // find increased extents of the symbol bounds due to the rotation if (mdefRot != 0.0) { double rotRad = mdefRot * M_PI180; double cs = cos(rotRad); double sn = sin(rotRad); double wcs, nwcs, wsn, nwsn, hsn, nhsn, hcs, nhcs, cwsn, cwcs, chsn, chcs; // check to see if the bounds have been set if (useBounds) { wcs = bounds.maxx * cs; nwcs = bounds.minx * cs; wsn = bounds.maxx * sn; nwsn = bounds.minx * sn; hsn = bounds.maxy * sn; nhsn = bounds.miny * sn; hcs = bounds.maxy * cs; nhcs = bounds.miny * cs; } else { wcs = w * cs; nwcs = -wcs; wsn = w * sn; nwsn = -wsn; hsn = h * sn; nhsn = -hsn; hcs = h * cs; nhcs = -hcs; } cwsn = cw * sn; chsn = ch * sn; cwcs = cw * cs; chcs = ch * cs; // find the octant that the marker is rotated into, and shift the points accordingly. // this way, the overpost points are still within 22.5 degrees of an axis-aligned box. // (position 0 will always be the closest to Center-Right) double nangle = fmod(mdefRot, 360.0); if (nangle < 0.0) nangle += 360.0; int i = (((int)((nangle/45.0) + 0.5)) << 1) & 0x0000000f; // i is 2 * the octant op_pts[i++] = wcs - chsn; op_pts[i++] = wsn + chcs; i &= 0x0000000f; // & 15 does (mod 16) op_pts[i++] = wcs - hsn; op_pts[i++] = wsn + hcs; i &= 0x0000000f; op_pts[i++] = cwcs - hsn; op_pts[i++] = cwsn + hcs; i &= 0x0000000f; op_pts[i++] = nwcs - hsn; op_pts[i++] = nwsn + hcs; i &= 0x0000000f; op_pts[i++] = nwcs - chsn; op_pts[i++] = nwsn + chcs; i &= 0x0000000f; op_pts[i++] = nwcs - nhsn; op_pts[i++] = nwsn + nhcs; i &= 0x0000000f; op_pts[i++] = cwcs - nhsn; op_pts[i++] = cwsn + nhcs; i &= 0x0000000f; op_pts[i++] = wcs - nhsn; op_pts[i] = wsn + nhcs; } else { if (!useBounds) { bounds.maxx = w; bounds.minx = -w; bounds.maxy = h; bounds.miny = -h; } op_pts[ 0] = bounds.maxx; op_pts[ 1] = ch; op_pts[ 2] = bounds.maxx; op_pts[ 3] = bounds.maxy; op_pts[ 4] = cw; op_pts[ 5] = bounds.maxy; op_pts[ 6] = bounds.minx; op_pts[ 7] = bounds.maxy; op_pts[ 8] = bounds.minx; op_pts[ 9] = ch; op_pts[10] = bounds.minx; op_pts[11] = bounds.miny; op_pts[12] = cw; op_pts[13] = bounds.miny; op_pts[14] = bounds.maxx; op_pts[15] = bounds.miny; } RS_LabelInfo candidates[8]; def.halign() = RS_HAlignment_Left; def.valign() = RS_VAlignment_Half; candidates[0] = RS_LabelInfo(cx, cy, op_pts[0], op_pts[1], mdefU, def); def.valign() = RS_VAlignment_Descent; candidates[1] = RS_LabelInfo(cx, cy, op_pts[2], op_pts[3], mdefU, def); def.halign() = RS_HAlignment_Center; candidates[2] = RS_LabelInfo(cx, cy, op_pts[4], op_pts[5], mdefU, def); def.halign() = RS_HAlignment_Right; candidates[3] = RS_LabelInfo(cx, cy, op_pts[6], op_pts[7], mdefU, def); def.valign() = RS_VAlignment_Half; candidates[4] = RS_LabelInfo(cx, cy, op_pts[8], op_pts[9], mdefU, def); def.valign() = RS_VAlignment_Ascent; candidates[5] = RS_LabelInfo(cx, cy, op_pts[10], op_pts[11], mdefU, def); def.halign() = RS_HAlignment_Center; candidates[6] = RS_LabelInfo(cx, cy, op_pts[12], op_pts[13], mdefU, def); def.halign() = RS_HAlignment_Left; candidates[7] = RS_LabelInfo(cx, cy, op_pts[14], op_pts[15], mdefU, def); renderer->ProcessLabelGroup(candidates, 8, txt, RS_OverpostType_FirstFit, true, lb, text->GetScaleLimit()); } } } } // free clipped line buffer if the geometry was clipped if (spClipLB.get()) LineBufferPool::FreeLineBuffer(m_lbPool, spClipLB.release()); }
/////////////////////////////////////////////////////////////////////////////// // Called when applying a point style on a feature geometry. Point styles can // be applied to all feature geometry types. void SE_Renderer::ProcessPoint(SE_ApplyContext* ctx, SE_RenderPointStyle* style, RS_Bounds* bounds) { // the feature geometry we're applying the style on... LineBuffer* featGeom = ctx->geometry; double angleRad = 0.0; if (style->angleControl == SE_AngleControl_FromGeometry) { switch (featGeom->geom_type()) { case GeometryType_LineString: case GeometryType_MultiLineString: case GeometryType_Polygon: case GeometryType_MultiPolygon: { double x0, y0; featGeom->Centroid(LineBuffer::ctLine, &x0, &y0, &angleRad); break; } } } angleRad += style->angleRad; // also account for any viewport rotation angleRad += GetWorldToScreenRotation(); SE_Matrix xform; bool yUp = YPointsUp(); // see StylizationEngine::Stylize for a detailed explanation of these transforms SE_Matrix xformbase; xformbase.translate(style->offset[0], style->offset[1]); xformbase.rotate(yUp? angleRad : -angleRad); xformbase.premultiply(*ctx->xform); // render the points for (int i=0; i<featGeom->point_count(); ++i) { double x, y; featGeom->get_point(i, x, y); // transform to screen space - feature geometry is in [the original] mapping space WorldToScreenPoint(x, y, x, y); xform = xformbase; xform.translate(x, y); if (style->drawLast) AddLabel(featGeom, style, xform, angleRad); else DrawSymbol(style->symbol, xform, angleRad, style->addToExclusionRegion); } if (bounds) { // get the symbol bounds after applying the transforms bounds->minx = bounds->miny = +DBL_MAX; bounds->maxx = bounds->maxy = -DBL_MAX; for (int i=0; i<4; ++i) { RS_F_Point xfpt; xformbase.transform(style->bounds[i].x, style->bounds[i].y, xfpt.x, xfpt.y); bounds->add_point(xfpt); } } }
void OutputFile::writePixels (int numScanLines) { try { Lock lock (*_data); if (_data->slices.size() == 0) throw Iex::ArgExc ("No frame buffer specified " "as pixel data source."); // // Maintain two iterators: // nextWriteBuffer: next linebuffer to be written to the file // nextCompressBuffer: next linebuffer to compress // int first = (_data->currentScanLine - _data->minY) / _data->linesInBuffer; int nextWriteBuffer = first; int nextCompressBuffer; int stop; int step; int scanLineMin; int scanLineMax; { // // Create a task group for all line buffer tasks. When the // taskgroup goes out of scope, the destructor waits until // all tasks are complete. // TaskGroup taskGroup; // // Determine the range of lineBuffers that intersect the scan // line range. Then add the initial compression tasks to the // thread pool. We always add in at least one task but the // individual task might not do anything if numScanLines == 0. // if (_data->lineOrder == INCREASING_Y) { int last = (_data->currentScanLine + (numScanLines - 1) - _data->minY) / _data->linesInBuffer; scanLineMin = _data->currentScanLine; scanLineMax = _data->currentScanLine + numScanLines - 1; int numTasks = max (min ((int)_data->lineBuffers.size(), last - first + 1), 1); for (int i = 0; i < numTasks; i++) { ThreadPool::addGlobalTask (new LineBufferTask (&taskGroup, _data, first + i, scanLineMin, scanLineMax)); } nextCompressBuffer = first + numTasks; stop = last + 1; step = 1; } else { int last = (_data->currentScanLine - (numScanLines - 1) - _data->minY) / _data->linesInBuffer; scanLineMax = _data->currentScanLine; scanLineMin = _data->currentScanLine - numScanLines + 1; int numTasks = max (min ((int)_data->lineBuffers.size(), first - last + 1), 1); for (int i = 0; i < numTasks; i++) { ThreadPool::addGlobalTask (new LineBufferTask (&taskGroup, _data, first - i, scanLineMin, scanLineMax)); } nextCompressBuffer = first - numTasks; stop = last - 1; step = -1; } while (true) { if (_data->missingScanLines <= 0) { throw Iex::ArgExc ("Tried to write more scan lines " "than specified by the data window."); } // // Wait until the next line buffer is ready to be written // LineBuffer *writeBuffer = _data->getLineBuffer (nextWriteBuffer); writeBuffer->wait(); int numLines = writeBuffer->scanLineMax - writeBuffer->scanLineMin + 1; _data->missingScanLines -= numLines; // // If the line buffer is only partially full, then it is // not complete and we cannot write it to disk yet. // if (writeBuffer->partiallyFull) { _data->currentScanLine = _data->currentScanLine + step * numLines; writeBuffer->post(); return; } // // Write the line buffer // writePixelData (_data, writeBuffer); nextWriteBuffer += step; _data->currentScanLine = _data->currentScanLine + step * numLines; #ifdef DEBUG assert (_data->currentScanLine == ((_data->lineOrder == INCREASING_Y) ? writeBuffer->scanLineMax + 1: writeBuffer->scanLineMin - 1)); #endif // // Release the lock on the line buffer // writeBuffer->post(); // // If this was the last line buffer in the scanline range // if (nextWriteBuffer == stop) break; // // If there are no more line buffers to compress, // then only continue to write out remaining lineBuffers // if (nextCompressBuffer == stop) continue; // // Add nextCompressBuffer as a compression task // ThreadPool::addGlobalTask (new LineBufferTask (&taskGroup, _data, nextCompressBuffer, scanLineMin, scanLineMax)); // // Update the next line buffer we need to compress // nextCompressBuffer += step; } // // Finish all tasks // } // // Exeption handling: // // LineBufferTask::execute() may have encountered exceptions, but // those exceptions occurred in another thread, not in the thread // that is executing this call to OutputFile::writePixels(). // LineBufferTask::execute() has caught all exceptions and stored // the exceptions' what() strings in the line buffers. // Now we check if any line buffer contains a stored exception; if // this is the case then we re-throw the exception in this thread. // (It is possible that multiple line buffers contain stored // exceptions. We re-throw the first exception we find and // ignore all others.) // const string *exception = 0; for (int i = 0; i < _data->lineBuffers.size(); ++i) { LineBuffer *lineBuffer = _data->lineBuffers[i]; if (lineBuffer->hasException && !exception) exception = &lineBuffer->exception; lineBuffer->hasException = false; } if (exception) throw Iex::IoExc (*exception); } catch (Iex::BaseExc &e) { REPLACE_EXC (e, "Failed to write pixel data to image " "file \"" << fileName() << "\". " << e); throw; } }
void PolygonAdapter::Stylize(Renderer* renderer, RS_FeatureReader* features, bool initialPass, SE_Evaluator* eval, LineBuffer* geometry, MdfModel::FeatureTypeStyle* style, const MdfModel::MdfString* tooltip, const MdfModel::MdfString* url, RS_ElevationSettings* elevSettings, CSysTransformer* /*layer2mapxformer*/) { m_eval = eval; // no need to do anything if the style is not an area style, so quit if (FeatureTypeStyleVisitor::DetermineFeatureTypeStyle(style) != FeatureTypeStyleVisitor::ftsArea) return; //------------------------------------------------------- // determine the rule for the feature //------------------------------------------------------- MdfModel::RuleCollection* arc = style->GetRules(); MdfModel::AreaRule* rule = NULL; for (int i=0; i<arc->GetCount(); ++i) { rule = static_cast<MdfModel::AreaRule*>(arc->GetAt(i)); // apply any filter on the rule - if it fails move to the next rule if (!ExecFilter(&rule->GetFilter())) { // don't stylize with failed rule rule = NULL; continue; } break; } if (!rule) return; MdfModel::AreaSymbolization2D* asym = rule->GetSymbolization(); if (asym == NULL) return; //------------------------------------------------------- // evaluate the style to use //------------------------------------------------------- // quick check if style is already cached RS_FillStyle* fillStyle = m_hAreaSymCache[asym]; if (!fillStyle) { // if not, then we need to either cache or evaluate it fillStyle = &m_fillStyle; ObtainStyle(asym, *fillStyle); } //------------------------------------------------------- // compute the clip offset from the styles //------------------------------------------------------- double clipOffsetWU = 0.0; // in mapping units bool bClip = renderer->RequiresClipping(); bool bLabelClip = renderer->RequiresLabelClipping(); if (bClip || bLabelClip) { double mapScale = renderer->GetMapScale(); // in meters in device units double clipOffsetMeters = GetClipOffset(fillStyle->outline(), mapScale); // add one pixel's worth to handle any roundoff clipOffsetMeters += METERS_PER_INCH / renderer->GetDpi(); // limit the offset to something reasonable if (clipOffsetMeters > MAX_CLIPOFFSET_IN_METERS) clipOffsetMeters = MAX_CLIPOFFSET_IN_METERS; // convert to mapping units clipOffsetWU = clipOffsetMeters * mapScale / renderer->GetMetersPerUnit(); } //------------------------------------------------------- // prepare the geometry on which to apply the style //------------------------------------------------------- LineBuffer* lb = geometry; std::auto_ptr<LineBuffer> spClipLB; if (bClip) { // the clip region is the map request extents expanded by the offset RS_Bounds clip = renderer->GetBounds(); clip.minx -= clipOffsetWU; clip.miny -= clipOffsetWU; clip.maxx += clipOffsetWU; clip.maxy += clipOffsetWU; // clip geometry to given extents LineBuffer* lbc = lb->Clip(clip, LineBuffer::ctAGF, m_lbPool); if (lbc != lb) { // if the clipped buffer is NULL (completely clipped) just move on to // the next feature if (!lbc) return; // otherwise continue processing with the clipped buffer lb = lbc; if (lb != geometry) spClipLB.reset(lb); } } //------------------------------------------------------- // do the StartFeature notification //------------------------------------------------------- RS_String tip; //TODO: this should be quick since we are not assigning RS_String eurl; const RS_String &theme = rule->GetLegendLabel(); if (tooltip && !tooltip->empty()) EvalString(*tooltip, tip); if (url && !url->empty()) EvalString(*url, eurl); // elevation settings RS_ElevationType elevType = RS_ElevationType_RelativeToGround; double zOffset = 0.0; double zExtrusion = 0.0; GetElevationParams(elevSettings, zOffset, zExtrusion, elevType); renderer->StartFeature(features, initialPass, tip.empty()? NULL : &tip, eurl.empty()? NULL : &eurl, theme.empty()? NULL : &theme, zOffset, zExtrusion, elevType); //------------------------------------------------------- // apply the style to the geometry using the renderer //------------------------------------------------------- renderer->ProcessPolygon(lb, *fillStyle); //------------------------------------------------------- // do labeling if needed //------------------------------------------------------- MdfModel::Label* label = rule->GetLabel(); if (label && label->GetSymbol()) { // Make sure the geometry is clipped if label clipping is specified. // If bClip is true then the geometry is already clipped. if (!bClip && bLabelClip) { // the clip region is the map request extents expanded by the offset RS_Bounds clip = renderer->GetBounds(); clip.minx -= clipOffsetWU; clip.miny -= clipOffsetWU; clip.maxx += clipOffsetWU; clip.maxy += clipOffsetWU; LineBuffer* lbc = lb->Clip(clip, LineBuffer::ctAGF, m_lbPool); if (lbc != lb) { // if the clipped buffer is NULL (completely clipped) just move on to // the next feature if (!lbc) return; // otherwise continue processing with the clipped buffer lb = lbc; if (lb != geometry) spClipLB.reset(lb); } } double cx = std::numeric_limits<double>::quiet_NaN(); double cy = std::numeric_limits<double>::quiet_NaN(); double dummy; // multi should work for simple polygons too lb->Centroid(LineBuffer::ctArea, &cx, &cy, &dummy); if (!_isnan(cx) && !_isnan(cy)) AddLabel(cx, cy, 0.0, false, label, RS_OverpostType_AllFit, true, renderer, lb); } // free clipped line buffer if the geometry was clipped if (spClipLB.get()) LineBufferPool::FreeLineBuffer(m_lbPool, spClipLB.release()); }
void SE_PositioningAlgorithms::EightSurrounding(SE_ApplyContext* applyCtx, SE_RenderStyle* rstyle, double mm2su) { SE_Renderer* se_renderer = applyCtx->renderer; LineBuffer* geometry = applyCtx->geometry; // eight surrounding labeling only applies to point feature geometry switch (geometry->geom_type()) { case GeometryType_Point: case GeometryType_MultiPoint: break; default: return; } // eight surrounding labeling only works with point styles if (rstyle->type != SE_RenderStyle_Point) return; // the style needs to contain at least one primitive SE_RenderPrimitiveList& prims = rstyle->symbol; if (prims.size() == 0) return; SE_RenderPointStyle* rpstyle = (SE_RenderPointStyle*)rstyle; // get actual feature point and transform to screen space // TODO: in the case of a multi-point feature we get the average of all the points; // generating candidate labels around this point doesn't make a whole lot of // sense double cx = 0.0; double cy = 0.0; geometry->Centroid(LineBuffer::ctPoint, &cx, &cy, NULL); // don't add a label if we can't compute the centroid if (_isnan(cx) || _isnan(cy)) return; se_renderer->WorldToScreenPoint(cx, cy, cx, cy); // Get the extent of the last drawn point symbol so that we know how much to offset // the label. This call assumes the symbol draws right before the label. // TODO: remove this assumption const RS_F_Point* cfpts = se_renderer->GetLastSymbolExtent(); RS_F_Point fpts[4]; if(cfpts[0].x == 0 && cfpts[0].y == 0 && cfpts[1].x == 0 && cfpts[1].y == 0 && cfpts[2].x == 0 && cfpts[2].y == 0 && cfpts[3].x == 0 && cfpts[3].y == 0) { for (int i=0; i<4; ++i) { fpts[i].x = cx; fpts[i].y = cy; } } else memcpy(fpts, cfpts, 4*sizeof(RS_F_Point)); double dx = fpts[1].x - fpts[0].x; double dy = fpts[1].y - fpts[0].y; double symbol_rot_rad = atan2(dy, dx); // factor out position and rotation SE_Matrix ixform; ixform.translate(-cx, -cy); // factor out point position ixform.rotate(-symbol_rot_rad); // factor out rotation for (int i=0; i<4; ++i) ixform.transform(fpts[i].x, fpts[i].y); bool yUp = se_renderer->YPointsUp(); if (!yUp) symbol_rot_rad = -symbol_rot_rad; // unrotated bounds RS_Bounds symbol_bounds(fpts[0].x, fpts[0].y, fpts[2].x, fpts[2].y); double symbol_width = symbol_bounds.width(); // symbol width in screen units double symbol_height = symbol_bounds.height(); // symbol height in screen units // offset the label from the symbol's edge double offset = POINT_LABEL_OFFSET_MM * mm2su; // offset in screen units // make sure we have at least one pixel's worth of offset double screenUnitsPerPixel = MILLIMETERS_PER_INCH * se_renderer->GetScreenUnitsPerMillimeterDevice() / se_renderer->GetDpi(); if (offset < screenUnitsPerPixel) offset = screenUnitsPerPixel; // compute how far label needs to be offset from center point of symbol double w2 = 0.5 * symbol_width; double h2 = 0.5 * symbol_height; double ch = 0.0; // vertical center point double cw = 0.0; // horizontal center point w2 += offset; h2 += offset; bool useBounds = symbol_bounds.IsValid(); if (useBounds) { symbol_bounds.maxx += offset; symbol_bounds.maxy += offset; symbol_bounds.minx -= offset; symbol_bounds.miny -= offset; ch = 0.5*(symbol_bounds.maxy + symbol_bounds.miny); cw = 0.5*(symbol_bounds.maxx + symbol_bounds.minx); } // get the viewport rotation double w2sAngleRad = se_renderer->GetWorldToScreenRotation(); // take into account rotation of the symbol - find increased extents // of the symbol bounds due to the rotation double op_pts[16]; if (symbol_rot_rad != 0.0) { double cs = cos(symbol_rot_rad); double sn = sin(symbol_rot_rad); // check to see if the bounds have been set double wcs, nwcs, wsn, nwsn, hsn, nhsn, hcs, nhcs, cwsn, cwcs, chsn, chcs; if (useBounds) { wcs = symbol_bounds.maxx * cs; nwcs = symbol_bounds.minx * cs; wsn = symbol_bounds.maxx * sn; nwsn = symbol_bounds.minx * sn; hsn = symbol_bounds.maxy * sn; nhsn = symbol_bounds.miny * sn; hcs = symbol_bounds.maxy * cs; nhcs = symbol_bounds.miny * cs; } else { wcs = w2 * cs; nwcs = -wcs; wsn = w2 * sn; nwsn = -wsn; hsn = h2 * sn; nhsn = -hsn; hcs = h2 * cs; nhcs = -hcs; } cwsn = cw * sn; chsn = ch * sn; cwcs = cw * cs; chcs = ch * cs; // Find the octant that the symbol is rotated into, and shift the points accordingly. // This way the overpost points are still within 22.5 degrees of an axis-aligned box // (position 0 will always be the closest to Center-Right). // NOTE: The symbol rotation includes the viewport rotation. We want to use the // relative angle between these to compute the quadrant (it's the angle of // the symbol relative to the viewport which matters). double relativeAngle = symbol_rot_rad - w2sAngleRad; double nangle = fmod(relativeAngle * M_180PI, 360.0); if (nangle < 0.0) nangle += 360.0; int i = (((int)((nangle/45.0) + 0.5)) << 1) & 0x0000000f; // i is 2 * the octant op_pts[i++] = wcs - chsn; op_pts[i++] = wsn + chcs; i &= 0x0000000f; // & 15 does (mod 16) op_pts[i++] = wcs - hsn; op_pts[i++] = wsn + hcs; i &= 0x0000000f; op_pts[i++] = cwcs - hsn; op_pts[i++] = cwsn + hcs; i &= 0x0000000f; op_pts[i++] = nwcs - hsn; op_pts[i++] = nwsn + hcs; i &= 0x0000000f; op_pts[i++] = nwcs - chsn; op_pts[i++] = nwsn + chcs; i &= 0x0000000f; op_pts[i++] = nwcs - nhsn; op_pts[i++] = nwsn + nhcs; i &= 0x0000000f; op_pts[i++] = cwcs - nhsn; op_pts[i++] = cwsn + nhcs; i &= 0x0000000f; op_pts[i++] = wcs - nhsn; op_pts[i ] = wsn + nhcs; } else { if (!useBounds) { symbol_bounds.maxx = w2; symbol_bounds.minx = -w2; symbol_bounds.maxy = h2; symbol_bounds.miny = -h2; } op_pts[0 ] = symbol_bounds.maxx; op_pts[1 ] = ch; op_pts[2 ] = symbol_bounds.maxx; op_pts[3 ] = symbol_bounds.maxy; op_pts[4 ] = cw; op_pts[5 ] = symbol_bounds.maxy; op_pts[6 ] = symbol_bounds.minx; op_pts[7 ] = symbol_bounds.maxy; op_pts[8 ] = symbol_bounds.minx; op_pts[9 ] = ch; op_pts[10] = symbol_bounds.minx; op_pts[11] = symbol_bounds.miny; op_pts[12] = cw; op_pts[13] = symbol_bounds.miny; op_pts[14] = symbol_bounds.maxx; op_pts[15] = symbol_bounds.miny; } // check if the incoming point style contains just a single text element bool foundSingleText = false; if (prims.size() == 1) { if (prims[0]->type == SE_RenderPrimitive_Text) foundSingleText = true; } // OK, who says I can't write bad code? Behold: SE_LabelInfo candidates[8]; double yScale = yUp? 1.0 : -1.0; // which way does y go in the renderer? double angleRad = rpstyle->angleRad; // also account for the viewport rotation angleRad += w2sAngleRad; if (foundSingleText) { // In this case we set the appropriate alignments for the single text element // in each candidate label. This allows us to draw the symbol directly at the // candidate points surrounding the feature point. SE_RenderStyle* st0 = se_renderer->CloneRenderStyle(rpstyle); ((SE_RenderText*)st0->symbol[0])->tdef.halign() = RS_HAlignment_Left; ((SE_RenderText*)st0->symbol[0])->tdef.valign() = RS_VAlignment_Half; UpdateStyleBounds(st0, se_renderer); candidates[0].Set(cx + op_pts[ 0], cy + op_pts[ 1]*yScale, RS_Units_Device, angleRad, st0); SE_RenderStyle* st1 = se_renderer->CloneRenderStyle(st0); ((SE_RenderText*)st1->symbol[0])->tdef.valign() = RS_VAlignment_Descent; UpdateStyleBounds(st1, se_renderer); candidates[1].Set(cx + op_pts[ 2], cy + op_pts[ 3]*yScale, RS_Units_Device, angleRad, st1); SE_RenderStyle* st2 = se_renderer->CloneRenderStyle(st1); ((SE_RenderText*)st2->symbol[0])->tdef.halign() = RS_HAlignment_Center; UpdateStyleBounds(st2, se_renderer); candidates[2].Set(cx + op_pts[ 4], cy + op_pts[ 5]*yScale, RS_Units_Device, angleRad, st2); SE_RenderStyle* st3 = se_renderer->CloneRenderStyle(st2); ((SE_RenderText*)st3->symbol[0])->tdef.halign() = RS_HAlignment_Right; UpdateStyleBounds(st3, se_renderer); candidates[3].Set(cx + op_pts[ 6], cy + op_pts[ 7]*yScale, RS_Units_Device, angleRad, st3); SE_RenderStyle* st4 = se_renderer->CloneRenderStyle(st3); ((SE_RenderText*)st4->symbol[0])->tdef.valign() = RS_VAlignment_Half; UpdateStyleBounds(st4, se_renderer); candidates[4].Set(cx + op_pts[ 8], cy + op_pts[ 9]*yScale, RS_Units_Device, angleRad, st4); SE_RenderStyle* st5 = se_renderer->CloneRenderStyle(st4); ((SE_RenderText*)st5->symbol[0])->tdef.valign() = RS_VAlignment_Ascent; UpdateStyleBounds(st5, se_renderer); candidates[5].Set(cx + op_pts[10], cy + op_pts[11]*yScale, RS_Units_Device, angleRad, st5); SE_RenderStyle* st6 = se_renderer->CloneRenderStyle(st5); ((SE_RenderText*)st6->symbol[0])->tdef.halign() = RS_HAlignment_Center; UpdateStyleBounds(st6, se_renderer); candidates[6].Set(cx + op_pts[12], cy + op_pts[13]*yScale, RS_Units_Device, angleRad, st6); SE_RenderStyle* st7 = se_renderer->CloneRenderStyle(st6); ((SE_RenderText*)st7->symbol[0])->tdef.halign() = RS_HAlignment_Left; UpdateStyleBounds(st7, se_renderer); candidates[7].Set(cx + op_pts[14], cy + op_pts[15]*yScale, RS_Units_Device, angleRad, st7); } else { // In the general case we have to account for the label symbol's extents when we // position each candidate. For example, for candidate 1 (top right) we adjust the // position so that the bottom left corner of the label symbol's extent ends up at // the top right candidate point. double labelMinX = rpstyle->bounds[0].x; double labelMinY = rpstyle->bounds[0].y; double labelMaxX = rpstyle->bounds[2].x; double labelMaxY = rpstyle->bounds[2].y; double labelCtrX = 0.5*(labelMinX + labelMaxX); double labelCtrY = 0.5*(labelMinY + labelMaxY); SE_RenderStyle* st0 = se_renderer->CloneRenderStyle(rpstyle); candidates[0].Set(cx + op_pts[ 0] - labelMinX, cy + (op_pts[ 1] - labelCtrY)*yScale, RS_Units_Device, angleRad, st0); SE_RenderStyle* st1 = se_renderer->CloneRenderStyle(st0); candidates[1].Set(cx + op_pts[ 2] - labelMinX, cy + (op_pts[ 3] - labelMinY)*yScale, RS_Units_Device, angleRad, st1); SE_RenderStyle* st2 = se_renderer->CloneRenderStyle(st1); candidates[2].Set(cx + op_pts[ 4] - labelCtrX, cy + (op_pts[ 5] - labelMinY)*yScale, RS_Units_Device, angleRad, st2); SE_RenderStyle* st3 = se_renderer->CloneRenderStyle(st2); candidates[3].Set(cx + op_pts[ 6] - labelMaxX, cy + (op_pts[ 7] - labelMinY)*yScale, RS_Units_Device, angleRad, st3); SE_RenderStyle* st4 = se_renderer->CloneRenderStyle(st3); candidates[4].Set(cx + op_pts[ 8] - labelMaxX, cy + (op_pts[ 9] - labelCtrY)*yScale, RS_Units_Device, angleRad, st4); SE_RenderStyle* st5 = se_renderer->CloneRenderStyle(st4); candidates[5].Set(cx + op_pts[10] - labelMaxX, cy + (op_pts[11] - labelMaxY)*yScale, RS_Units_Device, angleRad, st5); SE_RenderStyle* st6 = se_renderer->CloneRenderStyle(st5); candidates[6].Set(cx + op_pts[12] - labelCtrX, cy + (op_pts[13] - labelMaxY)*yScale, RS_Units_Device, angleRad, st6); SE_RenderStyle* st7 = se_renderer->CloneRenderStyle(st6); candidates[7].Set(cx + op_pts[14] - labelMinX, cy + (op_pts[15] - labelMaxY)*yScale, RS_Units_Device, angleRad, st7); } se_renderer->ProcessSELabelGroup(candidates, 8, RS_OverpostType_FirstFit, true, NULL); }
static DWORD WINAPI StdErrReaderThread(LPVOID lpParameter) { CDownloader* pObj = ((PipeThreadParm*)lpParameter)->pObj; char Line[4096+1]; // When output is redirected, RAW ASCII is used const DWORD dwToRead = countof(Line)-1; DWORD dwRead, nValue, nErrCode; BOOL bSuccess; CEStr szLine; const wchar_t *ptr; const wchar_t sProgressMark[] = L" " CEDLOG_MARK_PROGR; const wchar_t sInformationMark[] = L" " CEDLOG_MARK_INFO; const wchar_t sErrorMark[] = L" " CEDLOG_MARK_ERROR; LineBuffer buffer = {}; bool bExit = false; while (!bExit) { bSuccess = ReadFile(pObj->mh_PipeErrRead, Line, dwToRead, &dwRead, NULL); if (!bSuccess || dwRead == 0) { nErrCode = GetLastError(); break; } _ASSERTE(dwRead < countof(Line)); Line[dwRead] = 0; // Ensure it is ASCIIZ // Append to the line-buffer buffer.AddBlock(Line, dwRead); // Parse read line while (buffer.GetLine(szLine)) { bool bProgress = false; if ((ptr = wcsstr(szLine, sProgressMark)) != NULL) { bProgress = true; if (pObj->mfn_Callback[dc_ProgressCallback]) { // 09:01:20.811{1234} Progr: Bytes downloaded 1656 wchar_t* ptrEnd = NULL; LPCWSTR pszFrom = wcspbrk(ptr+wcslen(sProgressMark), L"0123456789"); nValue = pszFrom ? wcstoul(pszFrom, &ptrEnd, 10) : 0; if (nValue) { CEDownloadInfo progrInfo = { sizeof(progrInfo), pObj->m_CallbackLParam[dc_ProgressCallback] }; progrInfo.argCount = 1; progrInfo.Args[0].argType = at_Uint; progrInfo.Args[0].uintArg = nValue; pObj->mfn_Callback[dc_ProgressCallback](&progrInfo); } } } // For logging purposes if (!bProgress && ((ptr = wcsstr(szLine, sErrorMark)) != NULL)) { if (pObj->mfn_Callback[dc_ErrCallback]) { CEDownloadInfo Error = { sizeof(Error), pObj->m_CallbackLParam[dc_ErrCallback], szLine.ms_Val }; pObj->mfn_Callback[dc_ErrCallback](&Error); } } else //if (bProgress || ((ptr = wcsstr(szLine, sInformationMark)) != NULL)) { if (pObj->mfn_Callback[dc_LogCallback]) { CEDownloadInfo Info = { sizeof(Info), pObj->m_CallbackLParam[dc_LogCallback], szLine.ms_Val }; pObj->mfn_Callback[dc_LogCallback](&Info); } // Exit? ptr = wcsstr(szLine, sInformationMark); if (ptr) { ptr += wcslen(sInformationMark); if (wcsncmp(ptr, L"Exit", 4) == 0) { bExit = true; break; } } } } } return 0; };
void SE_PositioningAlgorithms::MultipleHighwaysShields(SE_ApplyContext* applyCtx, SE_RenderStyle* rstyle, double mm2su, RS_FeatureReader* featureReader, SE_SymbolManager* symbolManager) { if (featureReader == NULL) return; SE_Renderer* se_renderer = applyCtx->renderer; LineBuffer* geometry = applyCtx->geometry; // this placement algorithm only applies to line styles if (rstyle->type != SE_RenderStyle_Line) return; SE_RenderLineStyle* rlStyle = (SE_RenderLineStyle*)rstyle; // ... and the units control must be absolute if (rlStyle->unitsControl != SE_UnitsControl_Absolute) return; // highway info format: countryCode|type1|num1|type2|num2|type3|num3|... // example: US|2|101|3|1 StringOfTokens highwayInfo(featureReader->GetString(L"Url"), L"|"); int shieldCount = (highwayInfo.getTokenCount() - 1) / 2; if (shieldCount < 1) return; double startOffset = rlStyle->startOffset; double increment = rlStyle->repeat; // the endOffset is used in this context as the increment between multiple shields in one group // double incrementS = 10.0 * mm2su; double incrementS = rlStyle->endOffset; // calc the overall length of this geometry double totalLen = 0.0; for (int i=0; i<geometry->cntr_count(); ++i) { int pt = geometry->contour_start_point(i); int last = geometry->contour_end_point(i); while (pt < last) { // transform the point to screen space double cx1, cy1, cx2, cy2; se_renderer->WorldToScreenPoint(geometry->x_coord(pt), geometry->y_coord(pt), cx1, cy1); pt++; se_renderer->WorldToScreenPoint(geometry->x_coord(pt), geometry->y_coord(pt), cx2, cy2); // calc length double dx = cx2 - cx1; double dy = cy2 - cy1; totalLen += sqrt(dx*dx + dy*dy); } } if (startOffset >= 0.0) { // calc optimal start offset (with rlStyle->startOffset taken as a minimum) // to co-locate shield groups placed on two-line highways where the two // parallel lines are processed from opposit ends. // this avoids a problem with perceived irregular placement when overposting // removes just some of the duplicate shields double shieldGroupLen = (shieldCount - 1) * incrementS; // length in excess of the required length to place one group with startOffset on each side double availLen = totalLen - (shieldGroupLen + 2.0 * startOffset); if (availLen < 0.0) { // there is no room to 'properly' place even one group, nothing to do but cry about it return; } int numAdditionalGroups = (int) (availLen / (shieldGroupLen + increment)); double additionalOffset = (availLen - numAdditionalGroups * (shieldGroupLen + increment)) / 2; startOffset += additionalOffset; } else { // negative startOffset value disables the optimization // use absolute value as the offset startOffset = -startOffset; } SE_RenderPrimitiveList* symbolVectors = new SE_RenderPrimitiveList[shieldCount]; std::wstring countryCode = highwayInfo.getFirstToken(); int shieldIndex; for (shieldIndex=0; shieldIndex<shieldCount; ++shieldIndex) { std::wstring shieldType = highwayInfo.getNextToken(); std::wstring highwayNum = highwayInfo.getNextToken(); // first the shield graphic SE_RenderRaster* rr = new SE_RenderRaster(); std::wstring imgName = HIGWAY_SHIELD_SYMBOLS_PREFIX + countryCode + L"_" + shieldType + L".png"; symbolManager->GetImageData(HIGWAY_SHIELD_SYMBOLS_RESOURCE.c_str(), imgName.c_str(), rr->imageData); if (rr->imageData.size == 0) { // could not find the image or resource // we could fall back and try to pick up the image from a disk file like this: // std::wstring imgPathName = HIGWAY_SHIELD_SYMBOLS_LOCATION + imgName; // rr->pngPtr = symbolManager->GetImageData(L"", imgPathName.c_str(), rr->pngSize); // but let's not do that unless really necessary // cannot just leave this shield empty, that causes exceptions later, so bail out // TODO: find a better way to handle this condition return; } rr->position[0] = 0.0; rr->position[1] = 0.0; rr->extent[0] = 20.0; rr->extent[1] = 20.0; rr->angleRad = 0.0; if (highwayNum.length() == 1) rr->extent[0] = ((shieldType == L"3")? 25.0 : 20.0); else if (highwayNum.length() == 2) rr->extent[0] = 25.0; else rr->extent[0] = 30.0; double w = 0.5 * rr->extent[0]; double h = 0.5 * rr->extent[1]; rr->bounds[0].x = -w; rr->bounds[0].y = -h; rr->bounds[1].x = w; rr->bounds[1].y = -h; rr->bounds[2].x = w; rr->bounds[2].y = h; rr->bounds[3].x = -w; rr->bounds[3].y = h; // the shield graphic is ready symbolVectors[shieldIndex].push_back(rr); // now symbol for the highway number SE_RenderText* rt = new SE_RenderText(); rt->content = highwayNum; rt->position[0] = 0.0; rt->position[1] = 0.0; rt->tdef.font().name() = L"Arial"; rt->tdef.font().height() = 10.0*0.001 / mm2su; // convert mm to meters rt->tdef.rotation() = 0.0; rt->tdef.halign() = RS_HAlignment_Center; rt->tdef.valign() = RS_VAlignment_Half; if (shieldType == L"1") { rt->tdef.textcolor() = RS_Color(255, 255, 255, 255); } else { rt->tdef.textcolor() = RS_Color(0, 0, 0, 255); } rt->tdef.textbg() = RS_TextBackground_None; rt->tdef.font().style() = RS_FontStyle_Bold; // the number graphic is ready symbolVectors[shieldIndex].push_back(rt); } SE_Matrix symxf; shieldIndex = 0; // account for any viewport rotation double angleRad = se_renderer->GetWorldToScreenRotation(); // init position along the whole geometry to the start offset double drawpos = startOffset; for (int j=0; j<geometry->cntr_count(); ++j) { // current polyline int pt = geometry->contour_start_point(j); int last = geometry->contour_end_point(j); while (pt < last) { symxf.setIdentity(); symxf.rotate(angleRad); // current line segment // transform the point to screen space double cx1, cy1, cx2, cy2; se_renderer->WorldToScreenPoint(geometry->x_coord(pt), geometry->y_coord(pt), cx1, cy1); pt++; se_renderer->WorldToScreenPoint(geometry->x_coord(pt), geometry->y_coord(pt), cx2, cy2); // calc length double dx = cx2 - cx1; double dy = cy2 - cy1; double len = sqrt(dx*dx + dy*dy); // check if completely skipping current segment since it is smaller than the increment if (drawpos < len) { double invlen = 1.0 / len; double dx_fact = dx * invlen; double dy_fact = dy * invlen; double tx = cx1 + dx_fact * drawpos; double ty = cy1 + dy_fact * drawpos; symxf.translate(tx, ty); double dx_incr = dx_fact * increment; // x/y incr between groups of shields double dy_incr = dy_fact * increment; double dx_incS = dx_fact * incrementS; // x/y incr between shields in a group double dy_incS = dy_fact * incrementS; // follow the segment and place the shield symbols alternated via shieldIndex while (drawpos < len) { if (rlStyle->drawLast) { rlStyle->symbol = symbolVectors[shieldIndex]; memcpy(rlStyle->bounds, symbolVectors[shieldIndex].front()->bounds, sizeof(rlStyle->bounds)); SE_RenderStyle* clonedStyle = se_renderer->CloneRenderStyle(rlStyle); SE_LabelInfo info(symxf.x2, symxf.y2, RS_Units_Device, angleRad, clonedStyle); RS_OverpostType overpostType = rlStyle->checkExclusionRegion? RS_OverpostType_AllFit : RS_OverpostType_All; se_renderer->ProcessSELabelGroup(&info, 1, overpostType, rlStyle->addToExclusionRegion, geometry); } else { se_renderer->DrawSymbol(symbolVectors[shieldIndex], symxf, angleRad); // TODO: if this is ever needed ... // if (rlStyle->addToExclusionRegion) // se_renderer->AddExclusionRegion(style, symxf, 0.0); } // move on to the next shield, if beyond the last one go back to the first shieldIndex++; if (shieldIndex < shieldCount) { symxf.translate(dx_incS, dy_incS); drawpos += incrementS; } else { // finished with one group // go back to the first symbol and advance using the full increment shieldIndex = 0; symxf.translate(dx_incr, dy_incr); drawpos += increment; } } } drawpos -= len; } } // cleanup time // the rlStyle->symbol has been assigned various values from the 'symbolVectors', // 'un-assign' it, so that we can clean them up rlStyle->symbol.clear(); for (shieldIndex=0; shieldIndex<shieldCount; ++shieldIndex) { for (SE_RenderPrimitiveList::iterator iter = symbolVectors[shieldIndex].begin(); iter != symbolVectors[shieldIndex].end(); ++iter) { // necessary since destructor of SE_RenderPrimitive is not virtual switch ((*iter)->type) { case SE_RenderPrimitive_Polyline: delete (SE_RenderPolyline*)(*iter); break; case SE_RenderPrimitive_Polygon: delete (SE_RenderPolygon*)(*iter); break; case SE_RenderPrimitive_Raster: delete (SE_RenderRaster*)(*iter); break; case SE_RenderPrimitive_Text: delete (SE_RenderText*)(*iter); break; default: throw; // means there is a bug } } } delete [] symbolVectors; }
static int process(VDB::Writer const &out, LineBuffer &ifs) { auto active = std::vector<ContigPair>(); auto ref = decltype(active.front().first.ref)(0); ///< the active reference (first read) auto end = decltype(active.front().first.end)(0); ///< the largest ending position (first read) seen so far; the is the end of the active window unsigned long long in_count = 0; unsigned long long out_count = 0; unsigned long long gapless_count = 0; auto time0 = time(nullptr); auto freq = 0.1; auto report = freq; for ( ; ; ) { auto pair = ContigPair(ifs); auto const isEOF = pair.count == 0; if ((!active.empty() && (pair.first.ref != ref || pair.first.start >= end)) || isEOF) { // new pair is outside the active window (or EOF); // output the active contig pairs and empty the window for (auto && i : active) { if (i.first.ref == i.second.ref && i.second.start < i.first.end) { // the region is gapless, i.e. the mate-pair gap has been filled in i.first.end = i.second.start = 0; } } for (auto i = decltype(active.size())(0); i < active.size(); ++i) { if (active[i].first.end != 0 || active[i].second.end != 0) continue; // active[i] is gapless auto const group = active[i].group; auto start = active[i].first.start; auto end = active[i].second.end; AGAIN: for (auto j = decltype(i)(0); j < active.size(); ++j) { if (j == i) continue; auto const &J = active[j]; if (J.group != group || J.second.ref != ref || J.first.start >= end || J.second.end <= start) continue; // active[j] overlaps active[i] if ((J.first.end == 0 && J.second.start == 0) ///< active[j] is also gapless || (start < J.first.end && J.second.start < end)) ///< or active[i] covers active[j]'s gap { start = std::min(start, J.first.start); end = std::max(end, J.second.end); active[i].first.start = start; active[i].second.end = end; active[i].count += J.count; if (j < i) --i; active.erase(active.begin() + j); goto AGAIN; } } } std::sort(active.begin(), active.end(), ///< want order to be canonical; should be mostly in-order already [](ContigPair const &a, ContigPair const &b) { if (a.first.start < b.first.start) return true; if (a.first.start > b.first.start) return false; if (a.first.end == 0 && a.second.start == 0) { if (b.first.end == 0 && b.second.start == 0) { if (a.second.end < b.second.end) return false; ///< longer one goes first if (a.second.end > b.second.end) return true; } else if (a.second.ref == b.second.ref) { return true; ///< gapless one goes first } else { return a.second.ref < b.second.ref; } } else if (b.first.end == 0 && b.second.start == 0) { if (a.second.ref == b.second.ref) { return false; ///< gapless one goes first } else { return a.second.ref < b.second.ref; } } else { // both have a gap if (a.first.end < b.first.end) return true; if (a.first.end > b.first.end) return false; if (a.second.ref < b.second.ref) return true; if (a.second.ref > b.second.ref) return false; if (a.second.start < b.second.start) return true; if (a.second.start > b.second.start) return false; if (a.second.end < b.second.end) return true; if (a.second.end > b.second.end) return false; } return a.group < b.group; }); for (auto && i : active) { if (i.second.start == 0 && i.first.end == 0) ++gapless_count; i.write(out); ++out_count; } active.clear(); if (isEOF) goto REPORT; } if (active.empty()) { ref = pair.first.ref; end = pair.first.end; active.emplace_back(pair); } else { for ( ; ; ) { unsigned maxOverlap = 0; auto merge = active.size(); ///< index of an existing contig pair into which the new pair should be merged for (auto i = active.size(); i != 0; ) { ///< the best overlap is probably near the end of the list, so start at the back --i; ///< and loop backwards auto const &j = active[i]; if (j.group == pair.group && j.second.ref == pair.second.ref) { if (j == pair) { /// found an exact match, and since the list is unique, we're done merge = i; break; } auto const start1 = std::max(pair.first.start, j.first.start); auto const start2 = std::max(pair.second.start, j.second.start); auto const end1 = std::min(pair.first.end, j.first.end); auto const end2 = std::min(pair.second.end, j.second.end); /// the regions of overlap are [start1 - end1), [start2 - end2) /// if either are empty (start >= end) then we aren't interested in the contig pair if (start1 < end1 && start2 < end2) { unsigned const overlap = (end1 - start1) + (end2 - start2); if (maxOverlap < overlap) { maxOverlap = overlap; merge = i; } } } } if (merge == active.size()) { end = std::max(end, pair.first.end); active.emplace_back(pair); break; } auto const mergedPair = active[merge] + pair; if (active[merge] == mergedPair) { active[merge] = mergedPair; break; } pair = mergedPair; active.erase(active.begin() + merge); } } ++in_count; if (ifs.position() >= report) { report += freq; REPORT: auto elapsed = double(time(nullptr) - time0); if (elapsed > 0) std::cerr << "prog: " << unsigned(ifs.position() * 100.0) << "%; " << in_count << " alignments processed (" << in_count / elapsed << " per sec); (" << gapless_count << " gapless) " << out_count << " contig pairs generated (" << out_count / elapsed << " per sec); ratio: " << double(in_count) / out_count << std::endl; else std::cerr << "prog: " << unsigned(ifs.position() * 100.0) << "%; " << in_count << " alignments processed; (" << gapless_count << " gapless) " << out_count << " contig pairs generated; ratio: " << double(in_count) / out_count << std::endl; if (isEOF) return 0; } } }
void Shell::displayLine(const LineBuffer& line){ _cursor.column(_column); auto matched = _commands.parse(line.line(), _out, false); _modules.lineUpdated(matched, line, *this); _cursor.column(line.pos() + _column); }
void PolylineAdapter::Stylize(Renderer* renderer, RS_FeatureReader* features, bool initialPass, FdoExpressionEngine* exec, LineBuffer* geometry, MdfModel::FeatureTypeStyle* style, const MdfModel::MdfString* tooltip, const MdfModel::MdfString* url, RS_ElevationSettings* elevSettings, CSysTransformer* /*layer2mapxformer*/) { m_exec = exec; // no need to do anything if the style is not a line style, so quit if (FeatureTypeStyleVisitor::DetermineFeatureTypeStyle(style) != FeatureTypeStyleVisitor::ftsLine) return; //------------------------------------------------------- // determine the rule for the feature //------------------------------------------------------- MdfModel::RuleCollection* lrc = style->GetRules(); MdfModel::LineRule* rule = NULL; for (int i=0; i<lrc->GetCount(); ++i) { rule = static_cast<MdfModel::LineRule*>(lrc->GetAt(i)); // apply any filter on the rule - if it fails move to the next rule if (!ExecFdoFilter(&rule->GetFilter())) { // don't stylize with failed rule rule = NULL; continue; } break; } if (!rule) return; MdfModel::LineSymbolizationCollection* lsymc = rule->GetSymbolizations(); if (lsymc == NULL) return; int nSyms = lsymc->GetCount(); //------------------------------------------------------- // evaluate all the styles once //------------------------------------------------------- // temporary array used to store pointers to each evaluated style RS_LineStroke** ppStrokes = (RS_LineStroke**)alloca(nSyms * sizeof(RS_LineStroke*)); if (!ppStrokes) return; size_t tempIndex = 0; for (int i=0; i<nSyms; ++i) { MdfModel::LineSymbolization2D* lsym = lsymc->GetAt(i); // don't render if there's no symbolization if (lsym == NULL) { ppStrokes[i] = NULL; continue; } // quick check if style is already cached RS_LineStroke* cachedStyle = m_hLineSymCache[lsym]; if (cachedStyle) { ppStrokes[i] = cachedStyle; } else { // if not, then we need to either cache or evaluate it // make sure the vector has a style in the slot we need if (tempIndex >= m_lineSyms.size()) { _ASSERT(tempIndex == m_lineSyms.size()); // allocate a new style and add it to the vector m_lineSyms.push_back(new RS_LineStroke()); } // use the existing style in the vector ppStrokes[i] = m_lineSyms[tempIndex]; ObtainStyle(lsym, *ppStrokes[i]); ++tempIndex; } } //------------------------------------------------------- // compute the clip offset from the styles //------------------------------------------------------- double clipOffsetWU = 0.0; // in mapping units bool bClip = renderer->RequiresClipping(); bool bLabelClip = renderer->RequiresLabelClipping(); if (bClip || bLabelClip) { double mapScale = renderer->GetMapScale(); double clipOffsetMeters = 0.0; // in device units for (int i=0; i<nSyms; ++i) { if (ppStrokes[i]) { double styleClipOffset = GetClipOffset(*ppStrokes[i], mapScale); clipOffsetMeters = rs_max(styleClipOffset, clipOffsetMeters); } } // add one pixel's worth to handle any roundoff clipOffsetMeters += METERS_PER_INCH / renderer->GetDpi(); // limit the offset to something reasonable if (clipOffsetMeters > MAX_CLIPOFFSET_IN_METERS) clipOffsetMeters = MAX_CLIPOFFSET_IN_METERS; // convert to mapping units clipOffsetWU = clipOffsetMeters * mapScale / renderer->GetMetersPerUnit(); } //------------------------------------------------------- // prepare the geometry on which to apply the style //------------------------------------------------------- LineBuffer* lb = geometry; std::auto_ptr<LineBuffer> spClipLB; if (bClip) { // the clip region is the map request extents expanded by the offset RS_Bounds clip = renderer->GetBounds(); clip.minx -= clipOffsetWU; clip.miny -= clipOffsetWU; clip.maxx += clipOffsetWU; clip.maxy += clipOffsetWU; // clip geometry to given extents LineBuffer* lbc = lb->Clip(clip, LineBuffer::ctAGF, m_lbPool); if (lbc != lb) { // if the clipped buffer is NULL (completely clipped) just move on to // the next feature if (!lbc) return; // otherwise continue processing with the clipped buffer lb = lbc; if (lb != geometry) spClipLB.reset(lb); } } //------------------------------------------------------- // do the StartFeature notification //------------------------------------------------------- RS_String tip; //TODO: this should be quick since we are not assigning RS_String eurl; const RS_String &theme = rule->GetLegendLabel(); if (tooltip && !tooltip->empty()) EvalString(*tooltip, tip); if (url && !url->empty()) EvalString(*url, eurl); // elevation settings RS_ElevationType elevType = RS_ElevationType_RelativeToGround; double zOffset = 0.0; double zExtrusion = 0.0; GetElevationParams(elevSettings, zOffset, zExtrusion, elevType); renderer->StartFeature(features, initialPass, tip.empty()? NULL : &tip, eurl.empty()? NULL : &eurl, theme.empty()? NULL : &theme, zOffset, zExtrusion, elevType); //------------------------------------------------------- // apply the style to the geometry using the renderer //------------------------------------------------------- for (int i=0; i<nSyms; ++i) { if (ppStrokes[i]) renderer->ProcessPolyline(lb, *ppStrokes[i]); } //------------------------------------------------------- // do labeling if needed //------------------------------------------------------- MdfModel::Label* label = rule->GetLabel(); if (label && label->GetSymbol()) { // Make sure the geometry is clipped if label clipping is specified. // If bClip is true then the geometry is already clipped. if (!bClip && bLabelClip) { // the clip region is the map request extents expanded by the offset RS_Bounds clip = renderer->GetBounds(); clip.minx -= clipOffsetWU; clip.miny -= clipOffsetWU; clip.maxx += clipOffsetWU; clip.maxy += clipOffsetWU; LineBuffer* lbc = lb->Clip(clip, LineBuffer::ctAGF, m_lbPool); if (lbc != lb) { // if the clipped buffer is NULL (completely clipped) just move on to // the next feature if (!lbc) return; // otherwise continue processing with the clipped buffer lb = lbc; if (lb != geometry) spClipLB.reset(lb); } } double cx = std::numeric_limits<double>::quiet_NaN(); double cy = std::numeric_limits<double>::quiet_NaN(); double slope_rad = 0.0; // multi should work for simple polylines too lb->Centroid(LineBuffer::ctLine, &cx, &cy, &slope_rad); if (!_isnan(cx) && !_isnan(cy)) AddLabel(cx, cy, slope_rad, true, label, RS_OverpostType_AllFit, true, renderer, label->GetSymbol()->IsAdvancedPlacement()? lb : NULL); } // free clipped line buffer if the geometry was clipped if (spClipLB.get()) LineBufferPool::FreeLineBuffer(m_lbPool, spClipLB.release()); }
void SE_PositioningAlgorithms::Default(SE_ApplyContext* applyCtx, SE_RenderStyle* rstyle) { // the style needs to contain at least one primitive SE_RenderPrimitiveList& prims = rstyle->symbol; if (prims.size() == 0) return; SE_Renderer* se_renderer = applyCtx->renderer; LineBuffer* geometry = applyCtx->geometry; SE_Matrix& xform = *applyCtx->xform; double cx = 0.0; double cy = 0.0; double offsetX = 0.0; double offsetY = 0.0; double angleRad = 0.0; switch (rstyle->type) { case SE_RenderStyle_Point: { SE_RenderPointStyle* rpStyle = (SE_RenderPointStyle*)rstyle; // get the feature centroid (no angle for point centroids) geometry->Centroid(LineBuffer::ctPoint, &cx, &cy, NULL); // account for the point usage angle control and offset angleRad = rpStyle->angleRad; offsetX = rpStyle->offset[0]; offsetY = rpStyle->offset[1]; break; } case SE_RenderStyle_Line: { SE_RenderLineStyle* rlStyle = (SE_RenderLineStyle*)rstyle; // get the feature centroid and angle double fAngleRad; geometry->Centroid(LineBuffer::ctLine, &cx, &cy, &fAngleRad); // account for the angle control angleRad = rlStyle->angleRad; if (rlStyle->angleControl == SE_AngleControl_FromGeometry) angleRad += fAngleRad; break; } case SE_RenderStyle_Area: { SE_RenderAreaStyle* raStyle = (SE_RenderAreaStyle*)rstyle; // get the feature centroid (no angle for area centroids) geometry->Centroid(LineBuffer::ctArea, &cx, &cy, NULL); // account for the angle control angleRad = raStyle->angleRad; break; } } // don't add a label if we can't compute the centroid if (_isnan(cx) || _isnan(cy)) return; // need to convert centroid to screen units se_renderer->WorldToScreenPoint(cx, cy, cx, cy); // also account for any viewport rotation angleRad += se_renderer->GetWorldToScreenRotation(); // see StylizationEngine::Stylize for a detailed explanation of these transforms bool yUp = se_renderer->YPointsUp(); SE_Matrix xformLabel; xformLabel.translate(offsetX, offsetY); xformLabel.rotate(yUp? angleRad : -angleRad); xformLabel.premultiply(xform); xformLabel.translate(cx, cy); se_renderer->AddLabel(geometry, rstyle, xformLabel, angleRad); }