Beispiel #1
0
void Layer::joinConnectedFeatures()
{
    // go through all label texts
    QString labelText;
    while ( !connectedTexts->isEmpty() )
    {
        labelText = connectedTexts->takeFirst();

        //std::cerr << "JOIN: " << labelText << std::endl;
        QHash< QString, QLinkedList<FeaturePart*>* >::const_iterator partsPtr = connectedHashtable->find( labelText );
        if ( partsPtr == connectedHashtable->constEnd() )
            continue; // shouldn't happen
        QLinkedList<FeaturePart*>* parts = *partsPtr;

        // go one-by-one part, try to merge
        while ( !parts->isEmpty() )
        {
            // part we'll be checking against other in this round
            FeaturePart* partCheck = parts->takeFirst();

            FeaturePart* otherPart = _findConnectedPart( partCheck, parts );
            if ( otherPart )
            {
                //std::cerr << "- connected " << partCheck << " with " << otherPart << std::endl;

                // remove partCheck from r-tree
                double bmin[2], bmax[2];
                partCheck->getBoundingBox( bmin, bmax );
                rtree->Remove( bmin, bmax, partCheck );
                featureParts->removeOne( partCheck );

                otherPart->getBoundingBox( bmin, bmax );

                // merge points from partCheck to p->item
                if ( otherPart->mergeWithFeaturePart( partCheck ) )
                {
                    // reinsert p->item to r-tree (probably not needed)
                    rtree->Remove( bmin, bmax, otherPart );
                    otherPart->getBoundingBox( bmin, bmax );
                    rtree->Insert( bmin, bmax, otherPart );
                }
            }
        }

        // we're done processing feature parts with this particular label text
        delete parts;
    }

    // we're done processing connected fetures
    delete connectedHashtable;
    connectedHashtable = NULL;
    delete connectedTexts;
    connectedTexts = NULL;
}
Beispiel #2
0
//static
CoverArt CoverArtUtils::selectCoverArtForTrack(
        Track* pTrack,
        const QLinkedList<QFileInfo>& covers) {
    if (pTrack == NULL || covers.isEmpty()) {
        CoverArt art;
        art.info.source = CoverInfo::GUESSED;
        return art;
    }

    const QString trackBaseName = pTrack->getFileInfo().baseName();
    const QString albumName = pTrack->getAlbum();
    return selectCoverArtForTrack(trackBaseName, albumName, covers);
}
Beispiel #3
0
QLinkedList<const GEOSGeometry *>* pal::Util::unmulti( const GEOSGeometry *the_geom )
{
  QLinkedList<const GEOSGeometry*> *queue = new QLinkedList<const GEOSGeometry*>;
  QLinkedList<const GEOSGeometry*> *final_queue = new QLinkedList<const GEOSGeometry*>;

  const GEOSGeometry *geom;

  queue->append( the_geom );
  int nGeom;
  int i;

  GEOSContextHandle_t geosctxt = geosContext();

  while ( !queue->isEmpty() )
  {
    geom = queue->takeFirst();
    int type = GEOSGeomTypeId_r( geosctxt, geom );
    switch ( type )
    {
      case GEOS_MULTIPOINT:
      case GEOS_MULTILINESTRING:
      case GEOS_MULTIPOLYGON:
        nGeom = GEOSGetNumGeometries_r( geosctxt, geom );
        for ( i = 0; i < nGeom; i++ )
        {
          queue->append( GEOSGetGeometryN_r( geosctxt, geom, i ) );
        }
        break;
      case GEOS_POINT:
      case GEOS_LINESTRING:
      case GEOS_POLYGON:
        final_queue->append( geom );
        break;
      default:
        QgsDebugMsg( QString( "unexpected geometry type:%1" ).arg( type ) );
        delete final_queue;
        delete queue;
        return nullptr;
    }
  }
  delete queue;

  return final_queue;
}
Beispiel #4
0
void AssignLayers::run(Graph &graph)
{
    emit setStatusMsg("Assigning layers...");

    // copy the nodes to a linked list
    QLinkedList<AbstractNode*> vertices;
    for(AbstractNode* v : graph.getNodes()) {
        vertices.append(v);
    }

    QSet<AbstractNode*> U;
    QSet<AbstractNode*> Z;
    QList<QList<AbstractNode*>> layers;

    //add the first layer
    int currentLayer = 0;
    layers.append(QList<AbstractNode*>());
    while(!vertices.isEmpty()) {
        AbstractNode* selected = nullptr;
        for(AbstractNode* v : vertices) {
            if(Z.contains(v->getPredecessors().toSet())) {
                selected = v;
                break;
            }
        }

        if(selected != nullptr) {
            selected->setLayer(currentLayer);
            layers.last().append(selected);
            U.insert(selected);
            vertices.removeOne(selected);
        } else {
            currentLayer++;
            layers.append(QList<AbstractNode*>());
            Z.unite(U);
        }
    }

    graph.setLayers(layers);
    graph.repaintLayers();
    emit setStatusMsg("Assigning layers... Done!");
}
Beispiel #5
0
void PluckerGenerator::generatePixmap( Okular::PixmapRequest * request )
{
    const QSizeF size = mPages[ request->pageNumber() ]->size();

    QPixmap *pixmap = new QPixmap( request->width(), request->height() );
    pixmap->fill( Qt::white );

    QPainter p;
    p.begin( pixmap );

    qreal width = request->width();
    qreal height = request->height();

    p.scale( width / (qreal)size.width(), height / (qreal)size.height() );
    mPages[ request->pageNumber() ]->drawContents( &p );
    p.end();

    request->page()->setPixmap( request->id(), pixmap );


    if ( !mLinkAdded.contains( request->pageNumber() ) ) {
        QLinkedList<Okular::ObjectRect*> objects;
        for ( int i = 0; i < mLinks.count(); ++i ) {
            if ( mLinks[ i ].page == request->pageNumber() ) {
                QTextDocument *document = mPages[ request->pageNumber() ];

                QRectF rect;
                calculateBoundingRect( document, mLinks[ i ].start,
                                       mLinks[ i ].end, rect );

                objects.append( new Okular::ObjectRect( rect.left(), rect.top(), rect.right(), rect.bottom(), false, Okular::ObjectRect::Action, mLinks[ i ].link ) );
            }
        }

        if ( !objects.isEmpty() )
            request->page()->setObjectRects( objects );

        mLinkAdded.insert( request->pageNumber() );
    }

    signalPixmapRequestDone( request );
}
Beispiel #6
0
  QLinkedList<const GEOSGeometry *> *unmulti( const GEOSGeometry *the_geom )
  {
    QLinkedList<const GEOSGeometry*> *queue = new QLinkedList<const GEOSGeometry*>;
    QLinkedList<const GEOSGeometry*> *final_queue = new QLinkedList<const GEOSGeometry*>;

    const GEOSGeometry *geom;

    queue->append( the_geom );
    int nGeom;
    int i;

    while ( !queue->isEmpty() )
    {
      geom = queue->takeFirst();
      GEOSContextHandle_t geosctxt = geosContext();
      switch ( GEOSGeomTypeId_r( geosctxt, geom ) )
      {
        case GEOS_MULTIPOINT:
        case GEOS_MULTILINESTRING:
        case GEOS_MULTIPOLYGON:
          nGeom = GEOSGetNumGeometries_r( geosctxt, geom );
          for ( i = 0; i < nGeom; i++ )
          {
            queue->append( GEOSGetGeometryN_r( geosctxt, geom, i ) );
          }
          break;
        case GEOS_POINT:
        case GEOS_LINESTRING:
        case GEOS_POLYGON:
          final_queue->append( geom );
          break;
        default:
          delete final_queue;
          delete queue;
          return NULL;
      }
    }
    delete queue;

    return final_queue;
  }
Beispiel #7
0
void Layer::joinConnectedFeatures()
{
  // go through all label texts
  int connectedFeaturesId = 0;
  Q_FOREACH ( const QString& labelText, mConnectedTexts )
  {
    if ( !mConnectedHashtable.contains( labelText ) )
      continue; // shouldn't happen

    connectedFeaturesId++;

    QLinkedList<FeaturePart*>* parts = mConnectedHashtable.value( labelText );

    // go one-by-one part, try to merge
    while ( !parts->isEmpty() && parts->count() > 1 )
    {
      // part we'll be checking against other in this round
      FeaturePart* partCheck = parts->takeFirst();

      FeaturePart* otherPart = _findConnectedPart( partCheck, parts );
      if ( otherPart )
      {
        // remove partCheck from r-tree
        double checkpartBMin[2], checkpartBMax[2];
        partCheck->getBoundingBox( checkpartBMin, checkpartBMax );

        double otherPartBMin[2], otherPartBMax[2];
        otherPart->getBoundingBox( otherPartBMin, otherPartBMax );

        // merge points from partCheck to p->item
        if ( otherPart->mergeWithFeaturePart( partCheck ) )
        {
          // remove the parts we are joining from the index
          mFeatureIndex->Remove( checkpartBMin, checkpartBMax, partCheck );
          mFeatureIndex->Remove( otherPartBMin, otherPartBMax, otherPart );

          // reinsert merged line to r-tree (probably not needed)
          otherPart->getBoundingBox( otherPartBMin, otherPartBMax );
          mFeatureIndex->Insert( otherPartBMin, otherPartBMax, otherPart );

          mConnectedFeaturesIds.insert( partCheck->featureId(), connectedFeaturesId );
          mConnectedFeaturesIds.insert( otherPart->featureId(), connectedFeaturesId );

          mFeatureParts.removeOne( partCheck );
          delete partCheck;
        }
      }
    }

    // we're done processing feature parts with this particular label text
    delete parts;
    mConnectedHashtable.remove( labelText );
  }

  // we're done processing connected features

  //should be empty, but clear to be safe
  qDeleteAll( mConnectedHashtable );
  mConnectedHashtable.clear();

  mConnectedTexts.clear();
}
Beispiel #8
0
TEST_F(CoverArtUtilTest, searchImage) {
    // creating a temp track directory
    QString trackdir(QDir::tempPath() % "/TrackDir");
    ASSERT_FALSE(QDir().exists(trackdir)); // it must start empty
    ASSERT_TRUE(QDir().mkpath(trackdir));

    TrackPointer pTrack(Track::newTemporary(kTrackLocationTest));
    SoundSourceProxy(pTrack).loadTrackMetadata();
    QLinkedList<QFileInfo> covers;
    CoverArt res;
    // looking for cover in an empty directory
    res = CoverArtUtils::selectCoverArtForTrack(pTrack.data(), covers);
    CoverArt expected;
    expected.info.source = CoverInfo::GUESSED;
    EXPECT_EQ(expected, res);

    // Looking for a track with embedded cover.
    pTrack = TrackPointer(Track::newTemporary(kTrackLocationTest));
    SoundSourceProxy(pTrack).loadTrackMetadataAndCoverArt();
    expected = CoverArt();
    expected.image = pTrack->getCoverArt().image;
    expected.info.type = CoverInfo::METADATA;
    expected.info.source = CoverInfo::GUESSED;
    expected.info.coverLocation = QString();
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);
    EXPECT_EQ(expected, pTrack->getCoverArt());

    const char* format("jpg");
    const QString qFormat(format);

    // Since we already parsed this image from the matadata in
    // kTrackLocationTest, hang on to it since we use it as a template for
    // stuff below.
    const QImage img = expected.image;


    QString trackBaseName = "cover-test";
    QString trackAlbum = "album_name";

    // Search Strategy
    // 0. If we have just one file, we will get it.
    // 1. %track-file-base%.jpg in the track directory for %track-file-base%.mp3
    // 2. %album%.jpg
    // 3. cover.jpg
    // 4. front.jpg
    // 5. album.jpg
    // 6. folder.jpg
    // 7. if just one file exists take that otherwise none.

    // All the following expect the same image/hash to be selected.
    expected.image = img;
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);

    // All the following expect FILE and GUESSED.
    expected.info.type = CoverInfo::FILE;
    expected.info.source = CoverInfo::GUESSED;

    // 0. saving just one cover in our temp track dir
    QString cLoc_foo = QString(trackdir % "/" % "foo." % qFormat);
    EXPECT_TRUE(img.save(cLoc_foo, format));

    // looking for cover in an directory with one image will select that one.
    expected.image = QImage(cLoc_foo);
    expected.info.coverLocation = "foo.jpg";
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);
    covers << QFileInfo(cLoc_foo);
    res = CoverArtUtils::selectCoverArtForTrack(trackBaseName, trackAlbum,
                                                covers);
    EXPECT_EQ(expected, res);
    QFile::remove(cLoc_foo);

    QStringList extraCovers;
    // adding some extra images (bigger) just to populate the track dir.
    QString cLoc_big1 = QString(trackdir % "/" % "big1." % qFormat);
    EXPECT_TRUE(img.scaled(1000,1000).save(cLoc_big1, format));
    extraCovers << cLoc_big1;
    QString cLoc_big2 = QString(trackdir % "/" % "big2." % qFormat);
    EXPECT_TRUE(img.scaled(900,900).save(cLoc_big2, format));
    extraCovers << cLoc_big2;
    QString cLoc_big3 = QString(trackdir % "/" % "big3." % qFormat);
    EXPECT_TRUE(img.scaled(800,800).save(cLoc_big3, format));
    extraCovers << cLoc_big3;

    // saving more covers using the preferred names in the right order
    QLinkedList<QFileInfo> prefCovers;
    // 1. track_filename.jpg
    QString cLoc_filename = QString(trackdir % "/cover-test." % qFormat);
    EXPECT_TRUE(img.scaled(500,500).save(cLoc_filename, format));
    prefCovers << QFileInfo(cLoc_filename);
    // 2. album_name.jpg
    QString cLoc_albumName = QString(trackdir % "/album_name." % qFormat);
    EXPECT_TRUE(img.scaled(500,500).save(cLoc_albumName, format));
    prefCovers << QFileInfo(cLoc_albumName);
    // 3. cover.jpg
    QString cLoc_cover = QString(trackdir % "/" % "cover." % qFormat);
    EXPECT_TRUE(img.scaled(400,400).save(cLoc_cover, format));
    prefCovers << QFileInfo(cLoc_cover);
    // 4. front.jpg
    QString cLoc_front = QString(trackdir % "/" % "front." % qFormat);
    EXPECT_TRUE(img.scaled(300,300).save(cLoc_front, format));
    prefCovers << QFileInfo(cLoc_front);
    // 5. album.jpg
    QString cLoc_album = QString(trackdir % "/" % "album." % qFormat);
    EXPECT_TRUE(img.scaled(100,100).save(cLoc_album, format));
    prefCovers << QFileInfo(cLoc_album);
    // 6. folder.jpg
    QString cLoc_folder = QString(trackdir % "/" % "folder." % qFormat);
    EXPECT_TRUE(img.scaled(100,100).save(cLoc_folder, format));
    prefCovers << QFileInfo(cLoc_folder);
    // 8. other1.jpg
    QString cLoc_other1 = QString(trackdir % "/" % "other1." % qFormat);
    EXPECT_TRUE(img.scaled(10,10).save(cLoc_other1, format));
    prefCovers << QFileInfo(cLoc_other1);
    // 7. other2.jpg
    QString cLoc_other2 = QString(trackdir % "/" % "other2." % qFormat);
    EXPECT_TRUE(img.scaled(10,10).save(cLoc_other2, format));
    prefCovers << QFileInfo(cLoc_other2);

    // we must find covers in the right order
    EXPECT_EQ(8, prefCovers.size());

    // Remove the covers one by one from the front, checking that each one is
    // selected as we remove the previously-most-preferable cover.
    while (!prefCovers.isEmpty()) {
        QFileInfo cover = prefCovers.first();

        // We expect no cover selected for other1 since there are 2 covers,
        // neither of which match our preferred cover names. other2 will be
        // selected once we get to it since it is the only cover available.
        if (cover.baseName() == "other1") {
            expected.image = QImage();
            expected.info.type = CoverInfo::NONE;
            expected.info.coverLocation = QString();
            expected.info.hash = 0;
        } else {
            expected.image = QImage(cover.filePath());
            expected.info.type = CoverInfo::FILE;
            expected.info.coverLocation = cover.fileName();
            expected.info.hash = CoverArtUtils::calculateHash(expected.image);
        }
        res = CoverArtUtils::selectCoverArtForTrack(trackBaseName, trackAlbum,
                                                    prefCovers);
        EXPECT_QSTRING_EQ(expected.info.coverLocation, res.info.coverLocation);
        EXPECT_QSTRING_EQ(expected.info.hash, res.info.hash);
        EXPECT_EQ(expected, res);

        QFile::remove(cover.filePath());
        prefCovers.pop_front();
    }

    //
    // Additional tests
    //

    // what is chosen when cover.jpg and cover.JPG exists?
    // (it must always prefer the lighter cover)
    QString cLoc_coverJPG = trackdir % "/" % "cover." % "JPG";
    EXPECT_TRUE(img.scaled(200,200).save(cLoc_coverJPG, "JPG"));
    prefCovers.append(QFileInfo(cLoc_coverJPG));
    QString cLoc_coverjpg = trackdir % "/" % "cover." % "jpg";
    EXPECT_TRUE(img.scaled(400,400).save(cLoc_coverjpg, "jpg"));
    prefCovers.append(QFileInfo(cLoc_coverjpg));
    extraCovers << cLoc_coverJPG << cLoc_coverjpg;

    res = CoverArtUtils::selectCoverArtForTrack(trackBaseName, trackAlbum,
                                                prefCovers);
    expected.image = QImage(cLoc_coverJPG);
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);
    expected.info.coverLocation = "cover.JPG";
    EXPECT_EQ(expected, res);

    // As we are looking for %album%.jpg and %base_track.jpg%,
    // we need to check if everything works with UTF8 chars.
    trackBaseName = QString::fromUtf8("track_ðÑöæäî");
    trackAlbum = QString::fromUtf8("öæäîðÑ_album");

    prefCovers.clear();

    // 2. album_name.jpg
    cLoc_albumName = QString(trackdir % "/" % trackAlbum % "." % qFormat);
    EXPECT_TRUE(img.save(cLoc_albumName, format));
    prefCovers.append(QFileInfo(cLoc_albumName));
    res = CoverArtUtils::selectCoverArtForTrack(trackBaseName, trackAlbum,
                                                prefCovers);
    expected.image = QImage(cLoc_albumName);
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);
    expected.info.coverLocation = trackAlbum % ".jpg";
    EXPECT_EQ(expected, res);

    // 1. track_filename.jpg
    cLoc_filename = QString(trackdir % "/" % trackBaseName % "." % qFormat);
    EXPECT_TRUE(img.save(cLoc_filename, format));
    prefCovers.append(QFileInfo(cLoc_filename));
    res = CoverArtUtils::selectCoverArtForTrack(trackBaseName, trackAlbum,
                                                prefCovers);
    expected.image = QImage(cLoc_filename);
    expected.info.hash = CoverArtUtils::calculateHash(expected.image);
    expected.info.coverLocation = trackBaseName % ".jpg";
    EXPECT_EQ(expected, res);

    QFile::remove(cLoc_filename);
    QFile::remove(cLoc_albumName);

    // cleaning temp dir
    foreach (QString loc, extraCovers) {
        QFile::remove(loc);
    }
bool KNMusicPlaylistiTunesXMLParser::write(KNMusicPlaylistModel *playlist,
                                           const QString &filePath)
{
    //Generate the plist document.
    QDomDocument plistDocument;
    //Initial the plist element.
    QDomElement plistRoot=plistDocument.createElement("plist");
    plistRoot.setAttribute("version", "1.0");
    plistDocument.appendChild(plistRoot);

    //Initial the dict element.
    QDomElement dictElement=plistDocument.createElement("dict");
    plistRoot.appendChild(dictElement);
    appendDictValue(plistDocument, dictElement, "Major Version", 1);
    appendDictValue(plistDocument, dictElement, "Minor Version", 1);
    appendDictValue(plistDocument, dictElement, "Date",
                    QDateTime::currentDateTime());
    appendDictValue(plistDocument, dictElement, "Features", 5);
    appendDictValue(plistDocument, dictElement, "Show Content Ratings", true);

    //Generate database and song index list.
    QHash<QString, int> filePathIndex;
    QLinkedList<int> playlistIndexList;
    //Add paths to hash keys.
    for(int i=0; i<playlist->rowCount(); i++)
    {
        //Get current path.
        QString currentPath=playlist->rowProperty(i, FilePathRole).toString();
        //Check the path in the index hash.
        int currentIndex=filePathIndex.value(currentPath, -1);
        //If we never insert this path to the index,
        if(currentIndex==-1)
        {
            //Get the new index.
            currentIndex=i;
            //Insert the path to the hash.
            filePathIndex.insert(currentPath, currentIndex);
        }
        //Append the list.
        playlistIndexList.append(currentIndex);
    }

    //Output the database info to dict.
    //Initial the elements.
    QDomElement tracksKey=plistDocument.createElement("key"),
                tracksDict=plistDocument.createElement("dict");
    QDomText tracksKeyValue=plistDocument.createTextNode("Tracks");
    tracksKey.appendChild(tracksKeyValue);
    //Add to dict elements.
    dictElement.appendChild(tracksKey);
    dictElement.appendChild(tracksDict);
    //Write database info.
    QList<int> songIndexList=filePathIndex.values();
    while(!songIndexList.isEmpty())
    {
        int currentRow=songIndexList.takeFirst(),
                trackID=currentRow+100;
        //Generate current row key and dict.
        QDomElement trackKey=plistDocument.createElement("key"),
                    trackDict=plistDocument.createElement("dict");
        //Generate the track key value.
        QDomText trackKeyValue=
                plistDocument.createTextNode(QString::number(trackID));
        trackKey.appendChild(trackKeyValue);
        //Get the detail info.
        const KNMusicDetailInfo detailInfo=playlist->rowDetailInfo(currentRow);
        //Generate the dict.
        appendDictValue(plistDocument, trackDict, "Track ID",
                        trackID);
        appendDictValue(plistDocument, trackDict, "Name",
                        detailInfo.textLists[Name]);
        appendDictValue(plistDocument, trackDict, "Artist",
                        detailInfo.textLists[Artist]);
        appendDictValue(plistDocument, trackDict, "Album Artist",
                        detailInfo.textLists[AlbumArtist]);
        appendDictValue(plistDocument, trackDict, "Genre",
                        detailInfo.textLists[Genre]);
        appendDictValue(plistDocument, trackDict, "Kind",
                        detailInfo.textLists[Kind]);
        appendDictValue(plistDocument, trackDict, "Size",
                        detailInfo.size);
        appendDictValue(plistDocument, trackDict, "Total Time",
                        detailInfo.duration);
        appendDictValue(plistDocument, trackDict, "Track Number",
                        detailInfo.textLists[TrackNumber].toString().toInt());
        appendDictValue(plistDocument, trackDict, "Track Count",
                        detailInfo.textLists[TrackCount].toString().toInt());
        appendDictValue(plistDocument, trackDict, "Year",
                        detailInfo.textLists[Year].toString().toInt());
        appendDictValue(plistDocument, trackDict, "Date Modified",
                        detailInfo.dateModified);
        appendDictValue(plistDocument, trackDict, "Date Added",
                        detailInfo.dateAdded);
        appendDictValue(plistDocument, trackDict, "Bit Rate",
                        detailInfo.bitRate);
        appendDictValue(plistDocument, trackDict, "Sample Rate",
                        detailInfo.samplingRate);
        appendDictValue(plistDocument, trackDict, "Track Type", "File");
        QString fileLocate=QUrl::fromLocalFile(detailInfo.filePath).toString();
#ifdef Q_OS_WIN
        fileLocate.insert(7, "localhost");
#endif
        appendDictValue(plistDocument, trackDict, "Location",
                        QString(QUrl::toPercentEncoding(fileLocate, "/:")));
        appendDictValue(plistDocument, trackDict, "File Folder Count", -1);
        appendDictValue(plistDocument, trackDict, "Library Folder Count", -1);
        //Add the key and dict to track.
        tracksDict.appendChild(trackKey);
        tracksDict.appendChild(trackDict);
    }

    //Output the playlist info to dict.
    QDomElement playlistKey=plistDocument.createElement("key"),
            playlistArray=plistDocument.createElement("array");
    QDomText playlistKeyValue=plistDocument.createTextNode("Playlists");
    playlistKey.appendChild(playlistKeyValue);
    //Add the key and array to dict element.
    dictElement.appendChild(playlistKey);
    dictElement.appendChild(playlistArray);
    //Generate current playlist information.
    QDomElement playlistDict=plistDocument.createElement("dict");
    playlistArray.appendChild(playlistDict);
    //Set playlist information to the dict.
    appendDictValue(plistDocument, playlistDict, "Name", playlist->title());
    appendDictValue(plistDocument, playlistDict, "Playlist ID", "99");
    appendDictValue(plistDocument, playlistDict, "All Items", true);
    //Generate playlist items array.
    QDomElement playlistItemsKey=plistDocument.createElement("key"),
                playlistItemsArray=plistDocument.createElement("array");
    QDomText playlistItemsKeyValue=
                plistDocument.createTextNode("Playlist Items");
    playlistItemsKey.appendChild(playlistItemsKeyValue);
    //Add to current playlist dict.
    playlistDict.appendChild(playlistItemsKey);
    playlistDict.appendChild(playlistItemsArray);
    //Generate Track ID dicts.
    while(!playlistIndexList.isEmpty())
    {
        QDomElement currentTrackDict=plistDocument.createElement("dict");
        appendDictValue(plistDocument,
                        currentTrackDict,
                        "Track ID",
                        100+playlistIndexList.takeFirst());
        //Add the dict to the array.
        playlistItemsArray.appendChild(currentTrackDict);
    }
    return writeContent(filePath,
                        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE "
                        "plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\""
                        " \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
                        + plistDocument.toString(4));
}
Beispiel #10
0
void PointSet::splitPolygons( QLinkedList<PointSet *> &shapes_toProcess,
                              QLinkedList<PointSet *> &shapes_final,
                              double xrm, double yrm )
{
  int i, j;

  int nbp;
  double *x = nullptr;
  double *y = nullptr;

  int *pts = nullptr;

  int *cHull = nullptr;
  int cHullSize;

  double cp;
  double bestcp = 0;

  double bestArea = 0;
  double area;

  double base;
  double b, c;
  double s;

  int ihs;
  int ihn;

  int ips;
  int ipn;

  int holeS = -1;  // hole start and end points
  int holeE = -1;

  int retainedPt = -1;
  int pt = 0;

  double labelArea = xrm * yrm;

  PointSet *shape = nullptr;

  while ( !shapes_toProcess.isEmpty() )
  {
    shape = shapes_toProcess.takeFirst();

    x = shape->x;
    y = shape->y;
    nbp = shape->nbPoints;
    pts = new int[nbp];

    for ( i = 0; i < nbp; i++ )
    {
      pts[i] = i;
    }

    // conpute convex hull
    shape->cHullSize = GeomFunction::convexHullId( pts, x, y, nbp, shape->cHull );

    cHull = shape->cHull;
    cHullSize = shape->cHullSize;

    bestArea = 0;
    retainedPt = -1;

    // lookup for a hole
    for ( ihs = 0; ihs < cHullSize; ihs++ )
    {
      // ihs->ihn => cHull'seg
      ihn = ( ihs + 1 ) % cHullSize;

      ips = cHull[ihs];
      ipn = ( ips + 1 ) % nbp;
      if ( ipn != cHull[ihn] ) // next point on shape is not the next point on cHull => there is a hole here !
      {
        bestcp = 0;
        pt = -1;
        // lookup for the deepest point in the hole
        for ( i = ips; i != cHull[ihn]; i = ( i + 1 ) % nbp )
        {
          cp = std::fabs( GeomFunction::cross_product( x[cHull[ihs]], y[cHull[ihs]],
                          x[cHull[ihn]], y[cHull[ihn]],
                          x[i], y[i] ) );
          if ( cp - bestcp > EPSILON )
          {
            bestcp = cp;
            pt = i;
          }
        }

        if ( pt  != -1 )
        {
          // compute the ihs->ihn->pt triangle's area
          base = GeomFunction::dist_euc2d( x[cHull[ihs]], y[cHull[ihs]],
                                           x[cHull[ihn]], y[cHull[ihn]] );

          b = GeomFunction::dist_euc2d( x[cHull[ihs]], y[cHull[ihs]],
                                        x[pt], y[pt] );

          c = GeomFunction::dist_euc2d( x[cHull[ihn]], y[cHull[ihn]],
                                        x[pt], y[pt] );

          s = ( base + b + c ) / 2; // s = half perimeter
          area = s * ( s - base ) * ( s - b ) * ( s - c );
          if ( area < 0 )
            area = -area;

          // retain the biggest area
          if ( area - bestArea > EPSILON )
          {
            bestArea = area;
            retainedPt = pt;
            holeS = ihs;
            holeE = ihn;
          }
        }
      }
    }

    // we have a hole, its area, and the deppest point in hole
    // we're going to find the second point to cup the shape
    // holeS = hole starting point
    // holeE = hole ending point
    // retainedPt = deppest point in hole
    // bestArea = area of triangle HoleS->holeE->retainedPoint
    bestArea = std::sqrt( bestArea );
    double cx, cy, dx, dy, ex, ey, fx, fy, seg_length, ptx = 0, pty = 0, fptx = 0, fpty = 0;
    int ps = -1, pe = -1, fps = -1, fpe = -1;
    if ( retainedPt >= 0 && bestArea > labelArea ) // there is a hole so we'll cut the shape in two new shape (only if hole area is bigger than twice labelArea)
    {
      c = std::numeric_limits<double>::max();

      // iterate on all shape points except points which are in the hole
      bool isValid;
      int k, l;
      for ( i = ( cHull[holeE] + 1 ) % nbp; i != ( cHull[holeS] - 1 + nbp ) % nbp; i = j )
      {
        j = ( i + 1 ) % nbp; // i->j is shape segment not in hole

        // compute distance between retainedPoint and segment
        // whether perpendicular distance (if retaindPoint is fronting segment i->j)
        // or distance between retainedPt and i or j (choose the nearest)
        seg_length = GeomFunction::dist_euc2d( x[i], y[i], x[j], y[j] );
        cx = ( x[i] + x[j] ) / 2.0;
        cy = ( y[i] + y[j] ) / 2.0;
        dx = cy - y[i];
        dy = cx - x[i];

        ex = cx - dx;
        ey = cy + dy;
        fx = cx + dx;
        fy = cy - dy;

        if ( seg_length < EPSILON || std::fabs( ( b = GeomFunction::cross_product( ex, ey, fx, fy, x[retainedPt], y[retainedPt] ) / ( seg_length ) ) ) > ( seg_length / 2 ) )   // retainedPt is not fronting i->j
        {
          if ( ( ex = GeomFunction::dist_euc2d_sq( x[i], y[i], x[retainedPt], y[retainedPt] ) ) < ( ey = GeomFunction::dist_euc2d_sq( x[j], y[j], x[retainedPt], y[retainedPt] ) ) )
          {
            b = ex;
            ps = i;
            pe = i;
          }
          else
          {
            b = ey;
            ps = j;
            pe = j;
          }
        }
        else   // point fronting i->j => compute pependicular distance  => create a new point
        {
          b = GeomFunction::cross_product( x[i], y[i], x[j], y[j], x[retainedPt], y[retainedPt] ) / seg_length;
          b *= b;
          ps = i;
          pe = j;

          if ( !GeomFunction::computeLineIntersection( x[i], y[i], x[j], y[j], x[retainedPt], y[retainedPt], x[retainedPt] - dx, y[retainedPt] + dy, &ptx, &pty ) )
          {
            //error - it should intersect the line
          }
        }

        isValid = true;
        double pointX, pointY;
        if ( ps == pe )
        {
          pointX = x[pe];
          pointY = y[pe];
        }
        else
        {
          pointX = ptx;
          pointY = pty;
        }

        for ( k = cHull[holeS]; k != cHull[holeE]; k = ( k + 1 ) % nbp )
        {
          l = ( k + 1 ) % nbp;
          if ( GeomFunction::isSegIntersects( x[retainedPt], y[retainedPt], pointX, pointY, x[k], y[k], x[l], y[l] ) )
          {
            isValid = false;
            break;
          }
        }


        if ( isValid && b < c )
        {
          c = b;
          fps = ps;
          fpe = pe;
          fptx = ptx;
          fpty = pty;
        }
      }  // for point which are not in hole

      // we will cut the shapeu in two new shapes, one from [retainedPoint] to [newPoint] and one form [newPoint] to [retainedPoint]
      int imin = retainedPt;
      int imax = ( ( ( fps < retainedPt && fpe < retainedPt ) || ( fps > retainedPt && fpe > retainedPt ) ) ? std::min( fps, fpe ) : std::max( fps, fpe ) );

      int nbPtSh1, nbPtSh2; // how many points in new shapes ?
      if ( imax > imin )
        nbPtSh1 = imax - imin + 1 + ( fpe != fps );
      else
        nbPtSh1 = imax + nbp - imin + 1 + ( fpe != fps );

      if ( ( imax == fps ? fpe : fps ) < imin )
        nbPtSh2 = imin - ( imax == fps ? fpe : fps ) + 1 + ( fpe != fps );
      else
        nbPtSh2 = imin + nbp - ( imax == fps ? fpe : fps ) + 1 + ( fpe != fps );

      if ( retainedPt == -1 || fps == -1 || fpe == -1 )
      {
        if ( shape->parent )
          delete shape;
      }
      // check for useless spliting
      else if ( imax == imin || nbPtSh1 <= 2 || nbPtSh2 <= 2 || nbPtSh1 == nbp  || nbPtSh2 == nbp )
      {
        shapes_final.append( shape );
      }
      else
      {

        PointSet *newShape = shape->extractShape( nbPtSh1, imin, imax, fps, fpe, fptx, fpty );

        if ( shape->parent )
          newShape->parent = shape->parent;
        else
          newShape->parent = shape;

        shapes_toProcess.append( newShape );

        if ( imax == fps )
          imax = fpe;
        else
          imax = fps;

        newShape = shape->extractShape( nbPtSh2, imax, imin, fps, fpe, fptx, fpty );

        if ( shape->parent )
          newShape->parent = shape->parent;
        else
          newShape->parent = shape;

        shapes_toProcess.append( newShape );

        if ( shape->parent )
          delete shape;
      }
    }
    else
    {
      shapes_final.append( shape );
    }
    delete[] pts;
  }
}
/**
 * Produces FLASH erase and write plans for optimally programming application code into
 * a device.
 *
 * This routine assumes that pages filled with blank or "NOP" instructions (0xFFFF) do
 * not need to be erased nor written. For most applications, this will be sufficient,
 * providing extremely fast programming.
 *
 * To guarantee clean memory, perform a Verify After Write CRC check on each Erase
 * Block. This will find any leftover junk data from older firmware that can be erased.
 */
void DeviceWritePlanner::planFlashWrite(QLinkedList<Device::MemoryRange>& eraseList,
                                        QLinkedList<Device::MemoryRange>& writeList,
                                        unsigned int start, unsigned int end,
                                        unsigned int* data, unsigned int* existingData)
{
    unsigned int address = start;
    Device::MemoryRange block;

    while(address < end)
    {
        address = skipEmptyFlashPages(address, data);
        block.start = address;
        if(address >= end)
        {
            break;
        }

        address = findEndFlashWrite(address, data);
        if(address >= end)
        {
            address = end;
        }
        block.end = address;

        if(device->family == Device::PIC16 && !device->hasEraseFlashCommand())
        {
            // Certain PIC16 devices (such as PIC16F882) have a peculiar automatic erase
            // during write feature. To make that work, writes must be expanded to align
            // with Erase Block boundaries.
            block.start -= (block.start % device->eraseBlockSizeFLASH);
            if(block.end % device->eraseBlockSizeFLASH)
            {
                block.end += device->eraseBlockSizeFLASH - (block.end % device->eraseBlockSizeFLASH);
                address = block.end;
            }
        }
        writeList.append(block);

        address++;
    }

    if(existingData == NULL && device->family == Device::PIC32)
    {
        // Because PIC32 has Bulk Erase available for bootloader use,
        // it's faster to simply erase the entire FLASH memory space
        // than erasing specific erase blocks using an erase plan.
        block.start = device->startFLASH;
        block.end = device->endFLASH;
        eraseList.append(block);
    }
    else
    {
        if(existingData != NULL)
        {
            QLinkedList<Device::MemoryRange>::iterator it;
            for(it = writeList.begin(); it != writeList.end(); ++it)
            {
                qDebug("unpruned write(%X to %X)", it->start, it->end);
            }
            doNotWriteExistingData(writeList, start, end, data, existingData);
            for(it = writeList.begin(); it != writeList.end(); ++it)
            {
                qDebug("pruned write(%X to %X)", it->start, it->end);
            }
        }

        if(!writeList.isEmpty())
        {
            if(device->hasEraseFlashCommand())
            {
                flashEraseList(eraseList, writeList, data, existingData);
            }

            EraseAppCheckFirst(eraseList);
            WriteAppCheckLast(writeList);

            if(writeConfig)
            {
                eraseConfigPageLast(eraseList);
                writeConfigPageFirst(writeList);
                doNotEraseBootBlock(eraseList);     // needed in case boot block resides on config page
            }
            else
            {
                doNotEraseConfigPage(eraseList);
            }

            doNotEraseInterruptVectorTable(eraseList);
        }
    }

    packetSizeWriteList(writeList);
}
Beispiel #12
0
bool KNMusicLRCLyricsParser::parseData(const QString &lyricsTextData,
                                       QList<qint64> &positionList,
                                       QStringList &textList)
{
    //Clear the position list and text list.
    positionList.clear();
    textList.clear();
    //Split the lyrics text data.
    QStringList lyricsRawData=lyricsTextData.split(QRegExp("\n"),
                                                   QString::SkipEmptyParts);
    QList<LyricsLine> lyricsLineList;
    //Remove the same line in the lyrics raw data.
    lyricsRawData.removeDuplicates();
    //Parse the lyrics raw data.
    while(!lyricsRawData.isEmpty())
    {
        //Get the first line of the current list and remove all spaces.
        QString currentLine=lyricsRawData.takeFirst().simplified();
        //Find frames in the current line.
        QRegularExpressionMatchIterator frameMatcher=
                m_frameCatchRegExp.globalMatch(currentLine);
        int lastPosition=0;
        QLinkedList<QString> frameLists;
        //Get all the frames.
        while(frameMatcher.hasNext())
        {
            QRegularExpressionMatch matchedFrame=frameMatcher.next();
            //Check is the current matched frame is at the last position.
            //An example is:
            //  [00:00:01] Won't chu kiss me![00:00:03]Saikou no
            if(matchedFrame.capturedStart()!=lastPosition)
            {
                //Then we should pick out the data before the current start and
                //last position.
                //Like 'Won't chu kiss me!' in the example.
                QString text=currentLine.mid(lastPosition,
                                             matchedFrame.capturedStart()-lastPosition);
                //Parse the datas to frame lists.
                while(!frameLists.isEmpty())
                {
                    parseFrames(frameLists.takeFirst(),
                                text,
                                lyricsLineList);
                }
            }
            //Add current frame to frame list.
            frameLists.append(currentLine.mid(matchedFrame.capturedStart(),
                                              matchedFrame.capturedLength()));
            //Update the last position.
            lastPosition=matchedFrame.capturedEnd();
        }
        //Remove the previous datas, and parse the left datas to frame lists.
        currentLine.remove(0, lastPosition);
        while(!frameLists.isEmpty())
        {
            parseFrames(frameLists.takeFirst(),
                        currentLine,
                        lyricsLineList);
        }
    }
    //Check is the lyrics line list is empty or not, if it's empty, means we
    //can't parse it.
    if(lyricsLineList.isEmpty())
    {
        return false;
    }
    //Sorr the lyrics line.
    //- Why stable sort?
    //  Because there might be some frames at the same time. Display them with
    //their exist order.
    qStableSort(lyricsLineList.begin(), lyricsLineList.end(), frameLessThan);
    //Combine the same timestamp lyrics.
    QMap<qint64, QString> lyricsCombineMap;
    for(QList<LyricsLine>::iterator i=lyricsLineList.begin();
        i!=lyricsLineList.end();
        ++i)
    {
        lyricsCombineMap.insert((*i).position,
                                lyricsCombineMap.contains((*i).position)?
                                    lyricsCombineMap.value((*i).position)+'\n'+(*i).text:
                                    (*i).text);
    }
    //Export the position and the text.
    positionList=lyricsCombineMap.keys();
    textList=lyricsCombineMap.values();
    return true;
}
Beispiel #13
0
bool KNMusicTagWav::parseTag(QFile &musicFile,
                             QDataStream &musicDataStream,
                             KNMusicAnalysisItem &analysisItem)
{
    //Check file size.
    if(musicFile.size()<12)
    {
        //It cannot be a wav format file, until a valid one.
        return false;
    }
    //Gernerate the header cache.
    char rawHeader[12];
    //Read the header.
    musicDataStream.readRawData(rawHeader, 12);
    //Check the riff header and the wave header.
    if(memcmp(rawHeader, m_riffHeader, 4)!=0 ||
            memcmp(rawHeader+8, m_waveHeader, 4)!=0)
    {
        //This is not a wav file.
        return false;
    }
    /*
     * WAV file is a combination of several chunks.
     * Read all the chunks, and find LIST and id32 chunk.
     */
    //Get the music file size.
    qint64 fileSize=musicFile.size();
    //Generate the chunk header cache.
    char chunkHeader[8];
    //Initial the chunk found flag.
    bool listFound=false, id32Found=false;
    //We have to prepare the list here and write the data after parse all the
    //data, we want the id32 chunk has a higher priority than list chunk.
    //Prepare the wav item list for list chunk.
    QList<WAVItem> listData;
    //Generate the raw frame linked list for id32 chunk.
    QLinkedList<ID3v2Frame> frames;
    //Generate the id3v2 frame function set for id32 chunk.
    ID3v2FunctionSet functionSet;
    //Start finding the chunk.
    while(musicDataStream.device()->pos()<fileSize && !listFound && !id32Found)
    {
        //Read chunk head.
        musicDataStream.readRawData(chunkHeader, 8);
        //Calculate the chunk size.
        quint32 chunkSize=KNMusicUtil::inverseCharToInt32(chunkHeader+4);
        //Check if it's list chunk
        if(memcmp(chunkHeader, m_listChunk, 4)==0)
        {
            //Set list chunk found flag to true.
            listFound=true;
            //Generate chunk size cache.
            char *listRawData=new char[chunkSize];
            //Read the raw data.
            musicDataStream.readRawData(listRawData, chunkSize);
            //Parse list chunk.
            parseListChunk(listRawData, chunkSize, listData);
            //Recover memory.
            delete[] listRawData;
        }
        //Check if it's id32 chunk.
        else if(memcmp(chunkHeader, m_id32Chunk, 4)==0)
        {
            //Generate ID3v2 header cache.
            char rawHeader[10];
            //Generate ID3v2 header structure.
            ID3v2Header header;
            //Read ID3v2 header data.
            musicDataStream.readRawData(rawHeader, 10);
            //Parse the ID3v2 header.
            //and then Check is chunk size smaller than tag size.
            if(!parseID3v2Header(rawHeader, header) ||
                    chunkSize<(header.size+10))
            {
                //If we cannot parse it, skip the whole chunk.
                musicDataStream.skipRawData(chunkSize-10);
                //Continue to next chunk.
                continue;
            }
            //Generate the raw tag data field.
            char *rawTagData=new char[header.size];
            //Read the raw tag data.
            musicDataStream.readRawData(rawTagData, header.size);
            //Get the function set according to the minor version of the header.
            getId3v2FunctionSet(header.major, functionSet);
            //Parse the raw data.
            parseID3v2RawData(rawTagData, header, functionSet, frames);
            //Recover the memory.
            delete[] rawTagData;
            //Set the id32 chunk find flag to true.
            id32Found=true;
        }
        //For all the other chunks.
        else
        {
            //Skip the data.
            musicDataStream.skipRawData(chunkSize);
        }
    }
    //Check if the list data is not empty, first.
    //The data can be overwrite by id32 chunk data.
    if(!listData.isEmpty())
    {
        //Check all the data in the wav item list.
        for(auto i : listData)
        {
            //Get the index of current item.
            int chunkIndex=m_listKeyIndex.value(i.key, -1);
            //Check the validation of chunk index.
            if(chunkIndex==-1)
            {
                //Abandon the current index.
                continue;
            }
            //Set the data.
            analysisItem.detailInfo.textLists[chunkIndex]=
                    QVariant(i.value);
        }
    }
    //Check id32 chunk data then.
    if(!frames.isEmpty())
    {
        //Write the tag to analysis info.
        writeFrameToDetails(frames, functionSet, analysisItem);
    }
    //Mission complete.
    return true;
}
Beispiel #14
0
//static
CoverArt CoverArtUtils::selectCoverArtForTrack(
        const QString& trackBaseName,
        const QString& albumName,
        const QLinkedList<QFileInfo>& covers) {
    CoverArt art;
    art.info.source = CoverInfo::GUESSED;
    if (covers.isEmpty()) {
        return art;
    }

    PreferredCoverType bestType = NONE;
    const QFileInfo* bestInfo = NULL;

    // If there is a single image then we use it unconditionally. Otherwise
    // we use the priority order described in PreferredCoverType. Notably,
    // if there are multiple image files in the folder we require they match
    // one of the name patterns -- otherwise we run the risk of picking an
    // arbitrary image that happens to be in the same folder as some of the
    // user's music files.
    if (covers.size() == 1) {
        bestInfo = &covers.first();
    } else {
        // TODO(XXX) Sort instead so that we can fall-back if one fails to
        // open?
        foreach (const QFileInfo& file, covers) {
            const QString coverBaseName = file.baseName();
            if (bestType > TRACK_BASENAME &&
                coverBaseName.compare(trackBaseName,
                                      Qt::CaseInsensitive) == 0) {
                bestType = TRACK_BASENAME;
                bestInfo = &file;
                // This is the best type so we know we're done.
                break;
            } else if (bestType > ALBUM_NAME &&
                       coverBaseName.compare(albumName,
                                             Qt::CaseInsensitive) == 0) {
                bestType = ALBUM_NAME;
                bestInfo = &file;
            } else if (bestType > COVER &&
                       coverBaseName.compare(QLatin1String("cover"),
                                             Qt::CaseInsensitive) == 0) {
                bestType = COVER;
                bestInfo = &file;
            } else if (bestType > FRONT &&
                       coverBaseName.compare(QLatin1String("front"),
                                             Qt::CaseInsensitive) == 0) {
                bestType = FRONT;
                bestInfo = &file;
            } else if (bestType > ALBUM &&
                       coverBaseName.compare(QLatin1String("album"),
                                             Qt::CaseInsensitive) == 0) {
                bestType = ALBUM;
                bestInfo = &file;
            } else if (bestType > FOLDER &&
                       coverBaseName.compare(QLatin1String("folder"),
                                             Qt::CaseInsensitive) == 0) {
                bestType = FOLDER;
                bestInfo = &file;
            }
        }
    }

    if (bestInfo != NULL) {
        art.image = QImage(bestInfo->filePath());
        if (!art.image.isNull()) {
            art.info.source = CoverInfo::GUESSED;
            art.info.type = CoverInfo::FILE;
            // TODO() here we may introduce a duplicate hash code
            art.info.hash = CoverArtUtils::calculateHash(art.image);
            art.info.coverLocation = bestInfo->fileName();
            return art;
        }
    }

    return art;
}
Beispiel #15
0
bool Layer::registerFeature( QgsLabelFeature* lf )
{
  if ( lf->size().width() < 0 || lf->size().height() < 0 )
    return false;

  mMutex.lock();

  if ( mHashtable.contains( lf->id() ) )
  {
    mMutex.unlock();
    //A feature with this id already exists. Don't throw an exception as sometimes,
    //the same feature is added twice (dateline split with otf-reprojection)
    return false;
  }

  // assign label feature to this PAL layer
  lf->setLayer( this );

  // Split MULTI GEOM and Collection in simple geometries

  bool addedFeature = false;

  double geom_size = -1, biggest_size = -1;
  FeaturePart* biggest_part = nullptr;

  // break the (possibly multi-part) geometry into simple geometries
  QLinkedList<const GEOSGeometry*>* simpleGeometries = Util::unmulti( lf->geometry() );
  if ( !simpleGeometries ) // unmulti() failed?
  {
    mMutex.unlock();
    throw InternalException::UnknownGeometry();
  }

  GEOSContextHandle_t geosctxt = geosContext();

  bool featureGeomIsObstacleGeom = !lf->obstacleGeometry();

  while ( !simpleGeometries->isEmpty() )
  {
    const GEOSGeometry* geom = simpleGeometries->takeFirst();

    // ignore invalid geometries (e.g. polygons with self-intersecting rings)
    if ( GEOSisValid_r( geosctxt, geom ) != 1 ) // 0=invalid, 1=valid, 2=exception
    {
      continue;
    }

    int type = GEOSGeomTypeId_r( geosctxt, geom );

    if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON )
    {
      mMutex.unlock();
      throw InternalException::UnknownGeometry();
    }

    FeaturePart* fpart = new FeaturePart( lf, geom );

    // ignore invalid geometries
    if (( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) ||
        ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) )
    {
      delete fpart;
      continue;
    }

    // polygons: reorder coordinates
    if ( type == GEOS_POLYGON && GeomFunction::reorderPolygon( fpart->nbPoints, fpart->x, fpart->y ) != 0 )
    {
      delete fpart;
      continue;
    }

    // is the feature well defined?  TODO Check epsilon
    bool labelWellDefined = ( lf->size().width() > 0.0000001 && lf->size().height() > 0.0000001 );

    if ( lf->isObstacle() && featureGeomIsObstacleGeom )
    {
      //if we are not labelling the layer, only insert it into the obstacle list and avoid an
      //unnecessary copy
      if ( mLabelLayer && labelWellDefined )
      {
        addObstaclePart( new FeaturePart( *fpart ) );
      }
      else
      {
        addObstaclePart( fpart );
        fpart = nullptr;
      }
    }

    // feature has to be labeled?
    if ( !mLabelLayer || !labelWellDefined )
    {
      //nothing more to do for this part
      delete fpart;
      continue;
    }

    if ( mMode == LabelPerFeature && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) )
    {
      if ( type == GEOS_LINESTRING )
        GEOSLength_r( geosctxt, geom, &geom_size );
      else if ( type == GEOS_POLYGON )
        GEOSArea_r( geosctxt, geom, &geom_size );

      if ( geom_size > biggest_size )
      {
        biggest_size = geom_size;
        delete biggest_part; // safe with NULL part
        biggest_part = fpart;
      }
      else
      {
        delete fpart;
      }
      continue; // don't add the feature part now, do it later
    }

    // feature part is ready!
    addFeaturePart( fpart, lf->labelText() );
    addedFeature = true;
  }
  delete simpleGeometries;

  if ( !featureGeomIsObstacleGeom )
  {
    //do the same for the obstacle geometry
    simpleGeometries = Util::unmulti( lf->obstacleGeometry() );
    if ( !simpleGeometries ) // unmulti() failed?
    {
      mMutex.unlock();
      throw InternalException::UnknownGeometry();
    }

    while ( !simpleGeometries->isEmpty() )
    {
      const GEOSGeometry* geom = simpleGeometries->takeFirst();

      // ignore invalid geometries (e.g. polygons with self-intersecting rings)
      if ( GEOSisValid_r( geosctxt, geom ) != 1 ) // 0=invalid, 1=valid, 2=exception
      {
        continue;
      }

      int type = GEOSGeomTypeId_r( geosctxt, geom );

      if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON )
      {
        mMutex.unlock();
        throw InternalException::UnknownGeometry();
      }

      FeaturePart* fpart = new FeaturePart( lf, geom );

      // ignore invalid geometries
      if (( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) ||
          ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) )
      {
        delete fpart;
        continue;
      }

      // polygons: reorder coordinates
      if ( type == GEOS_POLYGON && GeomFunction::reorderPolygon( fpart->nbPoints, fpart->x, fpart->y ) != 0 )
      {
        delete fpart;
        continue;
      }

      // feature part is ready!
      addObstaclePart( fpart );
    }
    delete simpleGeometries;
  }

  mMutex.unlock();

  // if using only biggest parts...
  if (( mMode == LabelPerFeature || lf->hasFixedPosition() ) && biggest_part )
  {
    addFeaturePart( biggest_part, lf->labelText() );
    addedFeature = true;
  }

  // add feature to layer if we have added something
  if ( addedFeature )
  {
    mHashtable.insert( lf->id(), lf );
  }

  return addedFeature; // true if we've added something
}
Beispiel #16
0
std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeometry &mapBoundary )
{
  // to store obstacles
  RTree<FeaturePart *, double, 2, double> *obstacles = new RTree<FeaturePart *, double, 2, double>();

  std::unique_ptr< Problem > prob = qgis::make_unique< Problem >();

  int i, j;

  double bbx[4];
  double bby[4];

  double amin[2];
  double amax[2];

  int max_p = 0;

  LabelPosition *lp = nullptr;

  bbx[0] = bbx[3] = amin[0] = prob->bbox[0] = extent.xMinimum();
  bby[0] = bby[1] = amin[1] = prob->bbox[1] = extent.yMinimum();
  bbx[1] = bbx[2] = amax[0] = prob->bbox[2] = extent.xMaximum();
  bby[2] = bby[3] = amax[1] = prob->bbox[3] = extent.yMaximum();

  prob->pal = this;

  QLinkedList<Feats *> *fFeats = new QLinkedList<Feats *>;

  FeatCallBackCtx context;

  // prepare map boundary
  geos::unique_ptr mapBoundaryGeos( QgsGeos::asGeos( mapBoundary ) );
  geos::prepared_unique_ptr mapBoundaryPrepared( GEOSPrepare_r( QgsGeos::getGEOSHandler(), mapBoundaryGeos.get() ) );

  context.fFeats = fFeats;
  context.obstacles = obstacles;
  context.candidates = prob->candidates;
  context.mapBoundary = mapBoundaryPrepared.get();

  ObstacleCallBackCtx obstacleContext;
  obstacleContext.obstacles = obstacles;
  obstacleContext.obstacleCount = 0;

  // first step : extract features from layers

  int previousFeatureCount = 0;
  int previousObstacleCount = 0;

  QStringList layersWithFeaturesInBBox;

  mMutex.lock();
  const auto constMLayers = mLayers;
  for ( Layer *layer : constMLayers )
  {
    if ( !layer )
    {
      // invalid layer name
      continue;
    }

    // only select those who are active
    if ( !layer->active() )
      continue;

    // check for connected features with the same label text and join them
    if ( layer->mergeConnectedLines() )
      layer->joinConnectedFeatures();

    layer->chopFeaturesAtRepeatDistance();

    layer->mMutex.lock();

    // find features within bounding box and generate candidates list
    context.layer = layer;
    layer->mFeatureIndex->Search( amin, amax, extractFeatCallback, static_cast< void * >( &context ) );
    // find obstacles within bounding box
    layer->mObstacleIndex->Search( amin, amax, extractObstaclesCallback, static_cast< void * >( &obstacleContext ) );

    layer->mMutex.unlock();

    if ( context.fFeats->size() - previousFeatureCount > 0 || obstacleContext.obstacleCount > previousObstacleCount )
    {
      layersWithFeaturesInBBox << layer->name();
    }
    previousFeatureCount = context.fFeats->size();
    previousObstacleCount = obstacleContext.obstacleCount;
  }
  mMutex.unlock();

  prob->nbLabelledLayers = layersWithFeaturesInBBox.size();
  prob->labelledLayersName = layersWithFeaturesInBBox;

  if ( fFeats->isEmpty() )
  {
    delete fFeats;
    delete obstacles;
    return nullptr;
  }

  prob->nbft = fFeats->size();
  prob->nblp = 0;
  prob->featNbLp = new int [prob->nbft];
  prob->featStartId = new int [prob->nbft];
  prob->inactiveCost = new double[prob->nbft];

  Feats *feat = nullptr;

  // Filtering label positions against obstacles
  amin[0] = amin[1] = std::numeric_limits<double>::lowest();
  amax[0] = amax[1] = std::numeric_limits<double>::max();
  FilterContext filterCtx;
  filterCtx.cdtsIndex = prob->candidates;
  filterCtx.pal = this;
  obstacles->Search( amin, amax, filteringCallback, static_cast< void * >( &filterCtx ) );

  if ( isCanceled() )
  {
    const auto constFFeats = *fFeats;
    for ( Feats *feat : constFFeats )
    {
      qDeleteAll( feat->lPos );
      feat->lPos.clear();
    }

    qDeleteAll( *fFeats );
    delete fFeats;
    delete obstacles;
    return nullptr;
  }

  int idlp = 0;
  for ( i = 0; i < prob->nbft; i++ ) /* foreach feature into prob */
  {
    feat = fFeats->takeFirst();

    prob->featStartId[i] = idlp;
    prob->inactiveCost[i] = std::pow( 2, 10 - 10 * feat->priority );

    switch ( feat->feature->getGeosType() )
    {
      case GEOS_POINT:
        max_p = point_p;
        break;
      case GEOS_LINESTRING:
        max_p = line_p;
        break;
      case GEOS_POLYGON:
        max_p = poly_p;
        break;
    }

    // sort candidates by cost, skip less interesting ones, calculate polygon costs (if using polygons)
    max_p = CostCalculator::finalizeCandidatesCosts( feat, max_p, obstacles, bbx, bby );

    // only keep the 'max_p' best candidates
    while ( feat->lPos.count() > max_p )
    {
      // TODO remove from index
      feat->lPos.last()->removeFromIndex( prob->candidates );
      delete feat->lPos.takeLast();
    }

    // update problem's # candidate
    prob->featNbLp[i] = feat->lPos.count();
    prob->nblp += feat->lPos.count();

    // add all candidates into a rtree (to speed up conflicts searching)
    for ( j = 0; j < feat->lPos.count(); j++, idlp++ )
    {
      lp = feat->lPos.at( j );
      //lp->insertIntoIndex(prob->candidates);
      lp->setProblemIds( i, idlp ); // bugfix #1 (maxence 10/23/2008)
    }
    fFeats->append( feat );
  }

  int nbOverlaps = 0;

  while ( !fFeats->isEmpty() ) // foreach feature
  {
    if ( isCanceled() )
    {
      const auto constFFeats = *fFeats;
      for ( Feats *feat : constFFeats )
      {
        qDeleteAll( feat->lPos );
        feat->lPos.clear();
      }

      qDeleteAll( *fFeats );
      delete fFeats;
      delete obstacles;
      return nullptr;
    }

    feat = fFeats->takeFirst();
    while ( !feat->lPos.isEmpty() ) // foreach label candidate
    {
      lp = feat->lPos.takeFirst();
      lp->resetNumOverlaps();

      // make sure that candidate's cost is less than 1
      lp->validateCost();

      prob->addCandidatePosition( lp );
      //prob->feat[idlp] = j;

      lp->getBoundingBox( amin, amax );

      // lookup for overlapping candidate
      prob->candidates->Search( amin, amax, LabelPosition::countOverlapCallback, static_cast< void * >( lp ) );

      nbOverlaps += lp->getNumOverlaps();
    }
    delete feat;
  }
  delete fFeats;

  //delete candidates;
  delete obstacles;

  nbOverlaps /= 2;
  prob->all_nblp = prob->nblp;
  prob->nbOverlap = nbOverlaps;

  return prob;
}
Beispiel #17
0
void compile(QString path,QStringList& import,QFile &out){
    QFile fp(path);
    if(fp.open(QFile::ReadOnly)){
        QDir dir(QFileInfo(fp).absoluteDir());
        QString modName = QFileInfo(fp).baseName();
        if(readLine(fp).trimmed()!=FILE_HEAD){
            qDebug("Indicated file is not a algorithm file of Uranus2");
            exit(0);
        }
        int pIndent,cIndent=0,functionIndent=0;
        Function* function=0;
        QRegExp keyWord("(\\s*)(\\w+)\\s",Qt::CaseInsensitive);
        QRegExp argHook("(<.+>)?(.+)?");
        QLinkedList<StackItem*> stack;
        while(!fp.atEnd()){
            QString line=QString::fromUtf8(fp.readLine());
            keyWord.indexIn(line);
            QString key=keyWord.cap(2).toLower();
            line=line.mid(keyWord.cap().length()).trimmed();
            pIndent = cIndent;
            cIndent=keyWord.cap(1).length();
            if(cIndent<functionIndent){
                if(function!=0){
                    function->write(out);
                    function=0;
                }
            }else if(cIndent<=pIndent){
                while(pIndent>=cIndent){
                    pIndent--;
                    if(!stack.isEmpty()){
                        stack.pop_back();
                    }
                }
            }
            StackItem* parent = (stack.isEmpty())?0:stack.back(),
                    *self=new StackItem(key,line,cIndent);
            stack.push_back(self);

            if(key=="import"){
                import.append(dir.absoluteFilePath(line));
            }else if(key=="function"){
                function=new Function(modName,line);
                functionIndent=cIndent+1;
            }else if(key=="hint"){
                if(function!=0){
                    if(parent->key=="function")
                        self->indent++;
                    self->outBegin="#"+line;
                    function->append(self);
                }
            }else if(key=="arg"){
                if(parent->key=="function"&&function){
                    function->args()<<line;
                }
            }else if(key=="assign"){
                self->outBegin=line+"=";
                function->append(self);
            }else if(key=="value"){
                if(parent->key=="assign"){
                    argHook.indexIn(line);
                    if(argHook.cap(1)=="<list>"){
                    }else if(argHook.cap(1)=="<function>"){
                    }else if(argHook.cap(1)=="<variable>"){
                        self->outBegin=argHook.cap(2).trimmed();
                    }else{
                        self->outBegin=line.trimmed();
                    }
                    parent->addChild(self);
                }
            }else if(key=="branch"){
                self->outBegin="if True:";
                function->append(self);
            }else if(key=="call"){
                QString fname;
                if(line.left(3)=="://"){
                    fname=Function::conv(modName,line.mid(3));
                }else{
                    QStringList f = line.split("/");
                    if(f.count()==2){
                        fname=Function::conv(f.at(0),f.at(1));
                    }
                }
                self->outBegin=fname+"(";
                self->outSep=",";
                self->outEnd=")";
                if(parent->key=="do"){
                    function->append(self);
                }else{
                    parent->addChild(self);
                }
            }else if(key=="conditional"){
                self->outBegin="if True:";
                function->append(self);
            }else if(key=="do"){
            }else if(key=="list"){
                self->outBegin="[";
                self->outSep=",";
                self->outEnd="]";
                parent->addChild(self);
            }else if(key=="item"){
                argHook.indexIn(line);
                if(argHook.cap(1)=="<list>"){
                }else if(argHook.cap(1)=="<function>"){
                }else if(argHook.cap(1)=="<variable>"){
                    self->outBegin=argHook.cap(2).trimmed();
                }else{
                    self->outBegin=line.trimmed();
                }
                parent->addChild(self);
            }else if(key=="loop"){
                self->outBegin="if True:";
                function->append(self);
            }else if(key=="traverseloop"){
                self->outBegin="if True:";
                function->append(self);
            }else if(key=="traverse"){
                self->outBegin="for traverse in ";
                self->outEnd=":";
                function->append(self);
            }else if(key=="condition"){
                self->outEnd=":";
                if(parent->key=="branch"){
                    if(parent->data==0){
                        self->outBegin="if ";
                    }else{
                        self->outBegin="elif ";
                    }
                    parent->data=1;
                }else if(parent->key=="loop"){
                    self->outBegin="while ";
                }
                argHook.indexIn(line);
                if(argHook.cap(1)=="<list>"){
                }else if(argHook.cap(1)=="<function>"){
                }else if(argHook.cap(1)=="<variable>"){
                    self->outBegin+=argHook.cap(2).trimmed();
                }else{
                    self->outBegin+=line.trimmed();
                }
                function->append(self);
            }else if(key=="return"){
                self->outBegin="return ";
                argHook.indexIn(line);
                if(argHook.cap(1)=="<list>"){
                }else if(argHook.cap(1)=="<function>"){
                }else if(argHook.cap(1)=="<variable>"){
                    self->outBegin+=argHook.cap(2).trimmed();
                }else{
                    self->outBegin+=line.trimmed();
                }
                function->append(self);
            }else if(key=="execute"){
                self->outBegin="exec(";
                self->outEnd=")";
                argHook.indexIn(line);
                if(argHook.cap(1)=="<list>"){
                }else if(argHook.cap(1)=="<function>"){
                }else if(argHook.cap(1)=="<variable>"){
                    self->outBegin+=argHook.cap(2).trimmed();
                }else{
                    self->outBegin+=line.trimmed();
                }
                function->append(self);
            }else if(key=="break"){
                self->outBegin = "break";
                function->append(self);
            }else if(key=="continue"){
                self->outBegin = "continue";
                function->append(self);
            }else{
                if(parent->key=="call"){
                    argHook.indexIn(line);
                    if(argHook.cap(1)=="<list>"){
                    }else if(argHook.cap(1)=="<function>"){
                    }else if(argHook.cap(1)=="<variable>"){
                        self->outBegin+=argHook.cap(2).trimmed();
                    }else{
                        self->outBegin+=line.trimmed();
                    }
                    parent->addChild(self);
                }
            }
        }
        if(function!=0)
            function->write(out);
    }else{
        qDebug()<<"Can not open file "+path;
    }
}