Exemplo n.º 1
0
void MgdFeatureInfoRenderer::ProcessMarker(LineBuffer*   lb,
                                        RS_MarkerDef& mdef,
                                        bool          allowOverpost,
                                        RS_Bounds*    bounds)
{
    if(m_pointTest && m_featurePending)
    {
        double scale_factor;
        if (mdef.units() == RS_Units_Device)
            scale_factor = m_mapScale / m_metersPerUnit;
        else
            scale_factor = 1.0 / m_metersPerUnit;

        double cx = mdef.width() * scale_factor;
        double cy = mdef.height() * scale_factor;
        double ix = mdef.insx() * cx;
        double iy = mdef.insy() * cy;
        double angleRad = mdef.rotation() * M_PI180;
        double angleCos = cos(angleRad);
        double angleSin = sin(angleRad);

        for (int i = 0; i < lb->point_count(); i++)
        {
            double ox = lb->x_coord(i), oy = lb->y_coord(i);
            double x0 = ox - ix, x1 = x0 + cx;
            double y0 = oy - iy, y1 = y0 + cy;
            double sx = m_point[0] - ox, sy = m_point[1] - oy;
            double rx = sx * angleCos + sy * angleSin;
            double ry = sy * angleCos - sx * angleSin;
            double dx = rx + ox, dy = ry + oy;

            if(dx > x0 && dx < x1 && dy > y0 && dy < y1)
            {
                SetSelected();
                break;
            }
        }
    }
}
Exemplo n.º 2
0
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());
}
Exemplo n.º 3
0
bool GeometryAdapter::ConvertSymbol(MdfModel::Symbol* symbol, RS_MarkerDef& mdef)
{
    SymbolVisitor::eSymbolType type = SymbolVisitor::DetermineSymbolType(symbol);

    mdef.units() = (symbol->GetSizeContext() == MdfModel::MappingUnits)? RS_Units_Model : RS_Units_Device;

    double val;
    bool cacheable = true;

    // width
    cacheable = EvalDouble(symbol->GetSizeX(), val) && cacheable;
    mdef.width() = MdfModel::LengthConverter::UnitToMeters(symbol->GetUnit(), val);
    if (mdef.width() < 0.0)
    {
        // should not get negative width and height
        _ASSERT(false);
        mdef.width() = -mdef.width();
    }

    // height
    cacheable = EvalDouble(symbol->GetSizeY(), val) && cacheable;
    mdef.height() = MdfModel::LengthConverter::UnitToMeters(symbol->GetUnit(), val);
    if (mdef.height() < 0.0)
    {
        // should not get negative width and height
        _ASSERT(false);
        mdef.height() = -mdef.height();
    }

    // rotation + insertion point
    cacheable = EvalDouble(symbol->GetRotation(), mdef.rotation()) && cacheable;
    cacheable = EvalDouble(symbol->GetInsertionPointX(), mdef.insx()) && cacheable;
    cacheable = EvalDouble(symbol->GetInsertionPointY(), mdef.insy()) && cacheable;
    mdef.rotation() = fmod(mdef.rotation(), 360.0);

    if (type == SymbolVisitor::stMark)
    {
        MdfModel::MarkSymbol* marksym = (MdfModel::MarkSymbol*)symbol;

        mdef.type() = RS_MarkerType_Marker;

        // shape
        MdfModel::MarkSymbol::Shape shape = marksym->GetShape();
        switch (shape)
        {
            case MdfModel::MarkSymbol::Square:   mdef.markernum() = SLDType_Square;   break;
            case MdfModel::MarkSymbol::Circle:   mdef.markernum() = SLDType_Circle;   break;
            case MdfModel::MarkSymbol::Triangle: mdef.markernum() = SLDType_Triangle; break;
            case MdfModel::MarkSymbol::Star:     mdef.markernum() = SLDType_Star;     break;
            case MdfModel::MarkSymbol::Cross:    mdef.markernum() = SLDType_Cross;    break;
            case MdfModel::MarkSymbol::X:        mdef.markernum() = SLDType_X;        break;
            default: break;
        }

        // fill and edge colors
        cacheable = ConvertFill(marksym->GetFill(), mdef.style()) && cacheable;
        cacheable = ConvertStroke(marksym->GetEdge(), mdef.style().outline()) && cacheable;
    }
    else if (type == SymbolVisitor::stBlock)
    {
        MdfModel::BlockSymbol* blocksym = (MdfModel::BlockSymbol*)symbol;

        mdef.type()    = RS_MarkerType_Block;
        mdef.library() = blocksym->GetDrawingName();
        mdef.name()    = blocksym->GetBlockName();

        // block and layer override colors
        cacheable = EvalColor(blocksym->GetBlockColor(), mdef.style().color()) && cacheable;
        cacheable = EvalColor(blocksym->GetLayerColor(), mdef.style().outline().color()) && cacheable;
    }
    else if (type == SymbolVisitor::stW2D)
    {
        MdfModel::W2DSymbol* w2dsym = (MdfModel::W2DSymbol*)symbol;

        mdef.type()    = RS_MarkerType_W2D;
        mdef.library() = w2dsym->GetSymbolLibrary();
        mdef.name()    = w2dsym->GetSymbolName();

        // fill, line, and text override colors
        cacheable = EvalColor(w2dsym->GetFillColor(), mdef.style().color()) && cacheable;
        cacheable = EvalColor(w2dsym->GetLineColor(), mdef.style().outline().color()) && cacheable;
        cacheable = EvalColor(w2dsym->GetTextColor(), mdef.style().background()) && cacheable;
    }
    else if (type == SymbolVisitor::stFont)
    {
        MdfModel::FontSymbol* fontSym = (MdfModel::FontSymbol*)symbol;

        mdef.type() = RS_MarkerType_Font;

        // store the font name as the library string
        mdef.library() = fontSym->GetFontName();

        // store the marker character as the symbol name
        mdef.name() = (wchar_t)fontSym->GetCharacter();

        // font style
        RS_FontStyle_Mask style = RS_FontStyle_Regular;

        bool setting = false;
        cacheable = EvalBoolean(fontSym->GetBold(), setting) && cacheable;
        if (setting)
            style = (RS_FontStyle_Mask)(style | RS_FontStyle_Bold);

        cacheable = EvalBoolean(fontSym->GetItalic(), setting) && cacheable;
        if (setting)
            style = (RS_FontStyle_Mask)(style | RS_FontStyle_Italic);

        cacheable = EvalBoolean(fontSym->GetUnderlined(), setting) && cacheable;
        if (setting)
            style = (RS_FontStyle_Mask)(style | RS_FontStyle_Underline);

        mdef.fontstyle() = style;

        // foreground color
        cacheable = EvalColor(fontSym->GetForegroundColor(), mdef.style().color()) && cacheable;
    }
    else if (type == SymbolVisitor::stImage)
    {
        // TODO: not currently supported
        _ASSERT(false);
    }

    return cacheable;
}