<commit_before>#include "chrono_parallel/collision/ChCCollisionSystemBulletParallel.h"

namespace chrono {
namespace collision {

/*
 void defaultChronoNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo&
 dispatchInfo)
 {
 btCollisionDispatcher::defaultNearCallback(collisionPair, dispatcher, dispatchInfo);
 if (broad_callback)
 broad_callback(collisionPair, dispatcher, dispatchInfo);
 }
*/

ChCollisionSystemBulletParallel::ChCollisionSystemBulletParallel(ChParallelDataManager* dc,
                                                                 unsigned int max_objects,
                                                                 double scene_size)
    : data_manager(dc) {
  // btDefaultCollisionConstructionInfo conf_info(...); ***TODO***
  bt_collision_configuration = new btDefaultCollisionConfiguration();
  bt_dispatcher = new btCollisionDispatcher(bt_collision_configuration);

  //***OLD***

  btScalar sscene_size = (btScalar)scene_size;
  btVector3 worldAabbMin(-sscene_size, -sscene_size, -sscene_size);
  btVector3 worldAabbMax(sscene_size, sscene_size, sscene_size);
  bt_broadphase = new bt32BitAxisSweep3(
      worldAabbMin, worldAabbMax, max_objects, 0, true);  // true for disabling raycast accelerator

  //***NEW***
  // bt_broadphase = new btDbvtBroadphase();

  bt_collision_world = new btCollisionWorld(bt_dispatcher, bt_broadphase, bt_collision_configuration);

  // custom collision for sphere-sphere case ***OBSOLETE***
  // bt_dispatcher->registerCollisionCreateFunc(SPHERE_SHAPE_PROXYTYPE,SPHERE_SHAPE_PROXYTYPE,new
  // btSphereSphereCollisionAlgorithm::CreateFunc);

  // register custom collision for GIMPACT mesh case too
  btGImpactCollisionAlgorithm::registerAlgorithm(bt_dispatcher);

  counter = 0;
}

ChCollisionSystemBulletParallel::~ChCollisionSystemBulletParallel() {
  if (bt_collision_world)
    delete bt_collision_world;
  if (bt_broadphase)
    delete bt_broadphase;
  if (bt_dispatcher)
    delete bt_dispatcher;
  if (bt_collision_configuration)
    delete bt_collision_configuration;
}

void ChCollisionSystemBulletParallel::Clear(void) {
  int numManifolds = bt_collision_world->getDispatcher()->getNumManifolds();
  for (int i = 0; i < numManifolds; i++) {
    btPersistentManifold* contactManifold = bt_collision_world->getDispatcher()->getManifoldByIndexInternal(i);
    contactManifold->clearManifold();
  }
}

void ChCollisionSystemBulletParallel::Add(ChCollisionModel* model) {
  ChModelBullet* bmodel = static_cast<ChModelBullet*>(model);
  if (bmodel->GetBulletModel()->getCollisionShape()) {
    bmodel->SyncPosition();
    bmodel->GetBulletModel()->setCompanionId(counter);
    bt_collision_world->addCollisionObject(bmodel->GetBulletModel(), bmodel->GetFamilyGroup(), bmodel->GetFamilyMask());
    counter++;
    data_manager->num_rigid_shapes++;
  }
}

void ChCollisionSystemBulletParallel::Remove(ChCollisionModel* model) {
  ChModelBullet* bmodel = static_cast<ChModelBullet*>(model);
  if (bmodel->GetBulletModel()->getCollisionShape()) {
    bt_collision_world->removeCollisionObject(bmodel->GetBulletModel());
  }
}

void ChCollisionSystemBulletParallel::Run() {
  data_manager->system_timer.start("collision_broad");
  if (bt_collision_world) {
    bt_collision_world->performDiscreteCollisionDetection();
  }
  data_manager->system_timer.stop("collision_broad");
}
void ChCollisionSystemBulletParallel::ReportContacts(ChContactContainerBase* mcontactcontainer) {
  data_manager->system_timer.start("collision_narrow");
  data_manager->host_data.norm_rigid_rigid.clear();
  data_manager->host_data.cpta_rigid_rigid.clear();
  data_manager->host_data.cptb_rigid_rigid.clear();
  data_manager->host_data.dpth_rigid_rigid.clear();
  data_manager->host_data.bids_rigid_rigid.clear();
  data_manager->num_rigid_contacts = 0;
  // mcontactcontainer->BeginAddContact();
  ChCollisionInfo icontact;

  int numManifolds = bt_collision_world->getDispatcher()->getNumManifolds();
  for (int i = 0; i < numManifolds; i++) {
    btPersistentManifold* contactManifold = bt_collision_world->getDispatcher()->getManifoldByIndexInternal(i);
    btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
    btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
    contactManifold->refreshContactPoints(obA->getWorldTransform(), obB->getWorldTransform());

    icontact.modelA = (ChCollisionModel*)obA->getUserPointer();
    icontact.modelB = (ChCollisionModel*)obB->getUserPointer();

    double envelopeA = icontact.modelA->GetEnvelope();
    double envelopeB = icontact.modelB->GetEnvelope();

    double marginA = icontact.modelA->GetSafeMargin();
    double marginB = icontact.modelB->GetSafeMargin();

    bool activeA = ((ChBody*)(icontact.modelA->GetPhysicsItem()))->IsActive();
    bool activeB = ((ChBody*)(icontact.modelB->GetPhysicsItem()))->IsActive();

    if (activeA == 0 && activeB == 0) {
      continue;
    }

    // Execute custom broadphase callback, if any
    bool do_narrow_contactgeneration = true;
    if (this->broad_callback)
      do_narrow_contactgeneration = this->broad_callback->BroadCallback(icontact.modelA, icontact.modelB);

    if (do_narrow_contactgeneration) {
      int numContacts = contactManifold->getNumContacts();

      for (int j = 0; j < numContacts; j++) {
        btManifoldPoint& pt = contactManifold->getContactPoint(j);

        if (pt.getDistance() <
            marginA + marginB)  // to discard "too far" constraints (the Bullet engine also has its threshold)
        {
          btVector3 ptA = pt.getPositionWorldOnA();
          btVector3 ptB = pt.getPositionWorldOnB();

          icontact.vpA.Set(ptA.getX(), ptA.getY(), ptA.getZ());
          icontact.vpB.Set(ptB.getX(), ptB.getY(), ptB.getZ());

          icontact.vN.Set(-pt.m_normalWorldOnB.getX(), -pt.m_normalWorldOnB.getY(), -pt.m_normalWorldOnB.getZ());
          icontact.vN.Normalize();

          double ptdist = pt.getDistance();

          icontact.vpA = icontact.vpA - icontact.vN * envelopeA;
          icontact.vpB = icontact.vpB + icontact.vN * envelopeB;

          icontact.distance = ptdist + envelopeA + envelopeB;

          icontact.reaction_cache = pt.reactions_cache;

          // Execute some user custom callback, if any
          if (this->narrow_callback)
            this->narrow_callback->NarrowCallback(icontact);

          // Add to contact container
          // mcontactcontainer->AddContact(icontact);

          data_manager->host_data.norm_rigid_rigid.push_back(R3(icontact.vN.x, icontact.vN.y, icontact.vN.z));
          data_manager->host_data.cpta_rigid_rigid.push_back(R3(icontact.vpA.x, icontact.vpA.y, icontact.vpA.z));
          data_manager->host_data.cptb_rigid_rigid.push_back(R3(icontact.vpB.x, icontact.vpB.y, icontact.vpB.z));
          data_manager->host_data.dpth_rigid_rigid.push_back(icontact.distance);
          data_manager->host_data.bids_rigid_rigid.push_back(I2(obA->getCompanionId(), obB->getCompanionId()));
          data_manager->num_rigid_contacts++;
        }
      }
    }
    // you can un-comment out this line, and then all points are removed
    // contactManifold->clearManifold();
  }

  // mcontactcontainer->EndAddContact();
  data_manager->system_timer.stop("collision_narrow");
}
}  // END_OF_NAMESPACE____
}  // END_OF_NAMESPACE____
<commit_msg>Fix for DEM-P contact.<commit_after>#include "chrono_parallel/collision/ChCCollisionSystemBulletParallel.h"

namespace chrono {
namespace collision {

static const real edge_radius = 0.01;  // default edge radius (for penalty contact)

/*
 void defaultChronoNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo&
 dispatchInfo)
 {
 btCollisionDispatcher::defaultNearCallback(collisionPair, dispatcher, dispatchInfo);
 if (broad_callback)
 broad_callback(collisionPair, dispatcher, dispatchInfo);
 }
*/

ChCollisionSystemBulletParallel::ChCollisionSystemBulletParallel(ChParallelDataManager* dc,
                                                                 unsigned int max_objects,
                                                                 double scene_size)
    : data_manager(dc) {
  // btDefaultCollisionConstructionInfo conf_info(...); ***TODO***
  bt_collision_configuration = new btDefaultCollisionConfiguration();
  bt_dispatcher = new btCollisionDispatcher(bt_collision_configuration);

  //***OLD***

  btScalar sscene_size = (btScalar)scene_size;
  btVector3 worldAabbMin(-sscene_size, -sscene_size, -sscene_size);
  btVector3 worldAabbMax(sscene_size, sscene_size, sscene_size);
  bt_broadphase = new bt32BitAxisSweep3(
      worldAabbMin, worldAabbMax, max_objects, 0, true);  // true for disabling raycast accelerator

  //***NEW***
  // bt_broadphase = new btDbvtBroadphase();

  bt_collision_world = new btCollisionWorld(bt_dispatcher, bt_broadphase, bt_collision_configuration);

  // custom collision for sphere-sphere case ***OBSOLETE***
  // bt_dispatcher->registerCollisionCreateFunc(SPHERE_SHAPE_PROXYTYPE,SPHERE_SHAPE_PROXYTYPE,new
  // btSphereSphereCollisionAlgorithm::CreateFunc);

  // register custom collision for GIMPACT mesh case too
  btGImpactCollisionAlgorithm::registerAlgorithm(bt_dispatcher);

  counter = 0;
}

ChCollisionSystemBulletParallel::~ChCollisionSystemBulletParallel() {
  if (bt_collision_world)
    delete bt_collision_world;
  if (bt_broadphase)
    delete bt_broadphase;
  if (bt_dispatcher)
    delete bt_dispatcher;
  if (bt_collision_configuration)
    delete bt_collision_configuration;
}

void ChCollisionSystemBulletParallel::Clear(void) {
  int numManifolds = bt_collision_world->getDispatcher()->getNumManifolds();
  for (int i = 0; i < numManifolds; i++) {
    btPersistentManifold* contactManifold = bt_collision_world->getDispatcher()->getManifoldByIndexInternal(i);
    contactManifold->clearManifold();
  }
}

void ChCollisionSystemBulletParallel::Add(ChCollisionModel* model) {
  ChModelBullet* bmodel = static_cast<ChModelBullet*>(model);
  if (bmodel->GetBulletModel()->getCollisionShape()) {
    bmodel->SyncPosition();
    bmodel->GetBulletModel()->setCompanionId(counter);
    bt_collision_world->addCollisionObject(bmodel->GetBulletModel(), bmodel->GetFamilyGroup(), bmodel->GetFamilyMask());
    counter++;
    data_manager->num_rigid_shapes++;
  }
}

void ChCollisionSystemBulletParallel::Remove(ChCollisionModel* model) {
  ChModelBullet* bmodel = static_cast<ChModelBullet*>(model);
  if (bmodel->GetBulletModel()->getCollisionShape()) {
    bt_collision_world->removeCollisionObject(bmodel->GetBulletModel());
  }
}

void ChCollisionSystemBulletParallel::Run() {
  data_manager->system_timer.start("collision_broad");
  if (bt_collision_world) {
    bt_collision_world->performDiscreteCollisionDetection();
  }
  data_manager->system_timer.stop("collision_broad");
}
void ChCollisionSystemBulletParallel::ReportContacts(ChContactContainerBase* mcontactcontainer) {
  data_manager->system_timer.start("collision_narrow");
  data_manager->host_data.norm_rigid_rigid.clear();
  data_manager->host_data.cpta_rigid_rigid.clear();
  data_manager->host_data.cptb_rigid_rigid.clear();
  data_manager->host_data.dpth_rigid_rigid.clear();
  data_manager->host_data.bids_rigid_rigid.clear();
  data_manager->num_rigid_contacts = 0;
  // mcontactcontainer->BeginAddContact();
  ChCollisionInfo icontact;

  int numManifolds = bt_collision_world->getDispatcher()->getNumManifolds();
  for (int i = 0; i < numManifolds; i++) {
    btPersistentManifold* contactManifold = bt_collision_world->getDispatcher()->getManifoldByIndexInternal(i);
    btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
    btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
    contactManifold->refreshContactPoints(obA->getWorldTransform(), obB->getWorldTransform());

    icontact.modelA = (ChCollisionModel*)obA->getUserPointer();
    icontact.modelB = (ChCollisionModel*)obB->getUserPointer();

    double envelopeA = icontact.modelA->GetEnvelope();
    double envelopeB = icontact.modelB->GetEnvelope();

    double marginA = icontact.modelA->GetSafeMargin();
    double marginB = icontact.modelB->GetSafeMargin();

    bool activeA = ((ChBody*)(icontact.modelA->GetPhysicsItem()))->IsActive();
    bool activeB = ((ChBody*)(icontact.modelB->GetPhysicsItem()))->IsActive();

    if (activeA == 0 && activeB == 0) {
      continue;
    }

    // Execute custom broadphase callback, if any
    bool do_narrow_contactgeneration = true;
    if (this->broad_callback)
      do_narrow_contactgeneration = this->broad_callback->BroadCallback(icontact.modelA, icontact.modelB);

    if (do_narrow_contactgeneration) {
      int numContacts = contactManifold->getNumContacts();

      for (int j = 0; j < numContacts; j++) {
        btManifoldPoint& pt = contactManifold->getContactPoint(j);

        if (pt.getDistance() <
            marginA + marginB)  // to discard "too far" constraints (the Bullet engine also has its threshold)
        {
          btVector3 ptA = pt.getPositionWorldOnA();
          btVector3 ptB = pt.getPositionWorldOnB();

          icontact.vpA.Set(ptA.getX(), ptA.getY(), ptA.getZ());
          icontact.vpB.Set(ptB.getX(), ptB.getY(), ptB.getZ());

          icontact.vN.Set(-pt.m_normalWorldOnB.getX(), -pt.m_normalWorldOnB.getY(), -pt.m_normalWorldOnB.getZ());
          icontact.vN.Normalize();

          double ptdist = pt.getDistance();

          icontact.vpA = icontact.vpA - icontact.vN * envelopeA;
          icontact.vpB = icontact.vpB + icontact.vN * envelopeB;

          icontact.distance = ptdist + envelopeA + envelopeB;

          icontact.reaction_cache = pt.reactions_cache;

          // Execute some user custom callback, if any
          if (this->narrow_callback)
            this->narrow_callback->NarrowCallback(icontact);

          // Add to contact container
          // mcontactcontainer->AddContact(icontact);

          data_manager->host_data.norm_rigid_rigid.push_back(R3(icontact.vN.x, icontact.vN.y, icontact.vN.z));
          data_manager->host_data.cpta_rigid_rigid.push_back(R3(icontact.vpA.x, icontact.vpA.y, icontact.vpA.z));
          data_manager->host_data.cptb_rigid_rigid.push_back(R3(icontact.vpB.x, icontact.vpB.y, icontact.vpB.z));
          data_manager->host_data.dpth_rigid_rigid.push_back(icontact.distance);
          data_manager->host_data.erad_rigid_rigid.push_back(edge_radius);
          data_manager->host_data.bids_rigid_rigid.push_back(I2(obA->getCompanionId(), obB->getCompanionId()));
          data_manager->num_rigid_contacts++;
        }
      }
    }
    // you can un-comment out this line, and then all points are removed
    // contactManifold->clearManifold();
  }

  // mcontactcontainer->EndAddContact();
  data_manager->system_timer.stop("collision_narrow");
}
}  // END_OF_NAMESPACE____
}  // END_OF_NAMESPACE____
<|endoftext|>


<commit_before>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// Single cell view simulation worker
//==============================================================================

#include "cellmlfileruntime.h"
#include "cliutils.h"
#include "coredaesolver.h"
#include "corenlasolver.h"
#include "coreodesolver.h"
#include "singlecellviewsimulation.h"
#include "singlecellviewsimulationworker.h"

//==============================================================================

#include <QElapsedTimer>
#include <QMutex>
#include <QThread>

//==============================================================================

namespace OpenCOR {
namespace SingleCellView {

//==============================================================================

SingleCellViewSimulationWorker::SingleCellViewSimulationWorker(const SolverInterfaces &pSolverInterfaces,
                                                               CellMLSupport::CellmlFileRuntime *pRuntime,
                                                               SingleCellViewSimulation *pSimulation,
                                                               SingleCellViewSimulationWorker **pSelf) :
    mSolverInterfaces(pSolverInterfaces),
    mRuntime(pRuntime),
    mSimulation(pSimulation),
    mCurrentPoint(0.0),
    mProgress(0.0),
    mPaused(false),
    mStopped(false),
    mReset(false),
    mError(false),
    mSelf(pSelf)
{
    // Create our thread

    mThread = new QThread();

    // Move ourselves to our thread

    moveToThread(mThread);

    // Create a few connections

    connect(mThread, SIGNAL(started()),
            this, SLOT(started()));

    connect(this, SIGNAL(finished(const qint64 &)),
            mThread, SLOT(quit()));

    connect(mThread, SIGNAL(finished()),
            mThread, SLOT(deleteLater()));
    connect(mThread, SIGNAL(finished()),
            this, SLOT(deleteLater()));
}

//==============================================================================

bool SingleCellViewSimulationWorker::isRunning() const
{
    // Return whether our thread is running

    return mThread->isRunning() && !mPaused;
}

//==============================================================================

bool SingleCellViewSimulationWorker::isPaused() const
{
    // Return whether our thread is paused

    return mThread->isRunning() && mPaused;
}

//==============================================================================

double SingleCellViewSimulationWorker::currentPoint() const
{
    // Return our progress

    return mThread->isRunning()?
               mCurrentPoint:
               mSimulation->data()->startingPoint();
}

//==============================================================================

double SingleCellViewSimulationWorker::progress() const
{
    // Return our progress

    return mThread->isRunning()?mProgress:0.0;
}

//==============================================================================

bool SingleCellViewSimulationWorker::run()
{
    // Start our thread, but only if we are not already running

    if (!mThread->isRunning()) {
        mThread->start();

        return true;
    } else {
        return false;
    }
}

//==============================================================================

bool SingleCellViewSimulationWorker::pause()
{
    // Pause ourselves, but only if we are currently running

    if (isRunning()) {
        // Ask ourselves to pause

        mPaused = true;

        return true;
    } else {
        return false;
    }
}

//==============================================================================

bool SingleCellViewSimulationWorker::resume()
{
    // Resume ourselves, but only if are currently paused

    if (isPaused()) {
        // Ask ourselves to resume

        mPausedCondition.wakeOne();

        return true;
    } else {
        return false;
    }
}

//==============================================================================

bool SingleCellViewSimulationWorker::stop()
{
    // Check that we are either running or paused

    if (isRunning() || isPaused()) {
        // Ask our thread to stop

        mStopped = true;

        // Resume our thread, if needed

        if (isPaused())
            mPausedCondition.wakeOne();

        // Ask our thread to quit and wait for it to do so

        mThread->quit();
        mThread->wait();

        return true;
    } else {
        return false;
    }
}

//==============================================================================

bool SingleCellViewSimulationWorker::reset()
{
    // Check that we are either running or paused

    if (isRunning() || isPaused()) {
        // Ask ourselves to reinitialise our solver

        mReset = true;

        return true;
    } else {
        return false;
    }
}

//==============================================================================

void SingleCellViewSimulationWorker::started()
{
    // Let people know that we are running

    emit running(false);

    // Reset our progress

    mProgress = 0.0;

    // Set up our ODE/DAE solver

    CoreSolver::CoreVoiSolver *voiSolver = 0;
    CoreSolver::CoreOdeSolver *odeSolver = 0;
    CoreSolver::CoreDaeSolver *daeSolver = 0;

    if (mRuntime->needOdeSolver()) {
        foreach (SolverInterface *solverInterface, mSolverInterfaces)
            if (!solverInterface->solverName().compare(mSimulation->data()->odeSolverName())) {
                // The requested ODE solver was found, so retrieve an instance
                // of it

                voiSolver = odeSolver = static_cast<CoreSolver::CoreOdeSolver *>(solverInterface->solverInstance());

                break;
            }
    } else {
        foreach (SolverInterface *solverInterface, mSolverInterfaces)
            if (!solverInterface->solverName().compare("IDA")) {
                // The requested DAE solver was found, so retrieve an instance
                // of it

                voiSolver = daeSolver = static_cast<CoreSolver::CoreDaeSolver *>(solverInterface->solverInstance());

                break;
            }
    }

    // Make sure that we have found our ODE/DAE solver
    // Note #1: this should never happen, but we never know, so...
    // Note #2: see the end of this method about we do before returning...

    if (!voiSolver) {
        if (mRuntime->needOdeSolver())
            emitError(tr("the ODE solver could not be found"));
        else
            emitError(tr("the DAE solver could not be found"));

        *mSelf = 0;

        emit finished(-1);

        return;
    }

    // Set up our NLA solver, if needed

    CoreSolver::CoreNlaSolver *nlaSolver = 0;

    if (mRuntime->needNlaSolver()) {
        foreach (SolverInterface *solverInterface, mSolverInterfaces)
            if (!solverInterface->solverName().compare(mSimulation->data()->nlaSolverName())) {
                // The requested NLA solver was found, so retrieve an instance
                // of it

                nlaSolver = static_cast<CoreSolver::CoreNlaSolver *>(solverInterface->solverInstance());

                // Keep track of our NLA solver, so that doNonLinearSolve() can
                // work as expected

                CoreSolver::setNlaSolver(mRuntime->address(), nlaSolver);

                break;
            }

        // Make sure that we have found our NLA solver
        // Note #1: this should never happen, but we never know, so...
        // Note #2: see the end of this method about we do before returning...

        if (!nlaSolver) {
            emitError(tr("the NLA solver could not be found"));

            delete voiSolver;

            *mSelf = 0;

            emit finished(-1);

            return;
        }
    }

    // Keep track of any error that might be reported by any of our solvers

    mStopped = false;
    mError = false;

    if (odeSolver)
        connect(odeSolver, SIGNAL(error(const QString &)),
                this, SLOT(emitError(const QString &)));
    else
        connect(daeSolver, SIGNAL(error(const QString &)),
                this, SLOT(emitError(const QString &)));

    if (nlaSolver)
        connect(nlaSolver, SIGNAL(error(const QString &)),
                this, SLOT(emitError(const QString &)));

    // Retrieve our simulation properties

    double startingPoint = mSimulation->data()->startingPoint();
    double endingPoint   = mSimulation->data()->endingPoint();
    double pointInterval = mSimulation->data()->pointInterval();

    bool increasingPoints = endingPoint > startingPoint;
    const double oneOverPointsRange = 1.0/(endingPoint-startingPoint);
    quint64 pointCounter = 0;

    mCurrentPoint = startingPoint;

    // Initialise our ODE/DAE solver

    if (odeSolver) {
        odeSolver->setProperties(mSimulation->data()->odeSolverProperties());

        odeSolver->initialize(mCurrentPoint,
                              mRuntime->statesCount(),
                              mSimulation->data()->constants(),
                              mSimulation->data()->rates(),
                              mSimulation->data()->states(),
                              mSimulation->data()->algebraic(),
                              mRuntime->computeOdeRates());
    } else {
        daeSolver->setProperties(mSimulation->data()->daeSolverProperties());

        daeSolver->initialize(mCurrentPoint, endingPoint,
                              mRuntime->statesCount(),
                              mRuntime->condVarCount(),
                              mSimulation->data()->constants(),
                              mSimulation->data()->rates(),
                              mSimulation->data()->states(),
                              mSimulation->data()->algebraic(),
                              mSimulation->data()->condVar(),
                              mRuntime->computeDaeEssentialVariables(),
                              mRuntime->computeDaeResiduals(),
                              mRuntime->computeDaeRootInformation(),
                              mRuntime->computeDaeStateInformation());
    }

    // Initialise our NLA solver

    if (nlaSolver)
        nlaSolver->setProperties(mSimulation->data()->nlaSolverProperties());

    // Now, we are ready to compute our model, but only if no error has occurred
    // so far

    qint64 elapsedTime;

    if (!mError) {
        // Start our timer

        QElapsedTimer timer;

        elapsedTime = 0;

        timer.start();

        // Add our first point after making sure that all the variables are up
        // to date

        mSimulation->data()->recomputeVariables(mCurrentPoint);

        mSimulation->results()->addPoint(mCurrentPoint);

        // Our main work loop
        // Note: for performance reasons, it is essential that the following
        //       loop doesn't emit any signal, be it directly or indirectly,
        //       unless it is to let people know that we are pausing or running.
        //       Indeed, the signal/slot mechanism adds a certain level of
        //       overhead and, here, we want things to be as fast as possible,
        //       so...

        QMutex pausedMutex;

        while ((mCurrentPoint != endingPoint) && !mStopped) {
            // Determine our next point and compute our model up to it

            ++pointCounter;

            voiSolver->solve(mCurrentPoint,
                             increasingPoints?
                                 qMin(endingPoint, startingPoint+pointCounter*pointInterval):
                                 qMax(endingPoint, startingPoint+pointCounter*pointInterval));

            // Make sure that no error occurred

            if (mError)
                break;

            // Update our progress

            mProgress = (mCurrentPoint-startingPoint)*oneOverPointsRange;

            // Add our new point after making sure that all the variables are up
            // to date

            mSimulation->data()->recomputeVariables(mCurrentPoint);

            mSimulation->results()->addPoint(mCurrentPoint);

            // Delay things a bit, if (really) needed

            if (mSimulation->delay() && !mStopped)
                Core::doNothing(100*mSimulation->delay());

            // Pause ourselves, if (really) needed

            if (mPaused && !mStopped) {
                // We should be paused, so stop our timer

                elapsedTime += timer.elapsed();

                // Let people know that we are paused

                emit paused();

                // Actually pause ourselves

                pausedMutex.lock();
                    mPausedCondition.wait(&pausedMutex);
                pausedMutex.unlock();

                // We are not paused anymore

                mPaused = false;

                // Let people know that we are running again

                emit running(true);

                // Restart our timer

                timer.restart();
            }

            // Reinitialise our solver, if (really) needed

            if (mReset && !mStopped) {
                if (odeSolver)
                    odeSolver->initialize(mCurrentPoint,
                                          mRuntime->statesCount(),
                                          mSimulation->data()->constants(),
                                          mSimulation->data()->rates(),
                                          mSimulation->data()->states(),
                                          mSimulation->data()->algebraic(),
                                          mRuntime->computeOdeRates());
                else
                    daeSolver->initialize(mCurrentPoint, endingPoint,
                                          mRuntime->statesCount(),
                                          mRuntime->condVarCount(),
                                          mSimulation->data()->constants(),
                                          mSimulation->data()->rates(),
                                          mSimulation->data()->states(),
                                          mSimulation->data()->algebraic(),
                                          mSimulation->data()->condVar(),
                                          mRuntime->computeDaeEssentialVariables(),
                                          mRuntime->computeDaeResiduals(),
                                          mRuntime->computeDaeRootInformation(),
                                          mRuntime->computeDaeStateInformation());

                mReset = false;
            }
        }

        // Retrieve the total elapsed time, should no error have occurred

        if (mError)
            // An error occurred, so...

            elapsedTime = -1;
            // Note: we use -1 as a way to indicate that something went wrong...
        else
            elapsedTime += timer.elapsed();
    } else {
        // An error occurred, so...

        elapsedTime = -1;
        // Note: we use -1 as a way to indicate that something went wrong...
    }

    // Delete our solver(s)

    delete voiSolver;

    if (nlaSolver) {
        delete nlaSolver;

        CoreSolver::unsetNlaSolver(mRuntime->address());
    }

    // Reset our simulation owner's knowledge of us
    // Note: if we were to do it the Qt way, our simulation owner would have a
    //       slot for our finished() signal, but we want it to know as quickly
    //       as possible that we are done, so...

    *mSelf = 0;

    // Let people know that we are done and give them the elapsed time

    emit finished(elapsedTime);
}

//==============================================================================

void SingleCellViewSimulationWorker::emitError(const QString &pMessage)
{
    // A solver error occurred, so keep track of it and let people know about it

    mError = true;

    emit error(pMessage);
}

//==============================================================================

}   // namespace SingleCellView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some minor cleaning up [ci skip].<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// Single cell view simulation worker
//==============================================================================

#include "cellmlfileruntime.h"
#include "cliutils.h"
#include "coredaesolver.h"
#include "corenlasolver.h"
#include "coreodesolver.h"
#include "singlecellviewsimulation.h"
#include "singlecellviewsimulationworker.h"

//==============================================================================

#include <QElapsedTimer>
#include <QMutex>
#include <QThread>

//==============================================================================

namespace OpenCOR {
namespace SingleCellView {

//==============================================================================

SingleCellViewSimulationWorker::SingleCellViewSimulationWorker(const SolverInterfaces &pSolverInterfaces,
                                                               CellMLSupport::CellmlFileRuntime *pRuntime,
                                                               SingleCellViewSimulation *pSimulation,
                                                               SingleCellViewSimulationWorker **pSelf) :
    mSolverInterfaces(pSolverInterfaces),
    mRuntime(pRuntime),
    mSimulation(pSimulation),
    mCurrentPoint(0.0),
    mProgress(0.0),
    mPaused(false),
    mStopped(false),
    mReset(false),
    mError(false),
    mSelf(pSelf)
{
    // Create our thread

    mThread = new QThread();

    // Move ourselves to our thread

    moveToThread(mThread);

    // Create a few connections

    connect(mThread, SIGNAL(started()),
            this, SLOT(started()));

    connect(this, SIGNAL(finished(const qint64 &)),
            mThread, SLOT(quit()));

    connect(mThread, SIGNAL(finished()),
            mThread, SLOT(deleteLater()));
    connect(mThread, SIGNAL(finished()),
            this, SLOT(deleteLater()));
}

//==============================================================================

bool SingleCellViewSimulationWorker::isRunning() const
{
    // Return whether our thread is running

    return mThread->isRunning() && !mPaused;
}

//==============================================================================

bool SingleCellViewSimulationWorker::isPaused() const
{
    // Return whether our thread is paused

    return mThread->isRunning() && mPaused;
}

//==============================================================================

double SingleCellViewSimulationWorker::currentPoint() const
{
    // Return our progress

    return mThread->isRunning()?
               mCurrentPoint:
               mSimulation->data()->startingPoint();
}

//==============================================================================

double SingleCellViewSimulationWorker::progress() const
{
    // Return our progress

    return mThread->isRunning()?mProgress:0.0;
}

//==============================================================================

bool SingleCellViewSimulationWorker::run()
{
    // Start our thread, but only if we are not already running

    if (!mThread->isRunning()) {
        mThread->start();

        return true;
    } else {
        return false;
    }
}

//==============================================================================

bool SingleCellViewSimulationWorker::pause()
{
    // Pause ourselves, but only if we are currently running

    if (isRunning()) {
        // Ask ourselves to pause

        mPaused = true;

        return true;
    } else {
        return false;
    }
}

//==============================================================================

bool SingleCellViewSimulationWorker::resume()
{
    // Resume ourselves, but only if are currently paused

    if (isPaused()) {
        // Ask ourselves to resume

        mPausedCondition.wakeOne();

        return true;
    } else {
        return false;
    }
}

//==============================================================================

bool SingleCellViewSimulationWorker::stop()
{
    // Check that we are either running or paused

    if (isRunning() || isPaused()) {
        // Ask our thread to stop

        mStopped = true;

        // Resume our thread, if needed

        if (isPaused())
            mPausedCondition.wakeOne();

        // Ask our thread to quit and wait for it to do so

        mThread->quit();
        mThread->wait();

        return true;
    } else {
        return false;
    }
}

//==============================================================================

bool SingleCellViewSimulationWorker::reset()
{
    // Check that we are either running or paused

    if (isRunning() || isPaused()) {
        // Ask ourselves to reinitialise our solver

        mReset = true;

        return true;
    } else {
        return false;
    }
}

//==============================================================================

void SingleCellViewSimulationWorker::started()
{
    // Let people know that we are running

    emit running(false);

    // Reset our progress

    mProgress = 0.0;

    // Set up our ODE/DAE solver

    CoreSolver::CoreVoiSolver *voiSolver = 0;
    CoreSolver::CoreOdeSolver *odeSolver = 0;
    CoreSolver::CoreDaeSolver *daeSolver = 0;

    if (mRuntime->needOdeSolver()) {
        foreach (SolverInterface *solverInterface, mSolverInterfaces)
            if (!solverInterface->solverName().compare(mSimulation->data()->odeSolverName())) {
                // The requested ODE solver was found, so retrieve an instance
                // of it

                voiSolver = odeSolver = static_cast<CoreSolver::CoreOdeSolver *>(solverInterface->solverInstance());

                break;
            }
    } else {
        foreach (SolverInterface *solverInterface, mSolverInterfaces)
            if (!solverInterface->solverName().compare("IDA")) {
                // The requested DAE solver was found, so retrieve an instance
                // of it

                voiSolver = daeSolver = static_cast<CoreSolver::CoreDaeSolver *>(solverInterface->solverInstance());

                break;
            }
    }

    // Make sure that we have found our ODE/DAE solver
    // Note: this should never happen, but we never know, so...

    if (!voiSolver) {
        if (mRuntime->needOdeSolver())
            emitError(tr("the ODE solver could not be found"));
        else
            emitError(tr("the DAE solver could not be found"));

        *mSelf = 0;

        emit finished(-1);

        return;
    }

    // Set up our NLA solver, if needed

    CoreSolver::CoreNlaSolver *nlaSolver = 0;

    if (mRuntime->needNlaSolver()) {
        foreach (SolverInterface *solverInterface, mSolverInterfaces)
            if (!solverInterface->solverName().compare(mSimulation->data()->nlaSolverName())) {
                // The requested NLA solver was found, so retrieve an instance
                // of it

                nlaSolver = static_cast<CoreSolver::CoreNlaSolver *>(solverInterface->solverInstance());

                // Keep track of our NLA solver, so that doNonLinearSolve() can
                // work as expected

                CoreSolver::setNlaSolver(mRuntime->address(), nlaSolver);

                break;
            }

        // Make sure that we have found our NLA solver
        // Note #1: this should never happen, but we never know, so...
        // Note #2: see the end of this method about we do before returning...

        if (!nlaSolver) {
            emitError(tr("the NLA solver could not be found"));

            delete voiSolver;

            *mSelf = 0;

            emit finished(-1);

            return;
        }
    }

    // Keep track of any error that might be reported by any of our solvers

    mStopped = false;
    mError = false;

    if (odeSolver)
        connect(odeSolver, SIGNAL(error(const QString &)),
                this, SLOT(emitError(const QString &)));
    else
        connect(daeSolver, SIGNAL(error(const QString &)),
                this, SLOT(emitError(const QString &)));

    if (nlaSolver)
        connect(nlaSolver, SIGNAL(error(const QString &)),
                this, SLOT(emitError(const QString &)));

    // Retrieve our simulation properties

    double startingPoint = mSimulation->data()->startingPoint();
    double endingPoint   = mSimulation->data()->endingPoint();
    double pointInterval = mSimulation->data()->pointInterval();

    bool increasingPoints = endingPoint > startingPoint;
    const double oneOverPointsRange = 1.0/(endingPoint-startingPoint);
    quint64 pointCounter = 0;

    mCurrentPoint = startingPoint;

    // Initialise our ODE/DAE solver

    if (odeSolver) {
        odeSolver->setProperties(mSimulation->data()->odeSolverProperties());

        odeSolver->initialize(mCurrentPoint,
                              mRuntime->statesCount(),
                              mSimulation->data()->constants(),
                              mSimulation->data()->rates(),
                              mSimulation->data()->states(),
                              mSimulation->data()->algebraic(),
                              mRuntime->computeOdeRates());
    } else {
        daeSolver->setProperties(mSimulation->data()->daeSolverProperties());

        daeSolver->initialize(mCurrentPoint, endingPoint,
                              mRuntime->statesCount(),
                              mRuntime->condVarCount(),
                              mSimulation->data()->constants(),
                              mSimulation->data()->rates(),
                              mSimulation->data()->states(),
                              mSimulation->data()->algebraic(),
                              mSimulation->data()->condVar(),
                              mRuntime->computeDaeEssentialVariables(),
                              mRuntime->computeDaeResiduals(),
                              mRuntime->computeDaeRootInformation(),
                              mRuntime->computeDaeStateInformation());
    }

    // Initialise our NLA solver

    if (nlaSolver)
        nlaSolver->setProperties(mSimulation->data()->nlaSolverProperties());

    // Now, we are ready to compute our model, but only if no error has occurred
    // so far

    qint64 elapsedTime;

    if (!mError) {
        // Start our timer

        QElapsedTimer timer;

        elapsedTime = 0;

        timer.start();

        // Add our first point after making sure that all the variables are up
        // to date

        mSimulation->data()->recomputeVariables(mCurrentPoint);

        mSimulation->results()->addPoint(mCurrentPoint);

        // Our main work loop
        // Note: for performance reasons, it is essential that the following
        //       loop doesn't emit any signal, be it directly or indirectly,
        //       unless it is to let people know that we are pausing or running.
        //       Indeed, the signal/slot mechanism adds a certain level of
        //       overhead and, here, we want things to be as fast as possible,
        //       so...

        QMutex pausedMutex;

        while ((mCurrentPoint != endingPoint) && !mStopped) {
            // Determine our next point and compute our model up to it

            ++pointCounter;

            voiSolver->solve(mCurrentPoint,
                             increasingPoints?
                                 qMin(endingPoint, startingPoint+pointCounter*pointInterval):
                                 qMax(endingPoint, startingPoint+pointCounter*pointInterval));

            // Make sure that no error occurred

            if (mError)
                break;

            // Update our progress

            mProgress = (mCurrentPoint-startingPoint)*oneOverPointsRange;

            // Add our new point after making sure that all the variables are up
            // to date

            mSimulation->data()->recomputeVariables(mCurrentPoint);

            mSimulation->results()->addPoint(mCurrentPoint);

            // Delay things a bit, if (really) needed

            if (mSimulation->delay() && !mStopped)
                Core::doNothing(100*mSimulation->delay());

            // Pause ourselves, if (really) needed

            if (mPaused && !mStopped) {
                // We should be paused, so stop our timer

                elapsedTime += timer.elapsed();

                // Let people know that we are paused

                emit paused();

                // Actually pause ourselves

                pausedMutex.lock();
                    mPausedCondition.wait(&pausedMutex);
                pausedMutex.unlock();

                // We are not paused anymore

                mPaused = false;

                // Let people know that we are running again

                emit running(true);

                // Restart our timer

                timer.restart();
            }

            // Reinitialise our solver, if (really) needed

            if (mReset && !mStopped) {
                if (odeSolver)
                    odeSolver->initialize(mCurrentPoint,
                                          mRuntime->statesCount(),
                                          mSimulation->data()->constants(),
                                          mSimulation->data()->rates(),
                                          mSimulation->data()->states(),
                                          mSimulation->data()->algebraic(),
                                          mRuntime->computeOdeRates());
                else
                    daeSolver->initialize(mCurrentPoint, endingPoint,
                                          mRuntime->statesCount(),
                                          mRuntime->condVarCount(),
                                          mSimulation->data()->constants(),
                                          mSimulation->data()->rates(),
                                          mSimulation->data()->states(),
                                          mSimulation->data()->algebraic(),
                                          mSimulation->data()->condVar(),
                                          mRuntime->computeDaeEssentialVariables(),
                                          mRuntime->computeDaeResiduals(),
                                          mRuntime->computeDaeRootInformation(),
                                          mRuntime->computeDaeStateInformation());

                mReset = false;
            }
        }

        // Retrieve the total elapsed time, should no error have occurred

        if (mError)
            // An error occurred, so...

            elapsedTime = -1;
            // Note: we use -1 as a way to indicate that something went wrong...
        else
            elapsedTime += timer.elapsed();
    } else {
        // An error occurred, so...

        elapsedTime = -1;
        // Note: we use -1 as a way to indicate that something went wrong...
    }

    // Delete our solver(s)

    delete voiSolver;

    if (nlaSolver) {
        delete nlaSolver;

        CoreSolver::unsetNlaSolver(mRuntime->address());
    }

    // Reset our simulation owner's knowledge of us
    // Note: if we were to do it the Qt way, our simulation owner would have a
    //       slot for our finished() signal, but we want it to know as quickly
    //       as possible that we are done, so...

    *mSelf = 0;

    // Let people know that we are done and give them the elapsed time

    emit finished(elapsedTime);
}

//==============================================================================

void SingleCellViewSimulationWorker::emitError(const QString &pMessage)
{
    // A solver error occurred, so keep track of it and let people know about it

    mError = true;

    emit error(pMessage);
}

//==============================================================================

}   // namespace SingleCellView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>#include <vtkVersion.h>
#include <vtkImageData.h>
#include <vtkSmartPointer.h>
#include <vtkImageImport.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkXMLImageDataWriter.h>

int main(int, char *[])
{
  // Create a c-style image
  const int width = 4;
  const int height = 4;

  unsigned char cImage[width*height];
  unsigned char value = 0;
  for(unsigned int row = 0; row < height; ++row)
  {
    for(unsigned int col = 0; col < width; ++col)
    {
      cImage[row * width + col] = value;
      value += 10;
    }
  }

  // Convert the c-style image to a vtkImageData
  vtkSmartPointer<vtkImageImport> imageImport =
    vtkSmartPointer<vtkImageImport>::New();
  imageImport->SetDataSpacing(1, 1, 1);
  imageImport->SetDataOrigin(0, 0, 0);
  imageImport->SetWholeExtent(0, width-1, 0, height-1, 0, 0);
  imageImport->SetDataExtentToWholeExtent();
  imageImport->SetDataScalarTypeToUnsignedChar();
  imageImport->SetNumberOfScalarComponents(1);
  imageImport->SetImportVoidPointer(cImage);
  imageImport->Update();

  // Create an actor
  vtkSmartPointer<vtkImageActor> actor =
    vtkSmartPointer<vtkImageActor>::New();
#if VTK_MAJOR_VERSION <= 5
  actor->SetInput(imageImport->GetOutput());
#else
  actor->SetInputData(imageImport->GetOutput());
#endif

  // Setup renderer
  vtkSmartPointer<vtkRenderer> renderer =
    vtkSmartPointer<vtkRenderer>::New();
  renderer->AddActor(actor);
  renderer->ResetCamera();

  // Setup render window
  vtkSmartPointer<vtkRenderWindow> renderWindow =
    vtkSmartPointer<vtkRenderWindow>::New();
  renderWindow->AddRenderer(renderer);

  // Setup render window interactor
  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
    vtkSmartPointer<vtkRenderWindowInteractor>::New();
  vtkSmartPointer<vtkInteractorStyleImage> style =
    vtkSmartPointer<vtkInteractorStyleImage>::New();

  renderWindowInteractor->SetInteractorStyle(style);

  // Render and start interaction
  renderWindowInteractor->SetRenderWindow(renderWindow);
  renderWindowInteractor->Initialize();

  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}
<commit_msg>ENH: Removed old verison code<commit_after>#include <vtkSmartPointer.h>
#include <vtkImageImport.h>

#include <vtkImageData.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkInteractorStyleImage.h>
#include <vtkXMLImageDataWriter.h>

int main(int, char *[])
{
  // Create a c-style image
  const int width = 4;
  const int height = 4;

  unsigned char cImage[width*height];
  unsigned char value = 0;
  for(unsigned int row = 0; row < height; ++row)
  {
    for(unsigned int col = 0; col < width; ++col)
    {
      cImage[row * width + col] = value;
      value += 10;
    }
  }

  // Convert the c-style image to a vtkImageData
  vtkSmartPointer<vtkImageImport> imageImport =
    vtkSmartPointer<vtkImageImport>::New();
  imageImport->SetDataSpacing(1, 1, 1);
  imageImport->SetDataOrigin(0, 0, 0);
  imageImport->SetWholeExtent(0, width-1, 0, height-1, 0, 0);
  imageImport->SetDataExtentToWholeExtent();
  imageImport->SetDataScalarTypeToUnsignedChar();
  imageImport->SetNumberOfScalarComponents(1);
  imageImport->SetImportVoidPointer(cImage);
  imageImport->Update();

  // Create an actor
  vtkSmartPointer<vtkImageActor> actor =
    vtkSmartPointer<vtkImageActor>::New();
  actor->SetInputData(imageImport->GetOutput());

  // Setup renderer
  vtkSmartPointer<vtkRenderer> renderer =
    vtkSmartPointer<vtkRenderer>::New();
  renderer->AddActor(actor);
  renderer->ResetCamera();

  // Setup render window
  vtkSmartPointer<vtkRenderWindow> renderWindow =
    vtkSmartPointer<vtkRenderWindow>::New();
  renderWindow->AddRenderer(renderer);

  // Setup render window interactor
  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
    vtkSmartPointer<vtkRenderWindowInteractor>::New();
  vtkSmartPointer<vtkInteractorStyleImage> style =
    vtkSmartPointer<vtkInteractorStyleImage>::New();

  renderWindowInteractor->SetInteractorStyle(style);

  // Render and start interaction
  renderWindowInteractor->SetRenderWindow(renderWindow);
  renderWindowInteractor->Initialize();

  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QTextDocument>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDir>

#include <QtDeclarative/qmlengine.h>
#include <QtDeclarative/qmlcomponent.h>
#include <private/qmlgraphicsborderimage_p.h>
#include <private/qmlgraphicsimagebase_p.h>
#include <private/qmlgraphicsscalegrid_p_p.h>
#include <private/qmlgraphicsloader_p.h>
#include <QtDeclarative/qmlcontext.h>

#include "../shared/testhttpserver.h"

#define SERVER_PORT 14445
#define SERVER_ADDR "http://127.0.0.1:14445"

#define TRY_WAIT(expr) \
    do { \
        for (int ii = 0; ii < 6; ++ii) { \
            if ((expr)) break; \
            QTest::qWait(50); \
        } \
        QVERIFY((expr)); \
    } while (false)

class tst_qmlgraphicsborderimage : public QObject

{
    Q_OBJECT
public:
    tst_qmlgraphicsborderimage();

private slots:
    void noSource();
    void imageSource();
    void imageSource_data();
    void clearSource();
    void resized();
    void smooth();
    void tileModes();
    void sciSource();
    void sciSource_data();
    void invalidSciFile();
    void pendingRemoteRequest();
    void pendingRemoteRequest_data();

private:
    QmlEngine engine;
};

tst_qmlgraphicsborderimage::tst_qmlgraphicsborderimage()
{
}

void tst_qmlgraphicsborderimage::noSource()
{
    QString componentStr = "import Qt 4.6\nBorderImage { source: \"\" }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QCOMPARE(obj->source(), QUrl());
    QCOMPARE(obj->width(), 0.);
    QCOMPARE(obj->height(), 0.);
    QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Stretch);
    QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Stretch);

    delete obj;
}

void tst_qmlgraphicsborderimage::imageSource()
{
    QFETCH(QString, source);
    QFETCH(bool, valid);

    bool remote = source.startsWith("http");
    TestHTTPServer *server = 0;
    if (remote) {
        server = new TestHTTPServer(SERVER_PORT);
        QVERIFY(server->isValid());
        server->serveDirectory(SRCDIR "/data");
    }

    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" + source + "\" }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);

    if (remote)
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Loading);

    QCOMPARE(obj->source(), remote ? source : QUrl::fromLocalFile(source));

    if (valid) {
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Ready);
        QCOMPARE(obj->width(), 120.);
        QCOMPARE(obj->height(), 120.);
        QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Stretch);
        QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Stretch);
    } else {
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Error);
    }

    delete obj;
    delete server;
}

void tst_qmlgraphicsborderimage::clearSource()
{
    QString componentStr = "import Qt 4.6\nBorderImage { source: srcImage }";
    QmlContext *ctxt = engine.rootContext();
    ctxt->setContextProperty("srcImage", SRCDIR "/data/colors.png");
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QVERIFY(obj->status() == QmlGraphicsBorderImage::Ready);
    QCOMPARE(obj->width(), 120.);
    QCOMPARE(obj->height(), 120.);

    ctxt->setContextProperty("srcImage", "");
    QVERIFY(obj->source().isEmpty());
    QVERIFY(obj->status() == QmlGraphicsBorderImage::Null);
    QCOMPARE(obj->width(), 0.);
    QCOMPARE(obj->height(), 0.);
}

void tst_qmlgraphicsborderimage::imageSource_data()
{
    QTest::addColumn<QString>("source");
    QTest::addColumn<bool>("valid");

    QTest::newRow("local") << SRCDIR "/data/colors.png" << true;
    QTest::newRow("local not found") << SRCDIR "/data/no-such-file.png" << false;
    QTest::newRow("remote") << SERVER_ADDR "/colors.png" << true;
    QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << false;
}

void tst_qmlgraphicsborderimage::resized()
{
    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; width: 300; height: 300 }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QCOMPARE(obj->width(), 300.);
    QCOMPARE(obj->height(), 300.);
    QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Stretch);
    QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Stretch);

    delete obj;
}

void tst_qmlgraphicsborderimage::smooth()
{
    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; smooth: true; width: 300; height: 300 }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QCOMPARE(obj->width(), 300.);
    QCOMPARE(obj->height(), 300.);
    QCOMPARE(obj->smooth(), true);
    QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Stretch);
    QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Stretch);

    delete obj;
}

void tst_qmlgraphicsborderimage::tileModes()
{
    {
        QString componentStr = "import Qt 4.6\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; width: 100; height: 300; horizontalTileMode: BorderImage.Repeat; verticalTileMode: BorderImage.Repeat }";
        QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
        QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
        QVERIFY(obj != 0);
        QCOMPARE(obj->width(), 100.);
        QCOMPARE(obj->height(), 300.);
        QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Repeat);
        QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Repeat);

        delete obj;
    }
    {
        QString componentStr = "import Qt 4.6\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; width: 300; height: 150; horizontalTileMode: BorderImage.Round; verticalTileMode: BorderImage.Round }";
        QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
        QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
        QVERIFY(obj != 0);
        QCOMPARE(obj->width(), 300.);
        QCOMPARE(obj->height(), 150.);
        QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Round);
        QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Round);

        delete obj;
    }
}

void tst_qmlgraphicsborderimage::sciSource()
{
    QFETCH(QString, source);
    QFETCH(bool, valid);

    bool remote = source.startsWith("http");
    TestHTTPServer *server = 0;
    if (remote) {
        server = new TestHTTPServer(SERVER_PORT);
        QVERIFY(server->isValid());
        server->serveDirectory(SRCDIR "/data");
    }

    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" + source + "\"; width: 300; height: 300 }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);

    if (remote)
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Loading);

    QCOMPARE(obj->source(), remote ? source : QUrl::fromLocalFile(source));
    QCOMPARE(obj->width(), 300.);
    QCOMPARE(obj->height(), 300.);

    if (valid) {
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Ready);
        QCOMPARE(obj->border()->left(), 10);
        QCOMPARE(obj->border()->top(), 20);
        QCOMPARE(obj->border()->right(), 30);
        QCOMPARE(obj->border()->bottom(), 40);
        QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Round);
        QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Repeat);
    } else {
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Error);
    }

    delete obj;
    delete server;
}

void tst_qmlgraphicsborderimage::sciSource_data()
{
    QTest::addColumn<QString>("source");
    QTest::addColumn<bool>("valid");

    QTest::newRow("local") << SRCDIR "/data/colors-round.sci" << true;
    QTest::newRow("local not found") << SRCDIR "/data/no-such-file.sci" << false;
    QTest::newRow("remote") << SERVER_ADDR "/colors-round.sci" << true;
    QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.sci" << false;
}

void tst_qmlgraphicsborderimage::invalidSciFile()
{
    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" SRCDIR "/data/invalid.sci\"; width: 300; height: 300 }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QCOMPARE(obj->width(), 300.);
    QCOMPARE(obj->height(), 300.);
    QCOMPARE(obj->status(), QmlGraphicsImageBase::Error);
    QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Stretch);
    QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Stretch);

    delete obj;
}

void tst_qmlgraphicsborderimage::pendingRemoteRequest()
{
    QFETCH(QString, source);

    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" + source + "\" }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QCOMPARE(obj->status(), QmlGraphicsBorderImage::Loading);

    // verify no crash
    // This will cause a delayed "QThread: Destroyed while thread is still running" warning
    delete obj;
    QTest::qWait(50);
}

void tst_qmlgraphicsborderimage::pendingRemoteRequest_data()
{
    QTest::addColumn<QString>("source");

    QTest::newRow("png file") << "http://no-such-qt-server-like-this/none.png";
    QTest::newRow("sci file") << "http://no-such-qt-server-like-this/none.sci";
}

QTEST_MAIN(tst_qmlgraphicsborderimage)

#include "tst_qmlgraphicsborderimage.moc"
<commit_msg>check warnings<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QTextDocument>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDir>

#include <QtDeclarative/qmlengine.h>
#include <QtDeclarative/qmlcomponent.h>
#include <private/qmlgraphicsborderimage_p.h>
#include <private/qmlgraphicsimagebase_p.h>
#include <private/qmlgraphicsscalegrid_p_p.h>
#include <private/qmlgraphicsloader_p.h>
#include <QtDeclarative/qmlcontext.h>

#include "../shared/testhttpserver.h"

#define SERVER_PORT 14445
#define SERVER_ADDR "http://127.0.0.1:14445"

#define TRY_WAIT(expr) \
    do { \
        for (int ii = 0; ii < 6; ++ii) { \
            if ((expr)) break; \
            QTest::qWait(50); \
        } \
        QVERIFY((expr)); \
    } while (false)

class tst_qmlgraphicsborderimage : public QObject

{
    Q_OBJECT
public:
    tst_qmlgraphicsborderimage();

private slots:
    void noSource();
    void imageSource();
    void imageSource_data();
    void clearSource();
    void resized();
    void smooth();
    void tileModes();
    void sciSource();
    void sciSource_data();
    void invalidSciFile();
    void pendingRemoteRequest();
    void pendingRemoteRequest_data();

private:
    QmlEngine engine;
};

tst_qmlgraphicsborderimage::tst_qmlgraphicsborderimage()
{
}

void tst_qmlgraphicsborderimage::noSource()
{
    QString componentStr = "import Qt 4.6\nBorderImage { source: \"\" }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QCOMPARE(obj->source(), QUrl());
    QCOMPARE(obj->width(), 0.);
    QCOMPARE(obj->height(), 0.);
    QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Stretch);
    QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Stretch);

    delete obj;
}

void tst_qmlgraphicsborderimage::imageSource_data()
{
    QTest::addColumn<QString>("source");
    QTest::addColumn<bool>("remote");
    QTest::addColumn<QString>("error");

    QTest::newRow("local") << SRCDIR "/data/colors.png" << false << "";
    QTest::newRow("local not found") << SRCDIR "/data/no-such-file.png" << false
        << "Cannot open  QUrl( \"file://" SRCDIR "/data/no-such-file.png\" )  ";
    QTest::newRow("remote") << SERVER_ADDR "/colors.png" << true << "";
    QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.png" << true
        << "Network error loading  QUrl( \"" SERVER_ADDR "/no-such-file.png\" )  "
            "\"Error downloading " SERVER_ADDR "/no-such-file.png - server replied: Not found\" ";
}

void tst_qmlgraphicsborderimage::imageSource()
{
    QFETCH(QString, source);
    QFETCH(bool, remote);
    QFETCH(QString, error);

    TestHTTPServer *server = 0;
    if (remote) {
        server = new TestHTTPServer(SERVER_PORT);
        QVERIFY(server->isValid());
        server->serveDirectory(SRCDIR "/data");
    }

    if (!error.isEmpty())
        QTest::ignoreMessage(QtWarningMsg, error.toUtf8());

    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" + source + "\" }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);

    if (remote)
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Loading);

    QCOMPARE(obj->source(), remote ? source : QUrl::fromLocalFile(source));

    if (error.isEmpty()) {
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Ready);
        QCOMPARE(obj->width(), 120.);
        QCOMPARE(obj->height(), 120.);
        QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Stretch);
        QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Stretch);
    } else {
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Error);
    }

    delete obj;
    delete server;
}

void tst_qmlgraphicsborderimage::clearSource()
{
    QString componentStr = "import Qt 4.6\nBorderImage { source: srcImage }";
    QmlContext *ctxt = engine.rootContext();
    ctxt->setContextProperty("srcImage", SRCDIR "/data/colors.png");
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QVERIFY(obj->status() == QmlGraphicsBorderImage::Ready);
    QCOMPARE(obj->width(), 120.);
    QCOMPARE(obj->height(), 120.);

    ctxt->setContextProperty("srcImage", "");
    QVERIFY(obj->source().isEmpty());
    QVERIFY(obj->status() == QmlGraphicsBorderImage::Null);
    QCOMPARE(obj->width(), 0.);
    QCOMPARE(obj->height(), 0.);
}

void tst_qmlgraphicsborderimage::resized()
{
    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; width: 300; height: 300 }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QCOMPARE(obj->width(), 300.);
    QCOMPARE(obj->height(), 300.);
    QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Stretch);
    QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Stretch);

    delete obj;
}

void tst_qmlgraphicsborderimage::smooth()
{
    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; smooth: true; width: 300; height: 300 }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QCOMPARE(obj->width(), 300.);
    QCOMPARE(obj->height(), 300.);
    QCOMPARE(obj->smooth(), true);
    QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Stretch);
    QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Stretch);

    delete obj;
}

void tst_qmlgraphicsborderimage::tileModes()
{
    {
        QString componentStr = "import Qt 4.6\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; width: 100; height: 300; horizontalTileMode: BorderImage.Repeat; verticalTileMode: BorderImage.Repeat }";
        QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
        QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
        QVERIFY(obj != 0);
        QCOMPARE(obj->width(), 100.);
        QCOMPARE(obj->height(), 300.);
        QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Repeat);
        QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Repeat);

        delete obj;
    }
    {
        QString componentStr = "import Qt 4.6\nBorderImage { source: \"" SRCDIR "/data/colors.png\"; width: 300; height: 150; horizontalTileMode: BorderImage.Round; verticalTileMode: BorderImage.Round }";
        QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
        QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
        QVERIFY(obj != 0);
        QCOMPARE(obj->width(), 300.);
        QCOMPARE(obj->height(), 150.);
        QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Round);
        QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Round);

        delete obj;
    }
}

void tst_qmlgraphicsborderimage::sciSource()
{
    QFETCH(QString, source);
    QFETCH(bool, valid);

    bool remote = source.startsWith("http");
    TestHTTPServer *server = 0;
    if (remote) {
        server = new TestHTTPServer(SERVER_PORT);
        QVERIFY(server->isValid());
        server->serveDirectory(SRCDIR "/data");
    }

    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" + source + "\"; width: 300; height: 300 }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);

    if (remote)
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Loading);

    QCOMPARE(obj->source(), remote ? source : QUrl::fromLocalFile(source));
    QCOMPARE(obj->width(), 300.);
    QCOMPARE(obj->height(), 300.);

    if (valid) {
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Ready);
        QCOMPARE(obj->border()->left(), 10);
        QCOMPARE(obj->border()->top(), 20);
        QCOMPARE(obj->border()->right(), 30);
        QCOMPARE(obj->border()->bottom(), 40);
        QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Round);
        QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Repeat);
    } else {
        TRY_WAIT(obj->status() == QmlGraphicsBorderImage::Error);
    }

    delete obj;
    delete server;
}

void tst_qmlgraphicsborderimage::sciSource_data()
{
    QTest::addColumn<QString>("source");
    QTest::addColumn<bool>("valid");

    QTest::newRow("local") << SRCDIR "/data/colors-round.sci" << true;
    QTest::newRow("local not found") << SRCDIR "/data/no-such-file.sci" << false;
    QTest::newRow("remote") << SERVER_ADDR "/colors-round.sci" << true;
    QTest::newRow("remote not found") << SERVER_ADDR "/no-such-file.sci" << false;
}

void tst_qmlgraphicsborderimage::invalidSciFile()
{
    QTest::ignoreMessage(QtWarningMsg, "Unknown tile rule specified. Using Stretch "); // for "Roun"
    QTest::ignoreMessage(QtWarningMsg, "Unknown tile rule specified. Using Stretch "); // for "Repea"

    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" SRCDIR "/data/invalid.sci\"; width: 300; height: 300 }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QCOMPARE(obj->width(), 300.);
    QCOMPARE(obj->height(), 300.);
    QCOMPARE(obj->status(), QmlGraphicsImageBase::Error);
    QCOMPARE(obj->horizontalTileMode(), QmlGraphicsBorderImage::Stretch);
    QCOMPARE(obj->verticalTileMode(), QmlGraphicsBorderImage::Stretch);

    delete obj;
}

void tst_qmlgraphicsborderimage::pendingRemoteRequest()
{
    QFETCH(QString, source);

    QString componentStr = "import Qt 4.6\nBorderImage { source: \"" + source + "\" }";
    QmlComponent component(&engine, componentStr.toLatin1(), QUrl("file://"));
    QmlGraphicsBorderImage *obj = qobject_cast<QmlGraphicsBorderImage*>(component.create());
    QVERIFY(obj != 0);
    QCOMPARE(obj->status(), QmlGraphicsBorderImage::Loading);

    // verify no crash
    // This will cause a delayed "QThread: Destroyed while thread is still running" warning
    delete obj;
    QTest::qWait(50);
}

void tst_qmlgraphicsborderimage::pendingRemoteRequest_data()
{
    QTest::addColumn<QString>("source");

    QTest::newRow("png file") << "http://no-such-qt-server-like-this/none.png";
    QTest::newRow("sci file") << "http://no-such-qt-server-like-this/none.sci";
}

QTEST_MAIN(tst_qmlgraphicsborderimage)

#include "tst_qmlgraphicsborderimage.moc"
<|endoftext|>


<commit_before>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 **************************************************************************/

#include "Transform.h"

DC_BEGIN_DREEMCHEST

namespace Scene {

// ------------------------------------------- MoveTo ------------------------------------------- //

// ** MoveTo::target
Vec3 MoveTo::target( void ) const
{
	return m_target->get();
}

// ** MoveTo::isContinuous
bool MoveTo::isContinuous( void ) const
{
	return m_isContinuous;
}

// ** MoveTo::type
MoveTo::Type MoveTo::type( void ) const
{
	return m_type;
}

// ** MoveTo::damping
f32 MoveTo::damping( void ) const
{
	return m_damping;
}

// ** MoveTo::springForce
f32 MoveTo::springForce( void ) const
{
	return m_springForce;
}

// ------------------------------------------ Transform ------------------------------------------ //

// ** Transform::matrix
const Matrix4& Transform::matrix( void ) const
{
	return m_transform;
}

// ** Transform::setMatrix
void Transform::setMatrix( const Matrix4& value )
{
	m_transform = value;
}

// ** Transform::parent
const TransformWPtr& Transform::parent( void ) const
{
	return m_parent;
}

// ** Transform::setParent
void Transform::setParent( const TransformWPtr& value )
{
	m_parent = value;
}

// ** Transform::worldSpacePosition
Vec3 Transform::worldSpacePosition( void ) const
{
	return matrix() * Vec3( 0.0f, 0.0f, 0.0f );
}

// ** Transform::position
const Vec3& Transform::position( void ) const
{
	return m_position;
}

// ** Transform::setPosition
void Transform::setPosition( const Vec3& value )
{
	m_position = value;
}

// ** Transform::axisX
Vec3 Transform::axisX( void ) const
{
	return m_rotation.rotate( Vec3( 1.0f, 0.0f, 0.0f ) );
}

// ** Transform::axisY
Vec3 Transform::axisY( void ) const
{
	return m_rotation.rotate( Vec3( 0.0f, 1.0f, 0.0f ) );
}

// ** Transform::axisZ
Vec3 Transform::axisZ( void ) const
{
	return m_rotation.rotate( Vec3( 0.0f, 0.0f, 1.0f ) );
}

// ** Transform::x
f32 Transform::x( void ) const
{
	return m_position.x;
}

// ** Transform::setX
void Transform::setX( f32 value )
{
	m_position.x = value;
}

// ** Transform::y
f32 Transform::y( void ) const
{
	return m_position.y;
}

// ** Transform::setY
void Transform::setY( f32 value )
{
	m_position.y = value;
}

// ** Transform::rotation
const Quat& Transform::rotation( void ) const
{
	return m_rotation;
}

// ** Transform::rotate
void Transform::rotate( f32 angle, f32 x, f32 y, f32 z )
{
	Quat r = Quat::rotateAroundAxis( angle, Vec3( x, y, z ) );
	m_rotation = r * m_rotation;
}

// ** Transform::setRotation
void Transform::setRotation( const Quat& value )
{
	m_rotation = value;
}

// ** Transform::rotationX
f32 Transform::rotationX( void ) const
{
	return m_rotation.x;
}

// ** Transform::setRotationX
void Transform::setRotationX( f32 value )
{
	m_rotation.x = value;
}

// ** Transform::rotationY
f32 Transform::rotationY( void ) const
{
	return m_rotation.y;
}

// ** Transform::setRotationY
void Transform::setRotationY( f32 value )
{
	m_rotation.y = value;
}

// ** Transform::rotationZ
f32 Transform::rotationZ( void ) const
{
	return m_rotation.z;
}

// ** Transform::setRotationZ
void Transform::setRotationZ( f32 value )
{
	m_rotation = Quat::rotateAroundAxis( value, Vec3( 0.0f, 0.0f, 1.0f ) );
}

// ** Transform::setScale
void Transform::setScale( const Vec3& value )
{
	m_scale = value;
}

// ** Transform::scale
const Vec3& Transform::scale( void ) const
{
	return m_scale;
}

// ** Transform::scaleX
f32 Transform::scaleX( void ) const
{
	return m_scale.x;
}

// ** Transform::setScaleX
void Transform::setScaleX( f32 value )
{
	m_scale.x = value;
}

// ** Transform::scaleY
f32 Transform::scaleY( void ) const
{
	return m_scale.y;
}

// ** Transform::setScaleY
void Transform::setScaleY( f32 value )
{
	m_scale.y = value;
}

// ** Transform::scaleZ
f32 Transform::scaleZ( void ) const
{
	return m_scale.z;
}

// ** Transform::setScaleZ
void Transform::setScaleZ( f32 value )
{
	m_scale.z = value;
}

// ----------------------------------------------- Identifier ------------------------------------------------ //

// ** Identifier::name
const String& Identifier::name( void ) const
{
	return m_name;
}

// ** Identifier::setName
void Identifier::setName( const String& value )
{
	m_name = value;
}

// --------------------------------------------- MoveAlongAxes --------------------------------------------- //

// ** MoveAlongAxes::speed
f32 MoveAlongAxes::speed( void ) const
{
	return m_speed;
}

// ** MoveAlongAxes::coordinateSystem
u8 MoveAlongAxes::coordinateSystem( void ) const
{
	return m_coordinateSystem;
}

// ** MoveAlongAxes::delta
Vec3 MoveAlongAxes::delta( void ) const
{
	return m_delta->get();
}

// ** MoveAlongAxes::rangeForAxis
const Range& MoveAlongAxes::rangeForAxis( CoordinateSystemAxis axis ) const
{
	return m_range[axis];
}

// ** MoveAlongAxes::setRangeForAxis
void MoveAlongAxes::setRangeForAxis( CoordinateSystemAxis axis, const Range& value )
{
	m_range[axis] = value;
}

// --------------------------------------------- RotateAroundAxes --------------------------------------------- //

// ** RotateAroundAxes::speed
f32 RotateAroundAxes::speed( void ) const
{
	return m_speed;
}

// ** RotateAroundAxes::setSpeed
void RotateAroundAxes::setSpeed( f32 value )
{
	m_speed = value;
}

// ** RotateAroundAxes::coordinateSystem
u8 RotateAroundAxes::coordinateSystem( void ) const
{
	return m_coordinateSystem;
}

// ** RotateAroundAxes::delta
Vec3 RotateAroundAxes::delta( void ) const
{
	return m_delta->get();
}

// ** RotateAroundAxes::binding
Vec3BindingWPtr RotateAroundAxes::binding( void ) const
{
	return m_delta;
}

// ** RotateAroundAxes::setBinding
void RotateAroundAxes::setBinding( const Vec3BindingPtr& value )
{
	m_delta = value;
}

// ** RotateAroundAxes::rangeForAxis
const Range& RotateAroundAxes::rangeForAxis( CoordinateSystemAxis axis ) const
{
	return m_range[axis];
}

// ** RotateAroundAxes::setRangeForAxis
void RotateAroundAxes::setRangeForAxis( CoordinateSystemAxis axis, const Range& value )
{
	m_range[axis] = value;
}

// ** RotateAroundAxes::rotationForAxis
f32 RotateAroundAxes::rotationForAxis( CoordinateSystemAxis axis ) const
{
	return m_rotation[axis];
}

// ** RotateAroundAxes::setRotationForAxis
void RotateAroundAxes::setRotationForAxis( CoordinateSystemAxis axis, f32 value )
{
	m_rotation[axis] = value;
}

} // namespace Scene

DC_END_DREEMCHEST<commit_msg>Implemented: Transform z property accessors<commit_after>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 **************************************************************************/

#include "Transform.h"

DC_BEGIN_DREEMCHEST

namespace Scene {

// ------------------------------------------- MoveTo ------------------------------------------- //

// ** MoveTo::target
Vec3 MoveTo::target( void ) const
{
	return m_target->get();
}

// ** MoveTo::isContinuous
bool MoveTo::isContinuous( void ) const
{
	return m_isContinuous;
}

// ** MoveTo::type
MoveTo::Type MoveTo::type( void ) const
{
	return m_type;
}

// ** MoveTo::damping
f32 MoveTo::damping( void ) const
{
	return m_damping;
}

// ** MoveTo::springForce
f32 MoveTo::springForce( void ) const
{
	return m_springForce;
}

// ------------------------------------------ Transform ------------------------------------------ //

// ** Transform::matrix
const Matrix4& Transform::matrix( void ) const
{
	return m_transform;
}

// ** Transform::setMatrix
void Transform::setMatrix( const Matrix4& value )
{
	m_transform = value;
}

// ** Transform::parent
const TransformWPtr& Transform::parent( void ) const
{
	return m_parent;
}

// ** Transform::setParent
void Transform::setParent( const TransformWPtr& value )
{
	m_parent = value;
}

// ** Transform::worldSpacePosition
Vec3 Transform::worldSpacePosition( void ) const
{
	return matrix() * Vec3( 0.0f, 0.0f, 0.0f );
}

// ** Transform::position
const Vec3& Transform::position( void ) const
{
	return m_position;
}

// ** Transform::setPosition
void Transform::setPosition( const Vec3& value )
{
	m_position = value;
}

// ** Transform::axisX
Vec3 Transform::axisX( void ) const
{
	return m_rotation.rotate( Vec3( 1.0f, 0.0f, 0.0f ) );
}

// ** Transform::axisY
Vec3 Transform::axisY( void ) const
{
	return m_rotation.rotate( Vec3( 0.0f, 1.0f, 0.0f ) );
}

// ** Transform::axisZ
Vec3 Transform::axisZ( void ) const
{
	return m_rotation.rotate( Vec3( 0.0f, 0.0f, 1.0f ) );
}

// ** Transform::x
f32 Transform::x( void ) const
{
	return m_position.x;
}

// ** Transform::setX
void Transform::setX( f32 value )
{
	m_position.x = value;
}

// ** Transform::y
f32 Transform::y( void ) const
{
	return m_position.y;
}

// ** Transform::setY
void Transform::setY( f32 value )
{
	m_position.y = value;
}

// ** Transform::z
f32 Transform::z( void ) const
{
	return m_position.z;
}

// ** Transform::setZ
void Transform::setZ( f32 value )
{
	m_position.z = value;
}

// ** Transform::rotation
const Quat& Transform::rotation( void ) const
{
	return m_rotation;
}

// ** Transform::rotate
void Transform::rotate( f32 angle, f32 x, f32 y, f32 z )
{
	Quat r = Quat::rotateAroundAxis( angle, Vec3( x, y, z ) );
	m_rotation = r * m_rotation;
}

// ** Transform::setRotation
void Transform::setRotation( const Quat& value )
{
	m_rotation = value;
}

// ** Transform::rotationX
f32 Transform::rotationX( void ) const
{
	return m_rotation.x;
}

// ** Transform::setRotationX
void Transform::setRotationX( f32 value )
{
	m_rotation.x = value;
}

// ** Transform::rotationY
f32 Transform::rotationY( void ) const
{
	return m_rotation.y;
}

// ** Transform::setRotationY
void Transform::setRotationY( f32 value )
{
	m_rotation.y = value;
}

// ** Transform::rotationZ
f32 Transform::rotationZ( void ) const
{
	return m_rotation.z;
}

// ** Transform::setRotationZ
void Transform::setRotationZ( f32 value )
{
	m_rotation = Quat::rotateAroundAxis( value, Vec3( 0.0f, 0.0f, 1.0f ) );
}

// ** Transform::setScale
void Transform::setScale( const Vec3& value )
{
	m_scale = value;
}

// ** Transform::scale
const Vec3& Transform::scale( void ) const
{
	return m_scale;
}

// ** Transform::scaleX
f32 Transform::scaleX( void ) const
{
	return m_scale.x;
}

// ** Transform::setScaleX
void Transform::setScaleX( f32 value )
{
	m_scale.x = value;
}

// ** Transform::scaleY
f32 Transform::scaleY( void ) const
{
	return m_scale.y;
}

// ** Transform::setScaleY
void Transform::setScaleY( f32 value )
{
	m_scale.y = value;
}

// ** Transform::scaleZ
f32 Transform::scaleZ( void ) const
{
	return m_scale.z;
}

// ** Transform::setScaleZ
void Transform::setScaleZ( f32 value )
{
	m_scale.z = value;
}

// ----------------------------------------------- Identifier ------------------------------------------------ //

// ** Identifier::name
const String& Identifier::name( void ) const
{
	return m_name;
}

// ** Identifier::setName
void Identifier::setName( const String& value )
{
	m_name = value;
}

// --------------------------------------------- MoveAlongAxes --------------------------------------------- //

// ** MoveAlongAxes::speed
f32 MoveAlongAxes::speed( void ) const
{
	return m_speed;
}

// ** MoveAlongAxes::coordinateSystem
u8 MoveAlongAxes::coordinateSystem( void ) const
{
	return m_coordinateSystem;
}

// ** MoveAlongAxes::delta
Vec3 MoveAlongAxes::delta( void ) const
{
	return m_delta->get();
}

// ** MoveAlongAxes::rangeForAxis
const Range& MoveAlongAxes::rangeForAxis( CoordinateSystemAxis axis ) const
{
	return m_range[axis];
}

// ** MoveAlongAxes::setRangeForAxis
void MoveAlongAxes::setRangeForAxis( CoordinateSystemAxis axis, const Range& value )
{
	m_range[axis] = value;
}

// --------------------------------------------- RotateAroundAxes --------------------------------------------- //

// ** RotateAroundAxes::speed
f32 RotateAroundAxes::speed( void ) const
{
	return m_speed;
}

// ** RotateAroundAxes::setSpeed
void RotateAroundAxes::setSpeed( f32 value )
{
	m_speed = value;
}

// ** RotateAroundAxes::coordinateSystem
u8 RotateAroundAxes::coordinateSystem( void ) const
{
	return m_coordinateSystem;
}

// ** RotateAroundAxes::delta
Vec3 RotateAroundAxes::delta( void ) const
{
	return m_delta->get();
}

// ** RotateAroundAxes::binding
Vec3BindingWPtr RotateAroundAxes::binding( void ) const
{
	return m_delta;
}

// ** RotateAroundAxes::setBinding
void RotateAroundAxes::setBinding( const Vec3BindingPtr& value )
{
	m_delta = value;
}

// ** RotateAroundAxes::rangeForAxis
const Range& RotateAroundAxes::rangeForAxis( CoordinateSystemAxis axis ) const
{
	return m_range[axis];
}

// ** RotateAroundAxes::setRangeForAxis
void RotateAroundAxes::setRangeForAxis( CoordinateSystemAxis axis, const Range& value )
{
	m_range[axis] = value;
}

// ** RotateAroundAxes::rotationForAxis
f32 RotateAroundAxes::rotationForAxis( CoordinateSystemAxis axis ) const
{
	return m_rotation[axis];
}

// ** RotateAroundAxes::setRotationForAxis
void RotateAroundAxes::setRotationForAxis( CoordinateSystemAxis axis, f32 value )
{
	m_rotation[axis] = value;
}

} // namespace Scene

DC_END_DREEMCHEST<|endoftext|>