2

I am working on a project that need to move and update the shape of the feature of the layer.

I am working in c++/ QT4.8.5 and qgis api c++ 2.8.2. In my Layer I have a lot of features, each feature has a specific svg file corresponding to the value of the attribute of the feature like the color, the length and the angle

In my program, at the begining all the feature has an initial position, with the same caracteristic color=black, length=small, angle=0 When I start my simulator that generate random data and save them into the first feature, all of my feature rotate of the value of the angle of the first feature

I have 3 functions the first add a point to the layer the second update the data of the layer and the last update the feature with color, size and rotation

here is an extract of my code ( too long to post it full ) the 3 function

    void MainWindow::addTracks() {
        QgsVectorLayer * lLayer = mMapLayer.value(TRACKS);
        QgsVectorDataProvider * lDataProvider = lLayer->dataProvider();
        double lposX =(qrand()%(Xmax-Xmin)+Xmin);
        double lposY =(qrand()%(Ymin-Ymax)+Ymax);
        // init cap aleatoire
        double lCapqrand()%(360);
        // init vitesse aleatoire
        double lVitesse= qrand()%(30);
        // init classification
        int lClassif= qrand()%(5);
        QColor lColor;
        switch(lClassif) {
        case 1:
            lColor=QColor("green");
        break;
        case 2:
            lColor=QColor("blue");
        break;
        case 3:
            lColor=QColor("orange");
        break;
        case 4:
            lColor=QColor("red");
        default:
            lColor=QColor("black");
        }
        if (lVitesse < 10)
            lClassif=lClassif+10;
        else if (lVitesse <20)
            lClassif = lClassif + 20;
        else
            lClassif = lClassif + 30;
        //create point
        QgsGeometry * myPoint;
        myPoint = QgsGeometry::fromPoint(QgsPoint(lposX,lposY));
        QgsFeature myFeature;
        myFeature.setGeometry(myPoint);
        // set the value
        myFeature.initAttributes(8);
        myFeature.setAttribute(Name,"track");
        myFeature.setAttribute(TrackId , mId) ;
        myFeature.setAttribute(Classification , lClassif);
        myFeature.setAttribute(Longitude,lposY );
        myFeature.setAttribute(Latitude,lposX);
        myFeature.setAttribute(Couleur,lColor);
        myFeature.setAttribute(Cap,lCap);
        myFeature.setAttribute(Vitesse,lVitesse);
        QDateTime MyTime;
        myFeature.setAttribute(Heure , MyTime.currentDateTime().toString("dd.MM.yyyy hh:mm:ss.zzz"));
        myFeature.setValid(true);

        QgsFeatureList myFeatureList;
        myFeatureList.append(myFeature);
        lDataProvider->addFeatures(myFeatureList);

        lLayer->updateExtents();
        // Increment de l'Id
        mId=mId+1;

        // Add the Vector Layer to the Layer Registry
        QgsMapLayerRegistry::instance()->addMapLayer(lLayer, TRUE);
        // Add the Layer to the Layer Set
        QgsMapCanvasLayer PointMapCanvasLayer = QgsMapCanvasLayer(lLayer, TRUE);
        mpS57->myListForPrint.insert(1,PointMapCanvasLayer);
        // set the canvas to the extent of our layer
        mpMapCanvas->setExtent(lLayer->extent());
        // Set the Map Canvas Layer Set
        mpMapCanvas->setLayerSet(mpS57->myListForPrint);
        mpS57->UpdateTrack(lLayer);
        // zoom full canvas
        mpMapCanvas->zoomToFullExtent();
        mpMapCanvas->refresh();
        mpMapCanvas->updateMap();
        mpMapCanvas->updateFullExtent();
    }

    void MainWindow::moveTracks(int pTrackId) {
        QgsVectorLayer * lLayer = mMapLayer.value(TRACKS);
        lLayer->startEditing();

        QgsVectorDataProvider * lDataProvider;
        lDataProvider = lLayer->dataProvider();

        //calc new random X and Y
        double posX =(qrand()%(Xmax-Xmin)+Xmin);
        double posY =(qrand()%(Ymin-Ymax)+Ymax);
        // init vitesse aleatoire
       double lVitesse = qrand()%(30);
    // couleur
    QString lColor="black";
    // init classification
    int lClassif= qrand()%(5);
    // init cap aleatoire
    double lCap= qrand()%(360);
    //create point
    QgsGeometry *myPoint;
    myPoint=QgsGeometry::fromPoint(QgsPoint(posX,posY));
    myPoint->rotate(lCap,QgsPoint(posX,posY));
    QgsGeometryMap MyGeometryMap;

    //get the feature of the specify Id
    QgsFeatureIterator myFeatIter;
    myFeatIter = lDataProvider->getFeatures();
    QgsFeature myFeature;
    QgsFeatureId myFeatureId;

    // search the feature for the id
    while ( myFeatIter.nextFeature(myFeature)) {
        qDebug()<< " Feature Id Found =" << myFeature.id();
        if (pTrackId == myFeature.attribute(0)) {
            myFeatureId=myFeature.id();
            myFeature.setGeometry(*myPoint);
            myFeature.setAttribute(Longitude,posY );    // longitude
            myFeature.setAttribute(Latitude,posX);      // latitude
            myFeature.setAttribute(Vitesse,lVitesse);   // vitesse
            myFeature.setAttribute(Classification,lClassif);    // classif ou type
            myFeature.setAttribute(Cap,lCap);           // cap
            myFeature.setAttribute(Couleur,lColor);     // couleur
            myFeature.setValid(true);
        }
    }
    // update the attribute
    QgsAttributeMap MyAttributeMap;
    MyAttributeMap.insert(0,myFeatureId);
    MyAttributeMap.insert(1,myFeature.attribute("LABEL"));
    MyAttributeMap.insert(2,myFeature.attribute("TYPE"));
    MyAttributeMap.insert(3,myFeature.attribute("COLOR"));
    MyAttributeMap.insert(4,myFeature.attribute("posX"));
    MyAttributeMap.insert(5,myFeature.attribute("posY"));
    MyAttributeMap.insert(6,myFeature.attribute("CAP"));
    MyAttributeMap.insert(7,myFeature.attribute("VITESSE"));
    MyAttributeMap.insert(8,myFeature.attribute("TIMESTAMP"));

    QgsChangedAttributesMap MyChangedAttributesMap;
    MyChangedAttributesMap.insert(myFeatureId,MyAttributeMap);
    MyGeometryMap.insert(myFeatureId,*myPoint);

    bool lResult;
    lResult=lDataProvider->changeGeometryValues(MyGeometryMap);
    lResult=lDataProvider->changeAttributeValues(MyChangedAttributesMap);
    // save all change
    lLayer->commitChanges();
    mpS57->createTrackIco(myFeature,myFeatureId,true);
    // update the track
    mpS57->UpdateTrack2(lLayer,myFeature);
}


void CMyQgsS57::UpdateTrack2(QgsVectorLayer* pLayer,QgsFeature pFeature)
{
    QgsFeatureRendererV2 * lRenderer = pLayer->rendererV2();
    QgsSymbolV2 * lNewSymbol = lRenderer->symbolForFeature(pFeature);
    QgsStringMap MyTrackDefault;
    QString MyFeatureId;
    MyFeatureId = QString::number(pFeature.attribute(0).toInt());
    QString lTrackIcoDefault = "../data/Icones/iconeS52/track_"+MyFeatureId+ EXT_ICONE;
    // list of property for the boystyle
    QStringList MyTrackPropertyName;
    MyTrackPropertyName << "fill" << "name" << "outline" << "outline-width" << "size" << "angle";
    // list of corresponding value 1
    QStringList MyTrackPropertyValue;
    MyTrackPropertyValue << "#ff0000" << lTrackIcoDefault << "#000000" << "6.8" << "6" << QString::number((pFeature.attribute("CAP").toDouble()-90));

    // create the map 1 et 2
    for (int i =0; i < MyTrackPropertyName.size(); i++){
        MyTrackDefault.insert(MyTrackPropertyName.at(i),MyTrackPropertyValue.at(i));
    }
    // creation du svg marker layer
    QgsSymbolLayerV2* MySymbolLayer;
    MySymbolLayer = QgsSvgMarkerSymbolLayerV2::create(MyTrackDefault);
    lNewSymbol->deleteSymbolLayer(0);
    lNewSymbol->appendSymbolLayer(MySymbolLayer);
    //pLayer->setRendererV2(lRenderer);
    pLayer->setRendererV2( (QgsFeatureRendererV2*) lRenderer );
}

I don't understand why all of the feature of the layer rotate your suggestion or correction are welcome

complementary information I have just made some chnage in the code , but the result is the same here is the code the call of the function updatetrack is in comment tag I replace it by the change of the symbol

mpS57->createTrackIco(MyFeature,MyFeatureId,true);
// update the track

QgsStringMap MyTrackDefault;

QString lTrackIcoDefault = "../data/Icones/iconeS52/track_"+QString::number(MyFeatureId)+ EXT_ICONE;//attention au path icone "../data/Icones/iconeS52/" au lieu de PATH_ICONE
qDebug() << " icone path + name =" << lTrackIcoDefault ;
// list of property for the boystyle
QStringList MyTrackPropertyName;
MyTrackPropertyName << "fill" << "name" << "outline" << "outline-width" << "size" << "angle";
// list of corresponding value 1
QStringList MyTrackPropertyValue;
MyTrackPropertyValue << "#ff0000" << lTrackIcoDefault << "#000000" << "6.8" << "6" << QString::number((MyFeature.attribute("CAP").toDouble()-90));

// create the map 1 et 2
for (int i =0; i < MyTrackPropertyName.size(); i++){
    //1ere bouee
    MyTrackDefault.insert(MyTrackPropertyName.at(i),MyTrackPropertyValue.at(i));
}
QgsSymbolV2 * lNewSymbol = lLayer->rendererV2()->symbolForFeature(MyFeature);
// creation du svg marker layer
QgsSymbolLayerV2* MySymbolLayer;
MySymbolLayer = QgsSvgMarkerSymbolLayerV2::create(MyTrackDefault);
lNewSymbol->changeSymbolLayer(0,MySymbolLayer);

//mpS57->UpdateTrack2(lLayer,MyFeature);

is there something wrong, perhaps is the change of the symbol, it seems that all feature of the layer have the same symbol any idea ?

  • I rewrote my answer, hope it is more clear now. Look also in the chat. – Redoute Sep 3 '15 at 6:44
4

In QGIS styling is layer based, so it is generally not possible to set different styles or different symbols for individual features. I think this is because features are handled by the data source, while styling is organized by QGIS's layer.

Nevertheless you can get individual styling based on the feature attributes. This is called a "Data defined override". For example, you can set the SVG angle to an SQL expression like '"CAP" - 90'. Do this once at the time you style the layer. It is valid for all features of the layer, you won't have to change it when a feature's attribute changes.

If you need to create/style the layer programmatically, the function to set data defined overrides is QgsSymbolLayerV2::setDataDefinedProperty(). Beginning with QGIS 2.9 there are more specific funktions like QgsMarkerSymbolV2::setDataDefinedAngle().

  • ok i understand, but how can i change the attribute of one feature instead of the full layer ? – ainardi Sep 2 '15 at 12:15
  • I think moveTracks() already sets the attributes you need. @ainardi – Redoute Sep 2 '15 at 12:24
  • but what about the rotation oft he svg file, it is not coded in movetrack ! do you think that if I move the change of the symbol in movetrack it will work ? – ainardi Sep 2 '15 at 12:31
  • For the layer's SVG symbol angel you set the data defined override: "CAP" - 90 Then, after moveTracks() sets the value of attribute CAP, then the next canvas redraw will show the rotated symbols. At least I hope so. @ainardi – Redoute Sep 2 '15 at 12:39
  • in fact i do a CAP - 90 because the arrow contains in the svg file is oriented to 90 so if I want to display it to the default angle of 0 i had to rotate it of -90 degree, and in that case the icone is in the right direction before starting the simulation, with this artefact the arrow show exactly the CAP if the 90 by exemple the arrow show the east, if CAP is 180 the arrow show the south etc ..... – ainardi Sep 2 '15 at 12:46
1

I found a solution for my problem. instead of created a layer with a lot of feature, i create a lot of layer with only one feature the algorythm is :

  • create a layer with a indexed name like TRACKS01

  • add the point with default setting

  • change the attribute value

  • update the layer

I make a test with 10 layers, when i start my simulator, all layer move, change the color, change the icon differently and independently.

I am afraid that the function in the 2.9 setdatadefinedangle don't solve my problem, it said that : set data defined angle for whole symbol (including all symbols layerst)

I have no time to upgrade to the 2.9 may be later

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.