Skip to content

Exception occurred while drawing and filling polygons #2964

Description

@wangningyu

osgEarth Version (required): 3.8.0

Description of the problem: Polygon filling anomaly

What you have tried: I have tried three methods to fill the semi transparent space

Under the 2D plan view (-180/90 in the lower left and right corners, 180/90 in the upper right corner), the following effect should be drawn:

Image

I have encountered an issue where the semi transparent color filling is abnormal when drawing polygons.

I have tried the following three methods:

  • 1.the default method
void OSGWidget::addLargeConcavePolygonBase(osgEarth::MapNode* mapNode)
{
    QPolygonF               qPoly;
    std::vector<osg::Vec3d> ctrlPoints;

    ctrlPoints.push_back(osg::Vec3d(90.0,  30.0, 0));
    ctrlPoints.push_back(osg::Vec3d(120.0,  13.0, 0));
    ctrlPoints.push_back(osg::Vec3d(140.0,  1.0, 0));
    ctrlPoints.push_back(osg::Vec3d(95.0,  -4.0, 0));
    ctrlPoints.push_back(osg::Vec3d(85.0,  -5.0, 0));
    ctrlPoints.push_back(osg::Vec3d(75.0,  -6.0, 0));
    ctrlPoints.push_back(osg::Vec3d(45.0,  -7.0, 0));
    ctrlPoints.push_back(osg::Vec3d(15.0,  -10.0, 0));
    ctrlPoints.push_back(osg::Vec3d(0.0,  -8.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-8.0,  -20.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-15.0,  -45.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-90.0,  -70.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-135.0,  -45.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-160.0,  -0.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-90.0,  28.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-5.0,  6.0, 0));

    for (size_t i = 0; i < ctrlPoints.size() - 1; ++i)
        qPoly.push_back(QPointF(ctrlPoints.at(i).x(), ctrlPoints.at(i).y()));

    static osg::observer_ptr<osg::Group> m_polygonGroup;
    if (m_polygonGroup.valid()) m_root->removeChild(m_polygonGroup.get());

    osg::ref_ptr<osg::Group> newGroup = new osg::Group();
    m_root->addChild(newGroup.get());
    m_polygonGroup = newGroup.get();

    const osgEarth::SpatialReference    *srs = mapNode->getMap()->getSRS();
    osgEarth::Style                     style;

    style.getOrCreate<osgEarth::PolygonSymbol>()->fill()->color() = osgEarth::Color(osg::Vec4(1.0, 0.65, 0.0, 0.4));
    //style.getOrCreate<osgEarth::LineSymbol>()->stroke()->color() = osgEarth::Color(osg::Vec4(1.0, 0.65, 0.0, 0.4));
    //style.getOrCreate<osgEarth::LineSymbol>()->stroke()->width() = osgEarth::Distance(0.001, osgEarth::Units::PIXELS);
    //style.getOrCreate<osgEarth::LineSymbol>()->tessellationSize() = osgEarth::Distance(1000, osgEarth::Units::METERS);

    osgEarth::AltitudeSymbol* as = style.getOrCreate<osgEarth::AltitudeSymbol>();
    as->clamping() = osgEarth::AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN;
    as->technique() = osgEarth::AltitudeSymbol::TECHNIQUE_DRAPE;
    as->verticalOffset() = osgEarth::Distance(0.5, osgEarth::Units::METERS);

    osg::ref_ptr<osgEarth::Polygon> poly = new osgEarth::Polygon();
    for (const QPointF& pt : qPoly)
    {
        poly->push_back(osg::Vec3d(pt.x(), pt.y(), 0.0));
    }

    if (poly->front() != poly->back())
        poly->push_back(poly->front());

    poly->rewind(osgEarth::Geometry::ORIENTATION_CCW);

    osg::ref_ptr<osgEarth::FeatureNode> fn = new osgEarth::FeatureNode(new osgEarth::Feature(poly.get(), srs, style));
    fn->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin");
    newGroup->addChild(fn.get());
}
Image

this type can't show any polygon and fill color

  • 2. use TessellateOperator::tessellateGeo
// Using TessellateOperator to segment and draw functions
void OSGWidget::addLargeConcavePolygonTess(osgEarth::MapNode* mapNode)
{
    std::vector<osg::Vec3d> ctrlPoints;

    ctrlPoints.push_back(osg::Vec3d(90.0,  30.0, 0));
    ctrlPoints.push_back(osg::Vec3d(120.0,  13.0, 0));
    ctrlPoints.push_back(osg::Vec3d(140.0,  1.0, 0));
    ctrlPoints.push_back(osg::Vec3d(95.0,  -4.0, 0));
    ctrlPoints.push_back(osg::Vec3d(85.0,  -5.0, 0));
    ctrlPoints.push_back(osg::Vec3d(75.0,  -6.0, 0));
    ctrlPoints.push_back(osg::Vec3d(45.0,  -7.0, 0));
    ctrlPoints.push_back(osg::Vec3d(15.0,  -10.0, 0));
    ctrlPoints.push_back(osg::Vec3d(0.0,  -8.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-8.0,  -20.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-15.0,  -45.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-90.0,  -70.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-135.0,  -45.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-160.0,  -0.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-90.0,  28.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-5.0,  6.0, 0));

    osg::ref_ptr<osgEarth::Polygon> finalPoly = new osgEarth::Polygon();
    int numPoints = ctrlPoints.size();

    for (int i = 0; i < numPoints; ++i)
    {
        std::vector<osg::Vec3d> segmentPoints;

        // Calculate the index of the next point, and if it reaches the end, take the remainder to return to 0
        int nextIdx = (i + 1) % numPoints;

        // Split the long side into multiple segments
        osgEarth::Util::TessellateOperator::tessellateGeo(
            ctrlPoints[i],
            ctrlPoints[nextIdx],
            100,
            osgEarth::GEOINTERP_GREAT_CIRCLE, // Interpolation of large circular flight path
            segmentPoints
            );

        // Discard the last point of each paragraph
        // This not only avoids repeating the beginning and end, but also perfectly closes the entire polygon
        for (size_t j = 0; j < segmentPoints.size() - 1; ++j) {
            finalPoly->push_back(segmentPoints[j]);
        }
    }

    osg::ref_ptr<osgEarth::Feature> feature = new osgEarth::Feature(finalPoly.get(), osgEarth::SpatialReference::get("wgs84"));
    osgEarth::Style style;

    osgEarth::PolygonSymbol* fill = style.getOrCreate<osgEarth::PolygonSymbol>();
    fill->fill()->color() = osgEarth::Color(osgEarth::Color::Red, 0.5);

    osgEarth::LineSymbol* ls = style.getOrCreate<osgEarth::LineSymbol>();
    ls->stroke()->color() = osgEarth::Color::Green;
    ls->stroke()->width() = osgEarth::Distance(1.0, osgEarth::Units::PIXELS);

    osgEarth::AltitudeSymbol* alt = style.getOrCreate<osgEarth::AltitudeSymbol>();
    alt->clamping() = osgEarth::AltitudeSymbol::CLAMP_TO_TERRAIN;
    alt->technique() = osgEarth::AltitudeSymbol::TECHNIQUE_DRAPE;//TECHNIQUE_GPU;
    feature->setStyle(style);

    osg::ref_ptr<osgEarth::FeatureNode> node = new osgEarth::FeatureNode(feature.get());
    node->setMapNode(mapNode);

    mapNode->addChild(node.get());
}
Image

TessellateOperator's type can show the green bordline, but fill failed.

  • 3. split the East and West Hemispheres
// Forcefully insert a necessary point passing through the Y-axis in a polygon
QPolygonF insertYAxisIntersections(const QPolygonF& poly)
{
    QPolygonF newPoly;
    int n = poly.size();
    if (n < 2) return poly;

    for (int i = 0; i < n; ++i)
    {
        const QPointF& p1 = poly[i];
        const QPointF& p2 = poly[(i+1) % n]; // Next points, wrap around the polygon

        newPoly.push_back(p1); // First add the current point

        // Determine whether two points span both sides (x < 0 and x > 0)
        if ((p1.x() < 0 && p2.x() > 0) || (p1.x() > 0 && p2.x() < 0))
        {
            double t = (0.0 - p1.x()) / (p2.x() - p1.x()); // linear interpolation
            double yIntersect = p1.y() + t * (p2.y() - p1.y());
            QPointF interPoint(0.0, yIntersect);

            newPoly.push_back(interPoint); // Insert Intersection Point
        }
    }

    return newPoly;
}

void OSGWidget::addLargeConcavePolygonEastWest(osgEarth::MapNode* mapNode)
{
    QPolygonF               qPoly;
    std::vector<osg::Vec3d> ctrlPoints;

    ctrlPoints.push_back(osg::Vec3d(90.0,  30.0, 0));
    ctrlPoints.push_back(osg::Vec3d(120.0,  13.0, 0));
    ctrlPoints.push_back(osg::Vec3d(140.0,  1.0, 0));
    ctrlPoints.push_back(osg::Vec3d(95.0,  -4.0, 0));
    ctrlPoints.push_back(osg::Vec3d(85.0,  -5.0, 0));
    ctrlPoints.push_back(osg::Vec3d(75.0,  -6.0, 0));
    ctrlPoints.push_back(osg::Vec3d(45.0,  -7.0, 0));
    ctrlPoints.push_back(osg::Vec3d(15.0,  -10.0, 0));
    ctrlPoints.push_back(osg::Vec3d(0.0,  -8.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-8.0,  -20.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-15.0,  -45.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-90.0,  -70.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-135.0,  -45.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-160.0,  -0.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-90.0,  28.0, 0));
    ctrlPoints.push_back(osg::Vec3d(-5.0,  6.0, 0));

    for (size_t i = 0; i < ctrlPoints.size() - 1; ++i)
        qPoly.push_back(QPointF(ctrlPoints.at(i).x(), ctrlPoints.at(i).y()));

    // If two points of the original shape pass through the Y-axis, insert a point that passes through the Y-axis
    QPolygonF                           modifiedPoly = insertYAxisIntersections(qPoly);
    osg::ref_ptr<osg::Group>            newGroup = new osg::Group();
    mapNode->addChild(newGroup.get());

    const osgEarth::SpatialReference* srs = mapNode->getMap()->getSRS();

    osgEarth::Style style;
    style.getOrCreate<osgEarth::PolygonSymbol>()->fill()->color() = osgEarth::Color(osg::Vec4(1.0, 0.65, 0.0, 0.4));

    style.getOrCreate<osgEarth::LineSymbol>()->tessellationSize() = osgEarth::Distance(500, osgEarth::Units::METERS);
    style.getOrCreate<osgEarth::LineSymbol>()->stroke()->color() = osgEarth::Color(osg::Vec4(1.0, 0.65, 0.0, 0.4));
    style.getOrCreate<osgEarth::LineSymbol>()->stroke()->width() = osgEarth::Distance(0.01, osgEarth::Units::METERS);

    osgEarth::AltitudeSymbol* as = style.getOrCreate<osgEarth::AltitudeSymbol>();
    as->clamping() = osgEarth::AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN;
    as->technique() = osgEarth::AltitudeSymbol::TECHNIQUE_DRAPE;
    as->verticalOffset() = osgEarth::Distance(0.5, osgEarth::Units::METERS);

    // Draw separately from the east and west hemispheres
    osg::ref_ptr<osgEarth::Polygon> westPoly = new osgEarth::Polygon();
    osg::ref_ptr<osgEarth::Polygon> eastPoly = new osgEarth::Polygon();

    for (const QPointF& pt : modifiedPoly) {
        double lon = pt.x();
        if (lon <= 0) westPoly->push_back(osg::Vec3d(lon, pt.y(), 0));
        if (lon >= 0) eastPoly->push_back(osg::Vec3d(lon, pt.y(), 0));
    }

    // Process polygons of two hemispheres separately
    auto processSubPoly = [&](osg::ref_ptr<osgEarth::Polygon> sub) {
        if (sub->size() < 3) return;
        sub->rewind(osgEarth::Geometry::ORIENTATION_CCW);
        osg::ref_ptr<osgEarth::FeatureNode> fn = new osgEarth::FeatureNode(new osgEarth::Feature(sub.get(), srs, style));
        fn->getOrCreateStateSet()->setRenderBinDetails(10, "RenderBin");
        newGroup->addChild(fn.get());
    };

    if(westPoly->size()) processSubPoly(westPoly);
    if(eastPoly->size()) processSubPoly(eastPoly);
}
Image Image

If the border lines of the segmented polygon are colored, there will be a vertical line in the middle.

At present, I am not sure if this is due to an error in my usage method or a rendering error myself?

Best Regards!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions