<commit_before>#include "physics/n_body_system.hpp"

#include <cmath>
#include <functional>
#include <set>
#include <vector>

#include "geometry/r3_element.hpp"
#ifndef _MANAGED
#include "glog/logging.h"
#endif
#include "integrators/symplectic_partitioned_runge_kutta_integrator.hpp"
#include "quantities/quantities.hpp"

using principia::geometry::R3Element;
using principia::integrators::SPRKIntegrator;
using principia::integrators::SymplecticIntegrator;
using principia::quantities::Acceleration;
using principia::quantities::Exponentiation;
using principia::quantities::GravitationalParameter;
using principia::quantities::Length;
using principia::quantities::Speed;

namespace principia {
namespace physics {

template<typename InertialFrame>
NBodySystem<InertialFrame>::NBodySystem(Bodies&& massive_bodies,
                                        Bodies&& massless_bodies)
    : massive_bodies_(std::move(massive_bodies)),
      massless_bodies_(std::move(massless_bodies)) {
  // Parameter checking.
  for (auto const& body : massive_bodies_) {
    auto const inserted = bodies_.insert(body.get());
#ifndef _MANAGED
    CHECK(inserted.second) << "Massive body occurs multiple times";
    CHECK(!body->is_massless()) << "Massive body is massless";
#endif
  }
  for (auto const& body : massless_bodies_) {
    auto const inserted = bodies_.insert(body.get());
#ifndef _MANAGED
    CHECK(inserted.second) << "Massless body occurs multiple times";
    CHECK(body->is_massless()) << "Massless body is massive";
#endif
  }
}

template<typename InertialFrame>
std::vector<Body const*> NBodySystem<InertialFrame>::massless_bodies() const {
  std::vector<Body const*> result;
  for (auto const& body : massless_bodies_) {
    result.push_back(body.get());
  }
  return result;
}

template<typename InertialFrame>
std::vector<Body const*> NBodySystem<InertialFrame>::massive_bodies() const {
  std::vector<Body const*> result;
  for (auto const& body : massive_bodies_) {
    result.push_back(body.get());
  }
  return result;
}

template<typename InertialFrame>
void NBodySystem<InertialFrame>::Integrate(
    SymplecticIntegrator<Length, Speed> const& integrator,
    Time const& tmax,
    Time const& Δt,
    int const sampling_period,
    Trajectories const& trajectories) {
  SymplecticIntegrator<Length, Speed>::Parameters parameters;
  std::vector<SymplecticIntegrator<Length, Speed>::SystemState> solution;

#ifndef _MANAGED
  // These objects are for checking the consistency of the parameters.
  std::set<Time> times_in_trajectories;
  std::set<Body const*> bodies_in_trajectories;
#endif

  // Prepare the initial state of the integrator.  For efficiently computing the
  // accelerations, we need to separate the trajectories of massive bodies from
  // those of massless bodies.  They are put in this order in
  // |reordered_trajectories|.  The trajectories of massive and massless bodies
  // are put in |massive_trajectories| and |massless_trajectories|,
  // respectively.
  std::vector<Trajectory<InertialFrame>*> reordered_trajectories;
  std::vector<Trajectory<InertialFrame> const*> massive_trajectories;
  std::vector<Trajectory<InertialFrame> const*> massless_trajectories;
  // This loop ensures that the massive bodies precede the massless bodies in
  // the vectors representing the initial data.
  for (bool is_massless : {false, true}) {
    for (auto const& trajectory : trajectories) {
      // See if this trajectory should be processed in this iteration and
      // update the appropriate vector.
      Body const* const body = &trajectory->body();
      if (body->is_massless() != is_massless) {
        continue;
      }
      if (is_massless) {
        massless_trajectories.push_back(trajectory);
      } else {
        massive_trajectories.push_back(trajectory);
      }
      reordered_trajectories.push_back(trajectory);

      // Fill the initial position/velocity/time.
      R3Element<Length> const& position =
          trajectory->last_position().coordinates();
      R3Element<Speed> const& velocity =
          trajectory->last_velocity().coordinates();
      Time const& time = trajectory->last_time();
      for (int i = 0; i < 3; ++i) {
        parameters.initial.positions.emplace_back(position[i]);
      }
      for (int i = 0; i < 3; ++i) {
        parameters.initial.momenta.emplace_back(velocity[i]);
      }
      parameters.initial.time = time;

#ifndef _MANAGED
      // Check that the trajectory is for a body passed at construction.
      CHECK(bodies_.find(body) != bodies_.end())
          << "Trajectory for an unknown body";
      // Check that all trajectories are for different bodies.
      auto const inserted = bodies_in_trajectories.insert(body);
      CHECK(inserted.second) << "Multiple trajectories for the same body";
      // The final points of all trajectories must all be for the same time.
      times_in_trajectories.insert(time);
      CHECK_GE(1U, times_in_trajectories.size())
          << "Inconsistent last time in trajectories";
#endif
    }
  }
  {
    // Beyond this point we must not use the |trajectories| parameter as it is
    // in the wrong order with respect to the data passed to the integrator.  We
    // use this block to hide it.
    Trajectories const& trajectories = reordered_trajectories;

    parameters.tmax = tmax;
    parameters.Δt = Δt;
    parameters.sampling_period = sampling_period;
    dynamic_cast<const SPRKIntegrator<Length, Speed>*>(&integrator)->Solve(
        std::bind(&NBodySystem::ComputeGravitationalAccelerations,
                  massive_trajectories,
                  massless_trajectories,
                  std::placeholders::_1,
                  std::placeholders::_2,
                  std::placeholders::_3),
        &ComputeGravitationalVelocities,
        parameters, &solution);

    // TODO(phl): Ignoring errors for now.
    // Loop over the time steps.
    for (std::size_t i = 0; i < solution.size(); ++i) {
      SymplecticIntegrator<Length, Speed>::SystemState const& state =
          solution[i];
      Time const& time = state.time.value;
#ifndef _MANAGED
      CHECK_EQ(state.positions.size(), state.momenta.size());
#endif
      // Loop over the dimensions.
      for (std::size_t k = 0, t = 0; k < state.positions.size(); k += 3, ++t) {
        Vector<Length, InertialFrame> const position(
            R3Element<Length>(state.positions[k].value,
                              state.positions[k + 1].value,
                              state.positions[k + 2].value));
        Vector<Speed, InertialFrame> const velocity(
            R3Element<Speed>(state.momenta[k].value,
                             state.momenta[k + 1].value,
                             state.momenta[k + 2].value));
        trajectories[t]->Append(
            time, DegreesOfFreedom<InertialFrame>(position, velocity));
      }
    }
  }
}

template<typename InertialFrame>
void NBodySystem<InertialFrame>::ComputeGravitationalAccelerations(
    std::vector<Trajectory<InertialFrame> const*> const& massive_trajectories,
    std::vector<Trajectory<InertialFrame> const*> const& massless_trajectories,
    Time const& t,
    std::vector<Length> const& q,
    std::vector<Acceleration>* result) {
  result->assign(result->size(), Acceleration());

  // TODO(phl): Used to deal with proper accelerations here.
  for (std::size_t b1 = 0, three_b1 = 0;
       b1 < massive_trajectories.size();
       ++b1, three_b1 += 3) {
    GravitationalParameter const& body1_gravitational_parameter =
        massive_trajectories[b1]->body().gravitational_parameter();
    for (std::size_t b2 = b1 + 1; b2 < massive_trajectories.size(); ++b2) {
      std::size_t const three_b2 = 3 * b2;
      Length const Δq0 = q[three_b1] - q[three_b2];
      Length const Δq1 = q[three_b1 + 1] - q[three_b2 + 1];
      Length const Δq2 = q[three_b1 + 2] - q[three_b2 + 2];

      Exponentiation<Length, 2> const squared_distance =
          Δq0 * Δq0 + Δq1 * Δq1 + Δq2 * Δq2;
      Exponentiation<Length, -3> const multiplier =
          Sqrt(squared_distance) / (squared_distance * squared_distance);

      auto const μ2OverRSquared =
          massive_trajectories[b2]->body().gravitational_parameter() *
          multiplier;
      (*result)[three_b1] -= Δq0 * μ2OverRSquared;
      (*result)[three_b1 + 1] -= Δq1 * μ2OverRSquared;
      (*result)[three_b1 + 2] -= Δq2 * μ2OverRSquared;
      // Lex. III. Actioni contrariam semper & æqualem esse reactionem:
      // sive corporum duorum actiones in se mutuo semper esse æquales &
      // in partes contrarias dirigi.
      auto const μ1OverRSquared = body1_gravitational_parameter * multiplier;
      (*result)[three_b2] += Δq0 * μ1OverRSquared;
      (*result)[three_b2 + 1] += Δq1 * μ1OverRSquared;
      (*result)[three_b2 + 2] += Δq2 * μ1OverRSquared;
    }
    for (int b2 = 0; b2 < massless_trajectories.size(); ++b2) {
      std::size_t const three_b2 = 3 * b2;
      Length const Δq0 = q[three_b1] - q[three_b2];
      Length const Δq1 = q[three_b1 + 1] - q[three_b2 + 1];
      Length const Δq2 = q[three_b1 + 2] - q[three_b2 + 2];

      Exponentiation<Length, 2> const squared_distance =
          Δq0 * Δq0 + Δq1 * Δq1 + Δq2 * Δq2;
      Exponentiation<Length, -3> const multiplier =
          Sqrt(squared_distance) / (squared_distance * squared_distance);

      auto const μ1OverRSquared = body1_gravitational_parameter * multiplier;
      (*result)[three_b2] += Δq0 * μ1OverRSquared;
      (*result)[three_b2 + 1] += Δq1 * μ1OverRSquared;
      (*result)[three_b2 + 2] += Δq2 * μ1OverRSquared;
    }
  }

  // Finally, take into account the intrinsic accelerations.
  for (int b2 = 0; b2 < massless_trajectories.size(); ++b2) {
    std::size_t const three_b2 = 3 * b2;
    Trajectory<InertialFrame>::IntrinsicAcceleration* intrinsic_acceleration =
        massless_trajectories[b2]->intrinsic_acceleration();
    if (intrinsic_acceleration != nullptr) {
      R3Element<Acceleration> const acceleration =
          (*intrinsic_acceleration)(t).coordinates();
      (*result)[three_b2] += acceleration.x;
      (*result)[three_b2 + 1] += acceleration.y;
      (*result)[three_b2 + 2] += acceleration.z;
    }
  }
}

template<typename InertialFrame>
void NBodySystem<InertialFrame>::ComputeGravitationalVelocities(
    std::vector<Speed> const& p,
    std::vector<Speed>* result) {
  *result = p;
}

}  // namespace physics
}  // namespace principia
<commit_msg>Take fork time into account.<commit_after>#include "physics/n_body_system.hpp"

#include <cmath>
#include <functional>
#include <set>
#include <vector>

#include "geometry/r3_element.hpp"
#ifndef _MANAGED
#include "glog/logging.h"
#endif
#include "integrators/symplectic_partitioned_runge_kutta_integrator.hpp"
#include "quantities/quantities.hpp"

using principia::geometry::R3Element;
using principia::integrators::SPRKIntegrator;
using principia::integrators::SymplecticIntegrator;
using principia::quantities::Acceleration;
using principia::quantities::Exponentiation;
using principia::quantities::GravitationalParameter;
using principia::quantities::Length;
using principia::quantities::Speed;

namespace principia {
namespace physics {

template<typename InertialFrame>
NBodySystem<InertialFrame>::NBodySystem(Bodies&& massive_bodies,
                                        Bodies&& massless_bodies)
    : massive_bodies_(std::move(massive_bodies)),
      massless_bodies_(std::move(massless_bodies)) {
  // Parameter checking.
  for (auto const& body : massive_bodies_) {
    auto const inserted = bodies_.insert(body.get());
#ifndef _MANAGED
    CHECK(inserted.second) << "Massive body occurs multiple times";
    CHECK(!body->is_massless()) << "Massive body is massless";
#endif
  }
  for (auto const& body : massless_bodies_) {
    auto const inserted = bodies_.insert(body.get());
#ifndef _MANAGED
    CHECK(inserted.second) << "Massless body occurs multiple times";
    CHECK(body->is_massless()) << "Massless body is massive";
#endif
  }
}

template<typename InertialFrame>
std::vector<Body const*> NBodySystem<InertialFrame>::massless_bodies() const {
  std::vector<Body const*> result;
  for (auto const& body : massless_bodies_) {
    result.push_back(body.get());
  }
  return result;
}

template<typename InertialFrame>
std::vector<Body const*> NBodySystem<InertialFrame>::massive_bodies() const {
  std::vector<Body const*> result;
  for (auto const& body : massive_bodies_) {
    result.push_back(body.get());
  }
  return result;
}

template<typename InertialFrame>
void NBodySystem<InertialFrame>::Integrate(
    SymplecticIntegrator<Length, Speed> const& integrator,
    Time const& tmax,
    Time const& Δt,
    int const sampling_period,
    Trajectories const& trajectories) {
  SymplecticIntegrator<Length, Speed>::Parameters parameters;
  std::vector<SymplecticIntegrator<Length, Speed>::SystemState> solution;

#ifndef _MANAGED
  // These objects are for checking the consistency of the parameters.
  std::set<Time> times_in_trajectories;
  std::set<Body const*> bodies_in_trajectories;
#endif

  // Prepare the initial state of the integrator.  For efficiently computing the
  // accelerations, we need to separate the trajectories of massive bodies from
  // those of massless bodies.  They are put in this order in
  // |reordered_trajectories|.  The trajectories of massive and massless bodies
  // are put in |massive_trajectories| and |massless_trajectories|,
  // respectively.
  std::vector<Trajectory<InertialFrame>*> reordered_trajectories;
  std::vector<Trajectory<InertialFrame> const*> massive_trajectories;
  std::vector<Trajectory<InertialFrame> const*> massless_trajectories;
  // This loop ensures that the massive bodies precede the massless bodies in
  // the vectors representing the initial data.
  for (bool is_massless : {false, true}) {
    for (auto const& trajectory : trajectories) {
      // See if this trajectory should be processed in this iteration and
      // update the appropriate vector.
      Body const* const body = &trajectory->body();
      if (body->is_massless() != is_massless) {
        continue;
      }
      if (is_massless) {
        massless_trajectories.push_back(trajectory);
      } else {
        massive_trajectories.push_back(trajectory);
      }
      reordered_trajectories.push_back(trajectory);

      // Fill the initial position/velocity/time.
      R3Element<Length> const& position =
          trajectory->last_position().coordinates();
      R3Element<Speed> const& velocity =
          trajectory->last_velocity().coordinates();
      Time const& time = trajectory->last_time();
      for (int i = 0; i < 3; ++i) {
        parameters.initial.positions.emplace_back(position[i]);
      }
      for (int i = 0; i < 3; ++i) {
        parameters.initial.momenta.emplace_back(velocity[i]);
      }
      parameters.initial.time = time;

#ifndef _MANAGED
      // Check that the trajectory is for a body passed at construction.
      CHECK(bodies_.find(body) != bodies_.end())
          << "Trajectory for an unknown body";
      // Check that all trajectories are for different bodies.
      auto const inserted = bodies_in_trajectories.insert(body);
      CHECK(inserted.second) << "Multiple trajectories for the same body";
      // The final points of all trajectories must all be for the same time.
      times_in_trajectories.insert(time);
      CHECK_GE(1U, times_in_trajectories.size())
          << "Inconsistent last time in trajectories";
#endif
    }
  }
  {
    // Beyond this point we must not use the |trajectories| parameter as it is
    // in the wrong order with respect to the data passed to the integrator.  We
    // use this block to hide it.
    Trajectories const& trajectories = reordered_trajectories;

    parameters.tmax = tmax;
    parameters.Δt = Δt;
    parameters.sampling_period = sampling_period;
    dynamic_cast<const SPRKIntegrator<Length, Speed>*>(&integrator)->Solve(
        std::bind(&NBodySystem::ComputeGravitationalAccelerations,
                  massive_trajectories,
                  massless_trajectories,
                  std::placeholders::_1,
                  std::placeholders::_2,
                  std::placeholders::_3),
        &ComputeGravitationalVelocities,
        parameters, &solution);

    // TODO(phl): Ignoring errors for now.
    // Loop over the time steps.
    for (std::size_t i = 0; i < solution.size(); ++i) {
      SymplecticIntegrator<Length, Speed>::SystemState const& state =
          solution[i];
      Time const& time = state.time.value;
#ifndef _MANAGED
      CHECK_EQ(state.positions.size(), state.momenta.size());
#endif
      // Loop over the dimensions.
      for (std::size_t k = 0, t = 0; k < state.positions.size(); k += 3, ++t) {
        Vector<Length, InertialFrame> const position(
            R3Element<Length>(state.positions[k].value,
                              state.positions[k + 1].value,
                              state.positions[k + 2].value));
        Vector<Speed, InertialFrame> const velocity(
            R3Element<Speed>(state.momenta[k].value,
                             state.momenta[k + 1].value,
                             state.momenta[k + 2].value));
        trajectories[t]->Append(
            time, DegreesOfFreedom<InertialFrame>(position, velocity));
      }
    }
  }
}

template<typename InertialFrame>
void NBodySystem<InertialFrame>::ComputeGravitationalAccelerations(
    std::vector<Trajectory<InertialFrame> const*> const& massive_trajectories,
    std::vector<Trajectory<InertialFrame> const*> const& massless_trajectories,
    Time const& t,
    std::vector<Length> const& q,
    std::vector<Acceleration>* result) {
  result->assign(result->size(), Acceleration());

  // TODO(phl): Used to deal with proper accelerations here.
  for (std::size_t b1 = 0, three_b1 = 0;
       b1 < massive_trajectories.size();
       ++b1, three_b1 += 3) {
    GravitationalParameter const& body1_gravitational_parameter =
        massive_trajectories[b1]->body().gravitational_parameter();
    for (std::size_t b2 = b1 + 1; b2 < massive_trajectories.size(); ++b2) {
      std::size_t const three_b2 = 3 * b2;
      Length const Δq0 = q[three_b1] - q[three_b2];
      Length const Δq1 = q[three_b1 + 1] - q[three_b2 + 1];
      Length const Δq2 = q[three_b1 + 2] - q[three_b2 + 2];

      Exponentiation<Length, 2> const squared_distance =
          Δq0 * Δq0 + Δq1 * Δq1 + Δq2 * Δq2;
      Exponentiation<Length, -3> const multiplier =
          Sqrt(squared_distance) / (squared_distance * squared_distance);

      auto const μ2OverRSquared =
          massive_trajectories[b2]->body().gravitational_parameter() *
          multiplier;
      (*result)[three_b1] -= Δq0 * μ2OverRSquared;
      (*result)[three_b1 + 1] -= Δq1 * μ2OverRSquared;
      (*result)[three_b1 + 2] -= Δq2 * μ2OverRSquared;
      // Lex. III. Actioni contrariam semper & æqualem esse reactionem:
      // sive corporum duorum actiones in se mutuo semper esse æquales &
      // in partes contrarias dirigi.
      auto const μ1OverRSquared = body1_gravitational_parameter * multiplier;
      (*result)[three_b2] += Δq0 * μ1OverRSquared;
      (*result)[three_b2 + 1] += Δq1 * μ1OverRSquared;
      (*result)[three_b2 + 2] += Δq2 * μ1OverRSquared;
    }
    for (int b2 = 0; b2 < massless_trajectories.size(); ++b2) {
      std::size_t const three_b2 = 3 * b2;
      Length const Δq0 = q[three_b1] - q[three_b2];
      Length const Δq1 = q[three_b1 + 1] - q[three_b2 + 1];
      Length const Δq2 = q[three_b1 + 2] - q[three_b2 + 2];

      Exponentiation<Length, 2> const squared_distance =
          Δq0 * Δq0 + Δq1 * Δq1 + Δq2 * Δq2;
      Exponentiation<Length, -3> const multiplier =
          Sqrt(squared_distance) / (squared_distance * squared_distance);

      auto const μ1OverRSquared = body1_gravitational_parameter * multiplier;
      (*result)[three_b2] += Δq0 * μ1OverRSquared;
      (*result)[three_b2 + 1] += Δq1 * μ1OverRSquared;
      (*result)[three_b2 + 2] += Δq2 * μ1OverRSquared;
    }
  }

  // Finally, take into account the intrinsic accelerations.
  for (int b2 = 0; b2 < massless_trajectories.size(); ++b2) {
    std::size_t const three_b2 = 3 * b2;
    Trajectory<InertialFrame> const* trajectory = massless_trajectories[b2];
    Time const* fork_time = trajectory->fork_time();
    if (fork_time == nullptr || t < *fork_time) {
      Trajectory<InertialFrame>::IntrinsicAcceleration* intrinsic_acceleration =
          trajectory->intrinsic_acceleration();
      if (intrinsic_acceleration != nullptr) {
        R3Element<Acceleration> const acceleration =
            (*intrinsic_acceleration)(t).coordinates();
        (*result)[three_b2] += acceleration.x;
        (*result)[three_b2 + 1] += acceleration.y;
        (*result)[three_b2 + 2] += acceleration.z;
      }
    }
  }
}

template<typename InertialFrame>
void NBodySystem<InertialFrame>::ComputeGravitationalVelocities(
    std::vector<Speed> const& p,
    std::vector<Speed>* result) {
  *result = p;
}

}  // namespace physics
}  // namespace principia
<|endoftext|>


<commit_before>/*************************************************************************************
 *  Copyright (C) 2012 by Alejandro Fiestas Olivares <afiestas@kde.org>              *
 *                                                                                *
 *  This program is free software; you can redistribute it and/or                    *
 *  modify it under the terms of the GNU General Public License                      *
 *  as published by the Free Software Foundation; either version 2                   *
 *  of the License, or (at your option) any later version.                           *
 *                                                                                *
 *  This program is distributed in the hope that it will be useful,                  *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
 *  GNU General Public License for more details.                                     *
 *                                                                                *
 *  You should have received a copy of the GNU General Public License                *
 *  along with this program; if not, write to the Free Software                      *
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
 *************************************************************************************/

#include "generator.h"
#include "device.h"

#include <QtCore/QDebug>

#include <QDBusReply>
#include <QDBusMessage>
#include <QDBusConnection>

#include <kscreen/config.h>

Generator* Generator::instance = 0;

Generator* Generator::self()
{
    if (!Generator::instance) {
        Generator::instance = new Generator();
    }
    return Generator::instance;
}

Generator::Generator()
 : QObject()
 , m_isReady(false)
 , m_forceLaptop(false)
 , m_forceLidClosed(false)
 , m_forceDocked(false)
{
    connect(Device::self(), SIGNAL(ready()), SIGNAL(ready()));
}

void Generator::destroy()
{
    delete Generator::instance;
    Generator::instance = 0;
}

Generator::~Generator()
{
}

KScreen::Config* Generator::idealConfig()
{
    KScreen::Config* config = KScreen::Config::current();
    if (!config) {
        return 0;
    }

    disableAllDisconnectedOutputs(config->outputs());

    KScreen::OutputList outputs = config->connectedOutputs();

    if (outputs.count() == 1) {
        singleOutput(outputs);
        return config;
    }

    if (isLaptop()) {
        laptop(outputs);
        return config;
    }

    extendToRight(outputs);

    return config;
}

KScreen::Config* Generator::displaySwitch(int iteration)
{
    KScreen::Config* config = KScreen::Config::current();
    if (!config) {
        return 0;
    }

    KScreen::OutputList outputs = config->connectedOutputs();

    if (outputs.count() < 2) {
        singleOutput(outputs);
        return config;
    }

    if (outputs.count() > 2) {
        extendToRight(outputs);
        return config;
    }

    KScreen::Output* embedded, *external;
    embedded = embeddedOutput(outputs);
    outputs.remove(embedded->id());
    external = outputs.value(outputs.keys().first());

    //Clone
    if (iteration == 1) {
        KScreen::ModeList modes = embedded->modes();
        QMap<int, QSize> embeddedModeSize;
        Q_FOREACH(KScreen::Mode* mode, modes) {
            embeddedModeSize.insert(mode->id(), mode->size());
        }

        QList<int> embeddedKeys;
        KScreen::ModeList externalCommon;
        KScreen::ModeList externalModes = external->modes();
        Q_FOREACH(KScreen::Mode* mode, externalModes) {
            if (!embeddedModeSize.keys(mode->size()).isEmpty()) {
                externalCommon.insert(mode->id(), mode);
                embeddedKeys.append(embeddedModeSize.keys(mode->size()));
            }
        }

        KScreen::ModeList embeddedCommon;
        Q_FOREACH(int key, embeddedKeys) {
            embeddedCommon.insert(key, modes[key]);
        }

        KScreen::Mode* biggestEmbedded = biggestMode(embeddedCommon);
        KScreen::Mode* biggestExternal = biggestMode(externalCommon);

        embedded->setEnabled(true);
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentMode(biggestEmbedded->id());
        external->setEnabled(true);
        external->setPos(QPoint(0,0));
        external->setCurrentMode(biggestExternal->id());

        return config;
    }

    //Extend left
    if (iteration == 2) {
        external->setEnabled(true);
        external->setPos(QPoint(0,0));
        external->setCurrentMode(external->preferredMode());

        QSize size = external->mode(external->currentMode())->size();
        embedded->setPos(QPoint(size.width(), 0));
        embedded->setEnabled(true);
        embedded->setCurrentMode(embedded->preferredMode());
        embedded->setPrimary(true);
        return config;
    }

    //Turn of embedded
    if (iteration == 3) {
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        external->setEnabled(true);
        external->setPrimary(true);
        external->setCurrentMode(external->preferredMode());
        return config;
    }

    //Turn off external
    if (iteration == 4) {
        embedded->setEnabled(true);
        embedded->setPrimary(true);
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentMode(embedded->preferredMode());

        external->setEnabled(false);
        external->setPrimary(false);
        return config;
    }

    //Extend right
    if (iteration == 5) {
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentMode(embedded->preferredMode());
        embedded->setPrimary(true);
        embedded->setEnabled(true);

        QSize size = embedded->mode(embedded->currentMode())->size();
        external->setPos(QPoint(size.width(), 0));
        external->setEnabled(true);
        external->setCurrentMode(external->preferredMode());
        external->setPrimary(false);

        return config;
    }

    return config;
}

void Generator::singleOutput(KScreen::OutputList& outputs)
{
    qDebug() << "Config for one output";
    KScreen::Output* output = outputs.take(outputs.keys().first());
    if (!output) {
        return;
    }

    output->setCurrentMode(output->preferredMode());
    output->setEnabled(true);
    output->setPrimary(true);
}

void Generator::laptop(KScreen::OutputList& outputs)
{
    qDebug() << "Config for a laptop";

    KScreen::Output* embedded = embeddedOutput(outputs);
    if (!embedded) {
        qWarning() << "No embeded output found!";
        return;
    }

    outputs.remove(embedded->id());

    if (outputs.isEmpty() || !embedded) {
        qWarning("Neither external outputs or embedded could be found");
        return;
    }

    if (isLidClosed() && outputs.count() == 1) {
        qDebug() << "With lid closed";
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        KScreen::Output* external = outputs.value(outputs.keys().first());
        external->setEnabled(true);
        external->setCurrentMode(external->preferredMode());
        external->setPrimary(true);

        return;
    }

    if (isLidClosed() && outputs.count() > 1) {
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        extendToRight(outputs);
        return;
    }

    //If lid is open, laptop screen shuold be primary
    embedded->setPos(QPoint(0,0));
    embedded->setCurrentMode(embedded->preferredMode());
    embedded->setPrimary(true);
    embedded->setEnabled(true);

    int globalWidth;
    if ((embedded->rotation() == KScreen::Output::None) ||
        (embedded->rotation() == KScreen::Output::Inverted)) {
        globalWidth = embedded->mode(embedded->preferredMode())->size().width();
    } else {
        globalWidth = embedded->mode(embedded->preferredMode())->size().height();
    }
    KScreen::Output* biggest = biggestOutput(outputs);
    outputs.remove(biggest->id());

    biggest->setPos(QPoint(globalWidth, 0));
    biggest->setEnabled(true);
    biggest->setCurrentMode(biggest->preferredMode());
    biggest->setPrimary(false);

    if ((biggest->rotation() == KScreen::Output::None) ||
        (biggest->rotation() == KScreen::Output::Inverted)) {
        globalWidth += biggest->mode(biggest->currentMode())->size().width();
    } else {
        globalWidth += biggest->mode(biggest->currentMode())->size().height();
    }
    Q_FOREACH(KScreen::Output* output, outputs) {
        output->setEnabled(true);
        output->setCurrentMode(output->preferredMode());
        output->setPos(QPoint(globalWidth, 0));

        if ((output->rotation() == KScreen::Output::None) ||
            (output->rotation() == KScreen::Output::Inverted)) {
            globalWidth += output->mode(output->currentMode())->size().width();
        } else {
            globalWidth += output->mode(output->currentMode())->size().height();
        }
    }

    if (isDocked()) {
        qDebug() << "Docked";
        embedded->setPrimary(false);
        biggest->setPrimary(true);
    }
}

void Generator::extendToRight(KScreen::OutputList& outputs)
{
    KScreen::Output* biggest = biggestOutput(outputs);
    outputs.remove(biggest->id());

    biggest->setEnabled(true);
    biggest->setPrimary(true);
    biggest->setCurrentMode(biggest->preferredMode());
    biggest->setPos(QPoint(0,0));

    int globalWidth;
    if ((biggest->rotation() == KScreen::Output::None) ||
        (biggest->rotation() == KScreen::Output::Inverted)) {
        globalWidth = biggest->mode(biggest->currentMode())->size().width();
    } else {
        globalWidth = biggest->mode(biggest->currentMode())->size().height();
    }

    Q_FOREACH(KScreen::Output* output, outputs) {
        output->setEnabled(true);
        output->setPrimary(false);
        output->setCurrentMode(output->preferredMode());
        output->setPos(QPoint(globalWidth, 0));

        if ((output->rotation() == KScreen::Output::None) ||
            (output->rotation() == KScreen::Output::Inverted)) {
            globalWidth += output->mode(output->currentMode())->size().width();
        } else {
            globalWidth += output->mode(output->currentMode())->size().height();
        }
    }
}

KScreen::Mode* Generator::biggestMode(const KScreen::ModeList& modes)
{
    int area, total = 0;
    KScreen::Mode* biggest = 0;
    Q_FOREACH(KScreen::Mode* mode, modes) {
        area = mode->size().width() * mode->size().height();
        if (area < total) {
            continue;
        }
        if (area == total && mode->refreshRate() > biggest->refreshRate()) {
            biggest = mode;
            continue;
        }

        total = area;
        biggest = mode;
    }

    return biggest;
}

KScreen::Output* Generator::biggestOutput(const KScreen::OutputList &outputs)
{
    int area, total = 0;
    KScreen::Output* biggest = 0;
    Q_FOREACH(KScreen::Output* output, outputs) {
        KScreen::Mode* mode = output->mode(output->preferredMode());
        area = mode->size().width() * mode->size().height();
        if (area < total) {
            continue;
        }

        total = area;
        biggest = output;
    }

    return biggest;
}

void Generator::disableAllDisconnectedOutputs(const KScreen::OutputList& outputs)
{
    Q_FOREACH(KScreen::Output* output, outputs) {
        if (!output->isConnected()) {
            output->setEnabled(false);
            output->setPrimary(false);
        }
    }
}

KScreen::Output* Generator::embeddedOutput(const KScreen::OutputList& outputs)
{
    Q_FOREACH(KScreen::Output* output, outputs) {
        if (!isEmbedded(output->name())) {
            continue;
        }

        return output;
    }

    return 0;
}

bool Generator::isLaptop()
{
    if (m_forceLaptop) {
        return true;
    }

    return Device::self()->isLaptop();
}

bool Generator::isLidClosed()
{
    if (m_forceLidClosed) {
        return true;
    }

    return Device::self()->isLidClosed();
}

bool Generator::isDocked()
{
    if (m_forceDocked) {
        return true;
    }

    return Device::self()->isDocked();
}

bool Generator::isEmbedded(const QString &name)
{
    QStringList embedded;
    embedded << "LVDS";
    embedded << "IDP";
    embedded << "EDP";

    Q_FOREACH(const QString &pre, embedded) {
        if (name.toUpper().startsWith(pre)) {
            return true;
        }
    }

    return false;
}

void Generator::setForceLaptop(bool force)
{
    m_forceLaptop = force;
}

void Generator::setForceLidClosed(bool force)
{
    m_forceLidClosed = force;
}

void Generator::setForceDocked(bool force)
{
    m_forceDocked = force;
}
<commit_msg>Reset screen position for singleOutput<commit_after>/*************************************************************************************
 *  Copyright (C) 2012 by Alejandro Fiestas Olivares <afiestas@kde.org>              *
 *                                                                                *
 *  This program is free software; you can redistribute it and/or                    *
 *  modify it under the terms of the GNU General Public License                      *
 *  as published by the Free Software Foundation; either version 2                   *
 *  of the License, or (at your option) any later version.                           *
 *                                                                                *
 *  This program is distributed in the hope that it will be useful,                  *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
 *  GNU General Public License for more details.                                     *
 *                                                                                *
 *  You should have received a copy of the GNU General Public License                *
 *  along with this program; if not, write to the Free Software                      *
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
 *************************************************************************************/

#include "generator.h"
#include "device.h"

#include <QtCore/QDebug>

#include <QDBusReply>
#include <QDBusMessage>
#include <QDBusConnection>

#include <kscreen/config.h>

Generator* Generator::instance = 0;

Generator* Generator::self()
{
    if (!Generator::instance) {
        Generator::instance = new Generator();
    }
    return Generator::instance;
}

Generator::Generator()
 : QObject()
 , m_isReady(false)
 , m_forceLaptop(false)
 , m_forceLidClosed(false)
 , m_forceDocked(false)
{
    connect(Device::self(), SIGNAL(ready()), SIGNAL(ready()));
}

void Generator::destroy()
{
    delete Generator::instance;
    Generator::instance = 0;
}

Generator::~Generator()
{
}

KScreen::Config* Generator::idealConfig()
{
    KScreen::Config* config = KScreen::Config::current();
    if (!config) {
        return 0;
    }

    disableAllDisconnectedOutputs(config->outputs());

    KScreen::OutputList outputs = config->connectedOutputs();

    if (outputs.count() == 1) {
        singleOutput(outputs);
        return config;
    }

    if (isLaptop()) {
        laptop(outputs);
        return config;
    }

    extendToRight(outputs);

    return config;
}

KScreen::Config* Generator::displaySwitch(int iteration)
{
    KScreen::Config* config = KScreen::Config::current();
    if (!config) {
        return 0;
    }

    KScreen::OutputList outputs = config->connectedOutputs();

    if (outputs.count() < 2) {
        singleOutput(outputs);
        return config;
    }

    if (outputs.count() > 2) {
        extendToRight(outputs);
        return config;
    }

    KScreen::Output* embedded, *external;
    embedded = embeddedOutput(outputs);
    outputs.remove(embedded->id());
    external = outputs.value(outputs.keys().first());

    //Clone
    if (iteration == 1) {
        KScreen::ModeList modes = embedded->modes();
        QMap<int, QSize> embeddedModeSize;
        Q_FOREACH(KScreen::Mode* mode, modes) {
            embeddedModeSize.insert(mode->id(), mode->size());
        }

        QList<int> embeddedKeys;
        KScreen::ModeList externalCommon;
        KScreen::ModeList externalModes = external->modes();
        Q_FOREACH(KScreen::Mode* mode, externalModes) {
            if (!embeddedModeSize.keys(mode->size()).isEmpty()) {
                externalCommon.insert(mode->id(), mode);
                embeddedKeys.append(embeddedModeSize.keys(mode->size()));
            }
        }

        KScreen::ModeList embeddedCommon;
        Q_FOREACH(int key, embeddedKeys) {
            embeddedCommon.insert(key, modes[key]);
        }

        KScreen::Mode* biggestEmbedded = biggestMode(embeddedCommon);
        KScreen::Mode* biggestExternal = biggestMode(externalCommon);

        embedded->setEnabled(true);
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentMode(biggestEmbedded->id());
        external->setEnabled(true);
        external->setPos(QPoint(0,0));
        external->setCurrentMode(biggestExternal->id());

        return config;
    }

    //Extend left
    if (iteration == 2) {
        external->setEnabled(true);
        external->setPos(QPoint(0,0));
        external->setCurrentMode(external->preferredMode());

        QSize size = external->mode(external->currentMode())->size();
        embedded->setPos(QPoint(size.width(), 0));
        embedded->setEnabled(true);
        embedded->setCurrentMode(embedded->preferredMode());
        embedded->setPrimary(true);
        return config;
    }

    //Turn of embedded
    if (iteration == 3) {
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        external->setEnabled(true);
        external->setPrimary(true);
        external->setCurrentMode(external->preferredMode());
        return config;
    }

    //Turn off external
    if (iteration == 4) {
        embedded->setEnabled(true);
        embedded->setPrimary(true);
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentMode(embedded->preferredMode());

        external->setEnabled(false);
        external->setPrimary(false);
        return config;
    }

    //Extend right
    if (iteration == 5) {
        embedded->setPos(QPoint(0,0));
        embedded->setCurrentMode(embedded->preferredMode());
        embedded->setPrimary(true);
        embedded->setEnabled(true);

        QSize size = embedded->mode(embedded->currentMode())->size();
        external->setPos(QPoint(size.width(), 0));
        external->setEnabled(true);
        external->setCurrentMode(external->preferredMode());
        external->setPrimary(false);

        return config;
    }

    return config;
}

void Generator::singleOutput(KScreen::OutputList& outputs)
{
    qDebug() << "Config for one output";
    KScreen::Output* output = outputs.take(outputs.keys().first());
    if (!output) {
        return;
    }

    output->setCurrentMode(output->preferredMode());
    output->setEnabled(true);
    output->setPrimary(true);
    output->setPos(QPoint(0,0);
}

void Generator::laptop(KScreen::OutputList& outputs)
{
    qDebug() << "Config for a laptop";

    KScreen::Output* embedded = embeddedOutput(outputs);
    if (!embedded) {
        qWarning() << "No embeded output found!";
        return;
    }

    outputs.remove(embedded->id());

    if (outputs.isEmpty() || !embedded) {
        qWarning("Neither external outputs or embedded could be found");
        return;
    }

    if (isLidClosed() && outputs.count() == 1) {
        qDebug() << "With lid closed";
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        KScreen::Output* external = outputs.value(outputs.keys().first());
        external->setEnabled(true);
        external->setCurrentMode(external->preferredMode());
        external->setPrimary(true);

        return;
    }

    if (isLidClosed() && outputs.count() > 1) {
        embedded->setEnabled(false);
        embedded->setPrimary(false);

        extendToRight(outputs);
        return;
    }

    //If lid is open, laptop screen shuold be primary
    embedded->setPos(QPoint(0,0));
    embedded->setCurrentMode(embedded->preferredMode());
    embedded->setPrimary(true);
    embedded->setEnabled(true);

    int globalWidth;
    if ((embedded->rotation() == KScreen::Output::None) ||
        (embedded->rotation() == KScreen::Output::Inverted)) {
        globalWidth = embedded->mode(embedded->preferredMode())->size().width();
    } else {
        globalWidth = embedded->mode(embedded->preferredMode())->size().height();
    }
    KScreen::Output* biggest = biggestOutput(outputs);
    outputs.remove(biggest->id());

    biggest->setPos(QPoint(globalWidth, 0));
    biggest->setEnabled(true);
    biggest->setCurrentMode(biggest->preferredMode());
    biggest->setPrimary(false);

    if ((biggest->rotation() == KScreen::Output::None) ||
        (biggest->rotation() == KScreen::Output::Inverted)) {
        globalWidth += biggest->mode(biggest->currentMode())->size().width();
    } else {
        globalWidth += biggest->mode(biggest->currentMode())->size().height();
    }
    Q_FOREACH(KScreen::Output* output, outputs) {
        output->setEnabled(true);
        output->setCurrentMode(output->preferredMode());
        output->setPos(QPoint(globalWidth, 0));

        if ((output->rotation() == KScreen::Output::None) ||
            (output->rotation() == KScreen::Output::Inverted)) {
            globalWidth += output->mode(output->currentMode())->size().width();
        } else {
            globalWidth += output->mode(output->currentMode())->size().height();
        }
    }

    if (isDocked()) {
        qDebug() << "Docked";
        embedded->setPrimary(false);
        biggest->setPrimary(true);
    }
}

void Generator::extendToRight(KScreen::OutputList& outputs)
{
    KScreen::Output* biggest = biggestOutput(outputs);
    outputs.remove(biggest->id());

    biggest->setEnabled(true);
    biggest->setPrimary(true);
    biggest->setCurrentMode(biggest->preferredMode());
    biggest->setPos(QPoint(0,0));

    int globalWidth;
    if ((biggest->rotation() == KScreen::Output::None) ||
        (biggest->rotation() == KScreen::Output::Inverted)) {
        globalWidth = biggest->mode(biggest->currentMode())->size().width();
    } else {
        globalWidth = biggest->mode(biggest->currentMode())->size().height();
    }

    Q_FOREACH(KScreen::Output* output, outputs) {
        output->setEnabled(true);
        output->setPrimary(false);
        output->setCurrentMode(output->preferredMode());
        output->setPos(QPoint(globalWidth, 0));

        if ((output->rotation() == KScreen::Output::None) ||
            (output->rotation() == KScreen::Output::Inverted)) {
            globalWidth += output->mode(output->currentMode())->size().width();
        } else {
            globalWidth += output->mode(output->currentMode())->size().height();
        }
    }
}

KScreen::Mode* Generator::biggestMode(const KScreen::ModeList& modes)
{
    int area, total = 0;
    KScreen::Mode* biggest = 0;
    Q_FOREACH(KScreen::Mode* mode, modes) {
        area = mode->size().width() * mode->size().height();
        if (area < total) {
            continue;
        }
        if (area == total && mode->refreshRate() > biggest->refreshRate()) {
            biggest = mode;
            continue;
        }

        total = area;
        biggest = mode;
    }

    return biggest;
}

KScreen::Output* Generator::biggestOutput(const KScreen::OutputList &outputs)
{
    int area, total = 0;
    KScreen::Output* biggest = 0;
    Q_FOREACH(KScreen::Output* output, outputs) {
        KScreen::Mode* mode = output->mode(output->preferredMode());
        area = mode->size().width() * mode->size().height();
        if (area < total) {
            continue;
        }

        total = area;
        biggest = output;
    }

    return biggest;
}

void Generator::disableAllDisconnectedOutputs(const KScreen::OutputList& outputs)
{
    Q_FOREACH(KScreen::Output* output, outputs) {
        if (!output->isConnected()) {
            output->setEnabled(false);
            output->setPrimary(false);
        }
    }
}

KScreen::Output* Generator::embeddedOutput(const KScreen::OutputList& outputs)
{
    Q_FOREACH(KScreen::Output* output, outputs) {
        if (!isEmbedded(output->name())) {
            continue;
        }

        return output;
    }

    return 0;
}

bool Generator::isLaptop()
{
    if (m_forceLaptop) {
        return true;
    }

    return Device::self()->isLaptop();
}

bool Generator::isLidClosed()
{
    if (m_forceLidClosed) {
        return true;
    }

    return Device::self()->isLidClosed();
}

bool Generator::isDocked()
{
    if (m_forceDocked) {
        return true;
    }

    return Device::self()->isDocked();
}

bool Generator::isEmbedded(const QString &name)
{
    QStringList embedded;
    embedded << "LVDS";
    embedded << "IDP";
    embedded << "EDP";

    Q_FOREACH(const QString &pre, embedded) {
        if (name.toUpper().startsWith(pre)) {
            return true;
        }
    }

    return false;
}

void Generator::setForceLaptop(bool force)
{
    m_forceLaptop = force;
}

void Generator::setForceLidClosed(bool force)
{
    m_forceLidClosed = force;
}

void Generator::setForceDocked(bool force)
{
    m_forceDocked = force;
}
<|endoftext|>


<commit_before>/**
 * Implementation of Jarvis March for convex hull
 * computation of a set of points in the 2d space.
 */

#ifndef jarvis_march_h
#define jarvis_march_h

#include "angle.hpp"
#include "point_concept.hpp"
#include "static_assert.hpp"

#include <algorithm>

namespace hull::algorithms::details {
    /**
     *
     */
    template <
        typename RandomIt,
        typename TPoint = typename RandomIt::value_type
    >
    TPoint max_jarvis_march(RandomIt first, RandomIt last, const TPoint& point_on_hull) {
        auto endpoint = point_on_hull;

        // Helper lambda to determine wheter sj is on the left of line pi to endpoint
        auto is_on_the_left = [&endpoint, &point_on_hull](const auto& sj) {
            const auto res = cross(point_on_hull, endpoint, sj);

            // If they are collinear, we take the farthest point from pi
            if (hull::equals(res, static_cast<decltype(res)>(0))) {
                return hull::square_norm(sj - point_on_hull) > hull::square_norm(endpoint - point_on_hull);
            }

            return res > 0;
        };

        std::for_each(first, last, [&endpoint, &point_on_hull, is_on_the_left](const auto& sj) {
            // if (endpoint == pointOnHull) or (S[j] is on left of line from P[i] to endpoint)
            if (hull::equals(endpoint, point_on_hull) || is_on_the_left(sj)) {
                // found greater left turn, update endpoint
                endpoint = sj;
            }
        });

        return endpoint;
    }
}

namespace hull::algorithms {
    /**
     * Compute the convex hull of a container of points following
     * the Jarvis March algorithm.
     * Average time complexity: O(N * H) where N is the number of input
     * points and H the number of points on the convex hull.
     * Average space complexity: O(N + H).
     * Reference: https://en.wikipedia.org/wiki/Gift_wrapping_algorithm
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @return - the iterator to the last element forming the convex hull of the
     *           provided container of points.
     */
    template <typename RandomIt1, typename RandomIt2>
    RandomIt2 jarvis_march(RandomIt1 first, RandomIt1 last, RandomIt2 first2) {
        static_assert_is_random_access_iterator_to_point<RandomIt1>();
        static_assert_is_random_access_iterator_to_point<RandomIt2>();

        const auto N = std::distance(first, last);
        if (N <= 1) {
            return std::copy(first, last, first2);
        }

        // leftmost point
        const auto min_x = std::min_element(first, last, [](const auto& p1, const auto& p2) {
            return x(p1) < x(p2) || (x(p1) == x(p2) && y(p1) > y(p2));
        });
        auto point_on_hull = *min_x;
        decltype(point_on_hull) endpoint;

        // Helper lambda to determine wheter sj is on the left of line pi to endpoint
        auto is_on_the_left = [&endpoint](const auto& pi, const auto& sj) {
            const auto res = cross(pi, endpoint, sj);

            // If they are collinear, we take the farthest point from pi
            if (hull::equals(res, static_cast<decltype(res)>(0))) {
                return hull::square_norm(sj - pi) > hull::square_norm(endpoint - pi);
            }

            return res > 0;
        };

        // Repeat until wrapped around to first hull point
        std::size_t i{};
        do {
            // P[i] = pointOnHull
            *(first2 + i) = point_on_hull;

            // initial endpoint for a candidate edge on the hull
            endpoint = *first2;

            // for j from 1 to |S|
            std::for_each(first, last, [&endpoint, &point_on_hull, is_on_the_left](const auto& sj) {
                // if (endpoint == pointOnHull) or (S[j] is on left of line from P[i] to endpoint)
                if (hull::equals(endpoint, point_on_hull) || is_on_the_left(point_on_hull, sj)) {
                    // found greater left turn, update endpoint
                    endpoint = sj;
                }
            });

            i++;
            point_on_hull = endpoint;
        }
        while (!hull::equals(endpoint, *first2));

        return first2 + i;
    }
}

namespace hull {
    /**
     * Compile-time enumeration to choose the
     * algorithm thanks to a policy approach.
     * @param jarvis_march_t - Jarvis March algorithm.
     */
    struct jarvis_march_t {};

    /**
     * Algorithms policies to choose an overload.
     * @param jarvis_march - Jarvis March algorithm.
     */
    namespace choice {
        static constexpr const jarvis_march_t jarvis_march{};
    }

    /**
     * Overload of iterator-based convex hull computation for Jarvis March.
     * Average time complexity: O(N * H) where N is the number of input
     * points and H is the number of points on the convex hull.
     * Average space complexity: O(2 * N).
     * It is unfortunately not possible to use a std::back_insert_iterator.
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @return - the iterator to the last element forming the convex hull of the
     *           destination container of points.
     */
    template <typename RandomIt1, typename RandomIt2>
    auto compute_convex_hull(jarvis_march_t policy, RandomIt1 first, RandomIt1 last, RandomIt2 first2) {
        using value_type = typename std::iterator_traits<RandomIt2>::value_type;
        std::fill_n(first2, std::distance(first, last), value_type{});

        return algorithms::jarvis_march(first, last, first2);
    }

    namespace convex {
        /**
         * Overload of container-based convex hull computation for Jarvis March.
         * Average time complexity: O(N * H) where N is the number of input
         * points and H is the number of points on the convex hull.
         * Average space complexity: O(2 * N).
         * @param c1 - the input container.
         * @param c2 - the destination container.
         */
        template <typename TContainer1, typename TContainer2>
        void compute(jarvis_march_t policy, const TContainer1& c1, TContainer2& c2) {
            c2.resize(c1.size());

            std::fill(std::begin(c2), std::end(c2), typename TContainer2::value_type{});
            auto last = hull::algorithms::jarvis_march(std::begin(c1), std::end(c1), std::begin(c2));

            c2.erase(last, std::end(c2));
        }
    }
}

#endif
<commit_msg>Start refactoring Jarvis March's algorithm.<commit_after>/**
 * Implementation of Jarvis March for convex hull
 * computation of a set of points in the 2d space.
 */

#ifndef jarvis_march_h
#define jarvis_march_h

#include "angle.hpp"
#include "point_concept.hpp"
#include "static_assert.hpp"

#include <algorithm>

namespace hull::algorithms::details::jarvis {
    /**
     * Create a lambda which tells whether a given point
     * sj is on the left of the vector p0p1.
     * @param p0 - the first point of the vector.
     * @param p1 - the second point of the vector.
     * @return - a lambda function which takes a point sj
     *           and returns true if this point is on the
     *           left of the vector p0p1.
     */
    template <typename TPoint>
    auto is_on_the_left(const TPoint& p0, const TPoint& p1) {
        return [&p0, &p1](const auto& sj) {
            const auto res = cross(p0, p1, sj);

            // If they are collinear, we take the farthest point from pi
            if (hull::equals(res, static_cast<decltype(res)>(0))) {
                return hull::square_norm(sj - p0) > hull::square_norm(p1 - p0);
            }

            return res > 0;
        };
    }
}

namespace hull::algorithms::details {
    /**
     *
     */
    template <
        typename RandomIt,
        typename TPoint = typename RandomIt::value_type
    >
    TPoint max_jarvis_march(RandomIt first, RandomIt last, const TPoint& point_on_hull) {
        auto endpoint = point_on_hull;

        // Helper lambda to determine wheter sj is on the left of line pi to endpoint
        auto is_on_the_left = jarvis::is_on_the_left(point_on_hull, endpoint);

        std::for_each(first, last, [&endpoint, &point_on_hull, is_on_the_left](const auto& sj) {
            // if (endpoint == pointOnHull) or (S[j] is on left of line from P[i] to endpoint)
            if (hull::equals(endpoint, point_on_hull) || is_on_the_left(sj)) {
                // found greater left turn, update endpoint
                endpoint = sj;
            }
        });

        return endpoint;
    }
}

namespace hull::algorithms {
    /**
     * Compute the convex hull of a container of points following
     * the Jarvis March algorithm.
     * Average time complexity: O(N * H) where N is the number of input
     * points and H the number of points on the convex hull.
     * Average space complexity: O(N + H).
     * Reference: https://en.wikipedia.org/wiki/Gift_wrapping_algorithm
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @return - the iterator to the last element forming the convex hull of the
     *           provided container of points.
     */
    template <typename RandomIt1, typename RandomIt2>
    RandomIt2 jarvis_march(RandomIt1 first, RandomIt1 last, RandomIt2 first2) {
        static_assert_is_random_access_iterator_to_point<RandomIt1>();
        static_assert_is_random_access_iterator_to_point<RandomIt2>();

        const auto N = std::distance(first, last);
        if (N <= 1) {
            return std::copy(first, last, first2);
        }

        // leftmost point
        const auto min_x = std::min_element(first, last, [](const auto& p1, const auto& p2) {
            return x(p1) < x(p2) || (x(p1) == x(p2) && y(p1) > y(p2));
        });
        auto point_on_hull = *min_x;
        decltype(point_on_hull) endpoint;

        // Repeat until wrapped around to first hull point
        std::size_t i{};
        do {
            // P[i] = pointOnHull
            *(first2 + i) = point_on_hull;

            point_on_hull = details::max_jarvis_march(first, last, point_on_hull);

            i++;
        }
        while (!hull::equals(point_on_hull, *first2));

        return first2 + i;
    }
}

namespace hull {
    /**
     * Compile-time enumeration to choose the
     * algorithm thanks to a policy approach.
     * @param jarvis_march_t - Jarvis March algorithm.
     */
    struct jarvis_march_t {};

    /**
     * Algorithms policies to choose an overload.
     * @param jarvis_march - Jarvis March algorithm.
     */
    namespace choice {
        static constexpr const jarvis_march_t jarvis_march{};
    }

    /**
     * Overload of iterator-based convex hull computation for Jarvis March.
     * Average time complexity: O(N * H) where N is the number of input
     * points and H is the number of points on the convex hull.
     * Average space complexity: O(2 * N).
     * It is unfortunately not possible to use a std::back_insert_iterator.
     * @param first - the random access iterator to the first point of the container.
     * @param last - the random access iterator to the one-past last point of the container.
     * @param first2 - the random access iterator to the first point of the destination container.
     * @return - the iterator to the last element forming the convex hull of the
     *           destination container of points.
     */
    template <typename RandomIt1, typename RandomIt2>
    auto compute_convex_hull(jarvis_march_t policy, RandomIt1 first, RandomIt1 last, RandomIt2 first2) {
        using value_type = typename std::iterator_traits<RandomIt2>::value_type;
        std::fill_n(first2, std::distance(first, last), value_type{});

        return algorithms::jarvis_march(first, last, first2);
    }

    namespace convex {
        /**
         * Overload of container-based convex hull computation for Jarvis March.
         * Average time complexity: O(N * H) where N is the number of input
         * points and H is the number of points on the convex hull.
         * Average space complexity: O(2 * N).
         * @param c1 - the input container.
         * @param c2 - the destination container.
         */
        template <typename TContainer1, typename TContainer2>
        void compute(jarvis_march_t policy, const TContainer1& c1, TContainer2& c2) {
            c2.resize(c1.size());

            std::fill(std::begin(c2), std::end(c2), typename TContainer2::value_type{});
            auto last = hull::algorithms::jarvis_march(std::begin(c1), std::end(c1), std::begin(c2));

            c2.erase(last, std::end(c2));
        }
    }
}

#endif
<|endoftext|>


<commit_before>/**
 * @file noise.cpp
 * @brief Perlin noise routines for procedural textures, etc
 *
 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "noise.h"

#include "llrand.h"

// static
#define B 0x100
S32 p[B + B + 2];
F32 g3[B + B + 2][3];
F32 g2[B + B + 2][2];
F32 g1[B + B + 2];
S32 gNoiseStart = 1;

F32 noise2(F32 *vec)
{
	U8 bx0, bx1, by0, by1;
	U32 b00, b10, b01, b11;
	F32 rx0, rx1, ry0, ry1, *q, sx, sy, a, b, u, v;
	S32 i, j;

	if (gNoiseStart) {
		gNoiseStart = 0;
		init();
	}

	fast_setup(*vec, bx0, bx1, rx0, rx1);
	fast_setup(*(vec + 1), by0, by1, ry0, ry1);

	i = *(p + bx0);
	j = *(p + bx1);

	b00 = *(p + i + by0);
	b10 = *(p + j + by0);
	b01 = *(p + i + by1);
	b11 = *(p + j + by1);

	sx = s_curve(rx0);
	sy = s_curve(ry0);

	q = *(g2 + b00);
	u = fast_at2(rx0, ry0, q);
	q = *(g2 + b10);
	v = fast_at2(rx1, ry0, q);
	a = lerp_m(sx, u, v);

	q = *(g2 + b01);
	u = fast_at2(rx0,ry1,q);
	q = *(g2 + b11);
	v = fast_at2(rx1,ry1,q);
	b = lerp_m(sx, u, v);

	return lerp_m(sy, a, b);
}

<commit_msg>dummy whitespace change<commit_after>/**
 * @file noise.cpp
 * @brief Perlin noise routines for procedural textures, etc
 *
 * $LicenseInfo:firstyear=2000&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "noise.h"

#include "llrand.h"

// static
#define B 0x100
S32 p[B + B + 2];
F32 g3[B + B + 2][3];
F32 g2[B + B + 2][2];
F32 g1[B + B + 2];
S32 gNoiseStart = 1;

F32 noise2(F32 *vec)
{
	U8 bx0, bx1, by0, by1;
	U32 b00, b10, b01, b11;
	F32 rx0, rx1, ry0, ry1, *q, sx, sy, a, b, u, v;
	S32 i, j;

	if (gNoiseStart) {
		gNoiseStart = 0;
		init();
	}

	fast_setup(*vec, bx0, bx1, rx0, rx1);
	fast_setup(*(vec + 1), by0, by1, ry0, ry1);

	i = *(p + bx0);
	j = *(p + bx1);

	b00 = *(p + i + by0);
	b10 = *(p + j + by0);
	b01 = *(p + i + by1);
	b11 = *(p + j + by1);

	sx = s_curve(rx0);
	sy = s_curve(ry0);

	q = *(g2 + b00);
	u = fast_at2(rx0, ry0, q);
	q = *(g2 + b10);
	v = fast_at2(rx1, ry0, q);
	a = lerp_m(sx, u, v);

	q = *(g2 + b01);
	u = fast_at2(rx0,ry1,q);
	q = *(g2 + b11);
	v = fast_at2(rx1,ry1,q);
	b = lerp_m(sx, u, v);

	return lerp_m(sy, a, b);
}

<|endoftext|>


<commit_before>#include "CameraForm.h"
#include "Object.h"
#include "Director.h"

using namespace Math;
using namespace std;
using namespace Rendering;
using namespace Rendering::Buffer;
using namespace Rendering::Light;
using namespace Intersection;
using namespace Device;
using namespace Core;
using namespace Rendering::Camera;
using namespace Rendering::Manager;

CameraForm::CameraForm(Usage usage)
	: Component(), _frustum(nullptr), _renderTarget(nullptr), _camMatConstBuffer(nullptr), _usage(usage),
		_camCBChangeState(TransformCB::ChangeState::No)
{
	Matrix::Identity(_prevViewProjMat);
}

CameraForm::~CameraForm(void)
{
	Destroy();
}

void CameraForm::Initialize(const Math::Rect<float>& renderRect)
{
	_fieldOfViewDegree	= 45.0f;
	_clippingNear		= 0.1f;
	_clippingFar		= 1000.0f;

	const Size<unsigned int>& backBufferSize = Director::SharedInstance()->GetBackBufferSize();
	_aspect = (float)backBufferSize.w / (float)backBufferSize.h;

	_projectionType    = ProjectionType::Perspective;
	_clearColor = Color(0.5f, 0.5f, 1.0f, 1.0f);

	_frustum = new Frustum(0.0f);

	_renderTarget = new Texture::RenderTexture;
	_renderTarget->Initialize(backBufferSize, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, 0, 0);

	//_clearFlag = ClearFlag::FlagSolidColor;
	_renderRect = renderRect;

	_camMatConstBuffer = new ConstBuffer;
	_camMatConstBuffer->Initialize(sizeof(CameraCBData));

	Device::Director::SharedInstance()->GetCurrentScene()->GetCameraManager()->Add(this);
}

void CameraForm::Destroy()
{
	SAFE_DELETE(_frustum);
	SAFE_DELETE(_renderTarget);
	SAFE_DELETE(_camMatConstBuffer);
}

void CameraForm::CalcAspect()
{
	const Size<unsigned int>& backBufferSize =  Device::Director::SharedInstance()->GetBackBufferSize();
	_aspect = (float)backBufferSize.w / (float)backBufferSize.h;
}

void CameraForm::GetPerspectiveMatrix(Math::Matrix &outMatrix, bool isInverted) const
{
	float fovRadian = Math::Common::Deg2Rad(_fieldOfViewDegree);

	float clippingNear	= _clippingNear;
	float clippingFar	= _clippingFar;

	if(isInverted)
	{
		clippingNear	= _clippingFar;
		clippingFar		= _clippingNear;
	}

	Matrix::PerspectiveFovLH(outMatrix, _aspect, fovRadian, clippingNear, clippingFar);
}

void CameraForm::GetOrthogonalMatrix(Math::Matrix &outMatrix, bool isInverted, const Math::Size<uint>* customWH) const
{
	const Size<uint>& wh = customWH ? (*customWH) : Device::Director::SharedInstance()->GetBackBufferSize();

	float clippingNear	= _clippingNear;
	float clippingFar	= _clippingFar;

	if(isInverted)
	{
		clippingNear	= _clippingFar;
		clippingFar		= _clippingNear;
	}

	Matrix::OrthoLH(outMatrix, (float)(wh.w), (float)(wh.h), clippingNear, clippingFar);
}

void CameraForm::GetProjectionMatrix(Math::Matrix& outMatrix, bool isInverted) const
{
	if(_projectionType == ProjectionType::Perspective)
		GetPerspectiveMatrix(outMatrix, isInverted);
	else if(_projectionType == ProjectionType::Orthographic)
		GetOrthogonalMatrix(outMatrix, isInverted);
}

void CameraForm::GetViewMatrix(Math::Matrix &outMatrix, const Math::Matrix &worldMatrix)
{
	outMatrix = worldMatrix;

	Vector3 worldPos;
	worldPos.x = worldMatrix._41;
	worldPos.y = worldMatrix._42;
	worldPos.z = worldMatrix._43;

	Math::Vector3 right		= Math::Vector3(worldMatrix._11, worldMatrix._21, worldMatrix._31);
	Math::Vector3 up		= Math::Vector3(worldMatrix._12, worldMatrix._22, worldMatrix._32);
	Math::Vector3 forward	= Math::Vector3(worldMatrix._13, worldMatrix._23, worldMatrix._33);

	Vector3 p;
	p.x = -Vector3::Dot(right,		worldPos);
	p.y = -Vector3::Dot(up,			worldPos);
	p.z = -Vector3::Dot(forward,	worldPos);

	outMatrix._41 = p.x;
	outMatrix._42 = p.y;
	outMatrix._43 = p.z;
	outMatrix._44 = 1.0f;
}

void CameraForm::GetViewMatrix(Math::Matrix& outMatrix) const
{
	Matrix worldMat;
	_owner->GetTransform()->FetchWorldMatrix(worldMat);

	GetViewMatrix(outMatrix, worldMat);
}

void CameraForm::GetViewportMatrix(Math::Matrix& outMat, const Math::Rect<float>& rect)
{
	outMat._11 = rect.size.w /  2.0f;
	outMat._12 = 0.0f;
	outMat._13 = 0.0f;
	outMat._14 = 0.0f;

	outMat._21 = 0.0f;
	outMat._22 = -rect.size.h / 2.0f;
	outMat._23 = 0.0f;
	outMat._24 = 0.0f;

	outMat._31 = 0.0f;
	outMat._32 = 0.0f;
	outMat._33 = 1.0f;
	outMat._34 = 0.0f;

	outMat._41 = rect.x + rect.size.w / 2.0f;
	outMat._42 = rect.y + rect.size.h / 2.0f;
	outMat._43 = 0.0f;
	outMat._44 = 1.0f;
}

void CameraForm::GetInvViewportMatrix(Math::Matrix& outMat, const Math::Rect<float>& rect)
{
	Math::Matrix viewportMat;
	GetViewportMatrix(viewportMat, rect);

	Math::Matrix::Inverse(outMat, viewportMat);
}

void CameraForm::CullingWithUpdateCB(const Device::DirectX* dx, const std::vector<Core::Object*>& objects, const LightManager* lightManager)
{
	Matrix worldMat;
	_owner->GetTransform()->FetchWorldMatrix(worldMat);

	CameraCBData cbData;
	{
		Matrix& viewMat = cbData.viewMat;
		GetViewMatrix(cbData.viewMat, worldMat);

		Matrix projMat;
		GetProjectionMatrix(projMat, true);
		cbData.viewProjMat = viewMat * projMat;
	}

	bool isChanged = (cbData.viewProjMat != _prevViewProjMat);
	if(isChanged)
	{
		// Make Frustum
		{
			Matrix notInvProj;
			GetProjectionMatrix(notInvProj, false);
			_frustum->Make(cbData.viewMat * notInvProj);
		}

		_camCBChangeState = TransformCB::ChangeState::HasChanged;
	}

	bool isUpdate = (_camCBChangeState != TransformCB::ChangeState::No);

	if(isUpdate)
	{
		cbData.worldPos = Vector4(worldMat._41, worldMat._42, worldMat._43, 1.0f);
		cbData.prevViewProjMat = _prevViewProjMat;

		_prevViewProjMat = cbData.viewProjMat;

		Matrix::Transpose(cbData.viewMat, cbData.viewMat);
		Matrix::Transpose(cbData.viewProjMat, cbData.viewProjMat);
		Matrix::Transpose(cbData.prevViewProjMat, cbData.prevViewProjMat);

		_camMatConstBuffer->UpdateSubResource(dx->GetContext(), &cbData);

		_camCBChangeState = (static_cast<uint>(_camCBChangeState) + 1) % static_cast<uint>(TransformCB::ChangeState::MAX);
	}

	for(auto iter = objects.begin(); iter != objects.end(); ++iter)
		(*iter)->Culling(_frustum);
}

void CameraForm::SortTransparentMeshRenderQueue(RenderQueue& inoutTranparentMeshQ, const Transform* ownerTF, const RenderManager* renderMgr)
{
	const RenderManager::MeshList& transparentList = renderMgr->GetTransparentMeshes();
	if( transparentList.updateCounter != inoutTranparentMeshQ.updateCounter )
	{
		const auto& transparentMeshAddrSet = transparentList.meshes.GetVector();
		auto& thisCamMeshes = inoutTranparentMeshQ.meshes;

		thisCamMeshes.clear();
		for(auto addrSetIter = transparentMeshAddrSet.begin();
			addrSetIter != transparentMeshAddrSet.end(); ++addrSetIter)
		{
			for(auto iter = addrSetIter->begin(); iter != addrSetIter->end(); ++iter)
			{
				RenderManager::MeshList::meshkey addr = *iter;

				const Geometry::Mesh* mesh = reinterpret_cast<const Geometry::Mesh*>(addr);
				thisCamMeshes.push_back(mesh);
			}
		}

		inoutTranparentMeshQ.updateCounter = transparentList.updateCounter;
	}

	Math::Vector3 camPos;
	ownerTF->FetchWorldPosition(camPos);

	auto SortingByDistance = [&](const Geometry::Mesh*& left, const Geometry::Mesh*& right) -> bool
	{
		float leftDistance = D3D11_FLOAT32_MAX;
		{
			Math::Vector3 leftPos;
			left->GetOwner()->GetTransform()->FetchWorldPosition(leftPos);
			leftDistance = Math::Vector3::Distance(leftPos, camPos);
		}

		float rightDistance = D3D11_FLOAT32_MAX;
		{
			Math::Vector3 rightPos;
			right->GetOwner()->GetTransform()->FetchWorldPosition(rightPos);
			rightDistance = Math::Vector3::Distance(rightPos, camPos);
		}

		return leftDistance < rightDistance;
	};

	std::sort(inoutTranparentMeshQ.meshes.begin(), inoutTranparentMeshQ.meshes.end(), SortingByDistance);
}

void CameraForm::_Clone(CameraForm* newCam) const
{
	memcpy(newCam, this, sizeof(CameraForm));

	newCam->_frustum		= new Frustum(0.0f);
	newCam->_renderTarget	= new Texture::RenderTexture;
	{
		const Size<unsigned int>& size = Director::SharedInstance()->GetBackBufferSize();

		D3D11_TEXTURE2D_DESC desc;
		newCam->_renderTarget->GetTexture()->GetDesc(&desc);
		newCam->_renderTarget->Initialize(size, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, desc.BindFlags, desc.SampleDesc.Count);
	}
}
<commit_msg>CameraForm.cpp - CullingWithUpdateCB return 추가<commit_after>#include "CameraForm.h"
#include "Object.h"
#include "Director.h"

using namespace Math;
using namespace std;
using namespace Rendering;
using namespace Rendering::Buffer;
using namespace Rendering::Light;
using namespace Intersection;
using namespace Device;
using namespace Core;
using namespace Rendering::Camera;
using namespace Rendering::Manager;

CameraForm::CameraForm(Usage usage)
	: Component(), _frustum(nullptr), _renderTarget(nullptr), _camMatConstBuffer(nullptr), _usage(usage),
		_camCBChangeState(TransformCB::ChangeState::No)
{
	Matrix::Identity(_prevViewProjMat);
}

CameraForm::~CameraForm(void)
{
	Destroy();
}

void CameraForm::Initialize(const Math::Rect<float>& renderRect)
{
	_fieldOfViewDegree	= 45.0f;
	_clippingNear		= 0.1f;
	_clippingFar		= 1000.0f;

	const Size<unsigned int>& backBufferSize = Director::SharedInstance()->GetBackBufferSize();
	_aspect = (float)backBufferSize.w / (float)backBufferSize.h;

	_projectionType    = ProjectionType::Perspective;
	_clearColor = Color(0.5f, 0.5f, 1.0f, 1.0f);

	_frustum = new Frustum(0.0f);

	_renderTarget = new Texture::RenderTexture;
	_renderTarget->Initialize(backBufferSize, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, 0, 0);

	//_clearFlag = ClearFlag::FlagSolidColor;
	_renderRect = renderRect;

	_camMatConstBuffer = new ConstBuffer;
	_camMatConstBuffer->Initialize(sizeof(CameraCBData));

	Device::Director::SharedInstance()->GetCurrentScene()->GetCameraManager()->Add(this);
}

void CameraForm::Destroy()
{
	SAFE_DELETE(_frustum);
	SAFE_DELETE(_renderTarget);
	SAFE_DELETE(_camMatConstBuffer);
}

void CameraForm::CalcAspect()
{
	const Size<unsigned int>& backBufferSize =  Device::Director::SharedInstance()->GetBackBufferSize();
	_aspect = (float)backBufferSize.w / (float)backBufferSize.h;
}

void CameraForm::GetPerspectiveMatrix(Math::Matrix &outMatrix, bool isInverted) const
{
	float fovRadian = Math::Common::Deg2Rad(_fieldOfViewDegree);

	float clippingNear	= _clippingNear;
	float clippingFar	= _clippingFar;

	if(isInverted)
	{
		clippingNear	= _clippingFar;
		clippingFar		= _clippingNear;
	}

	Matrix::PerspectiveFovLH(outMatrix, _aspect, fovRadian, clippingNear, clippingFar);
}

void CameraForm::GetOrthogonalMatrix(Math::Matrix &outMatrix, bool isInverted, const Math::Size<uint>* customWH) const
{
	const Size<uint>& wh = customWH ? (*customWH) : Device::Director::SharedInstance()->GetBackBufferSize();

	float clippingNear	= _clippingNear;
	float clippingFar	= _clippingFar;

	if(isInverted)
	{
		clippingNear	= _clippingFar;
		clippingFar		= _clippingNear;
	}

	Matrix::OrthoLH(outMatrix, (float)(wh.w), (float)(wh.h), clippingNear, clippingFar);
}

void CameraForm::GetProjectionMatrix(Math::Matrix& outMatrix, bool isInverted) const
{
	if(_projectionType == ProjectionType::Perspective)
		GetPerspectiveMatrix(outMatrix, isInverted);
	else if(_projectionType == ProjectionType::Orthographic)
		GetOrthogonalMatrix(outMatrix, isInverted);
}

void CameraForm::GetViewMatrix(Math::Matrix &outMatrix, const Math::Matrix &worldMatrix)
{
	outMatrix = worldMatrix;

	Vector3 worldPos;
	worldPos.x = worldMatrix._41;
	worldPos.y = worldMatrix._42;
	worldPos.z = worldMatrix._43;

	Math::Vector3 right		= Math::Vector3(worldMatrix._11, worldMatrix._21, worldMatrix._31);
	Math::Vector3 up		= Math::Vector3(worldMatrix._12, worldMatrix._22, worldMatrix._32);
	Math::Vector3 forward	= Math::Vector3(worldMatrix._13, worldMatrix._23, worldMatrix._33);

	Vector3 p;
	p.x = -Vector3::Dot(right,		worldPos);
	p.y = -Vector3::Dot(up,			worldPos);
	p.z = -Vector3::Dot(forward,	worldPos);

	outMatrix._41 = p.x;
	outMatrix._42 = p.y;
	outMatrix._43 = p.z;
	outMatrix._44 = 1.0f;
}

void CameraForm::GetViewMatrix(Math::Matrix& outMatrix) const
{
	Matrix worldMat;
	_owner->GetTransform()->FetchWorldMatrix(worldMat);

	GetViewMatrix(outMatrix, worldMat);
}

void CameraForm::GetViewportMatrix(Math::Matrix& outMat, const Math::Rect<float>& rect)
{
	outMat._11 = rect.size.w /  2.0f;
	outMat._12 = 0.0f;
	outMat._13 = 0.0f;
	outMat._14 = 0.0f;

	outMat._21 = 0.0f;
	outMat._22 = -rect.size.h / 2.0f;
	outMat._23 = 0.0f;
	outMat._24 = 0.0f;

	outMat._31 = 0.0f;
	outMat._32 = 0.0f;
	outMat._33 = 1.0f;
	outMat._34 = 0.0f;

	outMat._41 = rect.x + rect.size.w / 2.0f;
	outMat._42 = rect.y + rect.size.h / 2.0f;
	outMat._43 = 0.0f;
	outMat._44 = 1.0f;
}

void CameraForm::GetInvViewportMatrix(Math::Matrix& outMat, const Math::Rect<float>& rect)
{
	Math::Matrix viewportMat;
	GetViewportMatrix(viewportMat, rect);

	Math::Matrix::Inverse(outMat, viewportMat);
}

bool CameraForm::CullingWithUpdateCB(const Device::DirectX* dx, const std::vector<Core::Object*>& objects, const LightManager* lightManager)
{
	Matrix worldMat;
	_owner->GetTransform()->FetchWorldMatrix(worldMat);

	CameraCBData cbData;
	{
		Matrix& viewMat = cbData.viewMat;
		GetViewMatrix(cbData.viewMat, worldMat);

		Matrix projMat;
		GetProjectionMatrix(projMat, true);
		cbData.viewProjMat = viewMat * projMat;
	}

	bool isChanged = (cbData.viewProjMat != _prevViewProjMat);
	if(isChanged)
	{
		// Make Frustum
		{
			Matrix notInvProj;
			GetProjectionMatrix(notInvProj, false);
			_frustum->Make(cbData.viewMat * notInvProj);
		}

		_camCBChangeState = TransformCB::ChangeState::HasChanged;
	}

	bool isUpdate = (_camCBChangeState != TransformCB::ChangeState::No);

	if(isUpdate)
	{
		cbData.worldPos = Vector4(worldMat._41, worldMat._42, worldMat._43, 1.0f);
		cbData.prevViewProjMat = _prevViewProjMat;

		_prevViewProjMat = cbData.viewProjMat;

		Matrix::Transpose(cbData.viewMat, cbData.viewMat);
		Matrix::Transpose(cbData.viewProjMat, cbData.viewProjMat);
		Matrix::Transpose(cbData.prevViewProjMat, cbData.prevViewProjMat);

		_camMatConstBuffer->UpdateSubResource(dx->GetContext(), &cbData);

		_camCBChangeState = (static_cast<uint>(_camCBChangeState) + 1) % static_cast<uint>(TransformCB::ChangeState::MAX);
	}

	for(auto iter = objects.begin(); iter != objects.end(); ++iter)
		(*iter)->Culling(_frustum);

	return isUpdate;
}

void CameraForm::SortTransparentMeshRenderQueue(RenderQueue& inoutTranparentMeshQ, const Transform* ownerTF, const RenderManager* renderMgr)
{
	const RenderManager::MeshList& transparentList = renderMgr->GetTransparentMeshes();
	if( transparentList.updateCounter != inoutTranparentMeshQ.updateCounter )
	{
		const auto& transparentMeshAddrSet = transparentList.meshes.GetVector();
		auto& thisCamMeshes = inoutTranparentMeshQ.meshes;

		thisCamMeshes.clear();
		for(auto addrSetIter = transparentMeshAddrSet.begin();
			addrSetIter != transparentMeshAddrSet.end(); ++addrSetIter)
		{
			for(auto iter = addrSetIter->begin(); iter != addrSetIter->end(); ++iter)
			{
				RenderManager::MeshList::meshkey addr = *iter;

				const Geometry::Mesh* mesh = reinterpret_cast<const Geometry::Mesh*>(addr);
				thisCamMeshes.push_back(mesh);
			}
		}

		inoutTranparentMeshQ.updateCounter = transparentList.updateCounter;
	}

	Math::Vector3 camPos;
	ownerTF->FetchWorldPosition(camPos);

	auto SortingByDistance = [&](const Geometry::Mesh*& left, const Geometry::Mesh*& right) -> bool
	{
		float leftDistance = D3D11_FLOAT32_MAX;
		{
			Math::Vector3 leftPos;
			left->GetOwner()->GetTransform()->FetchWorldPosition(leftPos);
			leftDistance = Math::Vector3::Distance(leftPos, camPos);
		}

		float rightDistance = D3D11_FLOAT32_MAX;
		{
			Math::Vector3 rightPos;
			right->GetOwner()->GetTransform()->FetchWorldPosition(rightPos);
			rightDistance = Math::Vector3::Distance(rightPos, camPos);
		}

		return leftDistance < rightDistance;
	};

	std::sort(inoutTranparentMeshQ.meshes.begin(), inoutTranparentMeshQ.meshes.end(), SortingByDistance);
}

void CameraForm::_Clone(CameraForm* newCam) const
{
	memcpy(newCam, this, sizeof(CameraForm));

	newCam->_frustum		= new Frustum(0.0f);
	newCam->_renderTarget	= new Texture::RenderTexture;
	{
		const Size<unsigned int>& size = Director::SharedInstance()->GetBackBufferSize();

		D3D11_TEXTURE2D_DESC desc;
		newCam->_renderTarget->GetTexture()->GetDesc(&desc);
		newCam->_renderTarget->Initialize(size, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, desc.BindFlags, desc.SampleDesc.Count);
	}
}
<|endoftext|>


<commit_before>#include "topology.h"
#include "protocol.h"
#include "protocolfactory.h"
#include "e2egraph.h"
#include "network.h"
#include "parse.h"
#include <cmath>
#include <iostream>
#include <fstream>
#include <vector>
#include "p2psim.h"

using namespace std;

E2EGraph::E2EGraph(vector<string> *v)
{
  _num = atoi((*v)[0].c_str());
  assert(_num > 0);

  _pairwise.resize(_num);
  for (unsigned int i = 0; i < _num; i++)
    _pairwise[i].resize(_num);
}

E2EGraph::~E2EGraph()
{
}

latency_t
E2EGraph::latency(IPAddress ip1, IPAddress ip2)
{
  //we can not use random ip address for e2egraph now
  assert(ip1 > 0 && ip1 <= _num);
  assert(ip2 > 0 && ip2 <= _num);
  return (latency_t) _pairwise[ip1-1][ip2-1];
}

void
E2EGraph::parse(ifstream &ifs)
{
  string line;

  while(getline(ifs,line)) {
    vector<string> words = split(line);

    // skip empty lines and commented lines
    if(words.empty() || words[0][0] == '#')
      continue;

    // XXX Thomer:  The else clause also seems
    // to expect 2 words per line?
    if (words.size() >= 2) {
      IPAddress ipaddr = atoi(words[0].c_str());
      assert(ipaddr > 0 && ipaddr <= _num);

      // what kind of node?
      Node *n = new Node(ipaddr);

      // add the node to the network
      send(Network::Instance()->nodechan(), &n);

    } else {

      // x,y coordinates
      vector<string> pair = split(words[0], ",");
      IPAddress ip1 = atoi(pair[0].c_str());
      IPAddress ip2 = atoi(pair[1].c_str());
      assert(ip1>0 && ip1 <= _num);
      assert(ip2>0 && ip2 <= _num);

      int lat = atoi(words[1].c_str());
      if (lat < 0) {
	lat = 0;
      }
      // latency between node1 and node2
      _pairwise[ip1 -1][ip2 -1] = (latency_t) lat;
    }
  }
}
<commit_msg>make file format consistent<commit_after>#include "topology.h"
#include "protocol.h"
#include "protocolfactory.h"
#include "e2egraph.h"
#include "network.h"
#include "parse.h"
#include <cmath>
#include <iostream>
#include <fstream>
#include <vector>
#include "p2psim.h"

using namespace std;

E2EGraph::E2EGraph(vector<string> *v)
{
  _num = atoi((*v)[0].c_str());
  assert(_num > 0);

  _pairwise.resize(_num);
  for (unsigned int i = 0; i < _num; i++)
    _pairwise[i].resize(_num);
}

E2EGraph::~E2EGraph()
{
}

latency_t
E2EGraph::latency(IPAddress ip1, IPAddress ip2)
{
  //we can not use random ip address for e2egraph now
  assert(ip1 > 0 && ip1 <= _num);
  assert(ip2 > 0 && ip2 <= _num);
  return (latency_t) _pairwise[ip1-1][ip2-1];
}

void
E2EGraph::parse(ifstream &ifs)
{
  string line;

  while(getline(ifs,line)) {
    vector<string> words = split(line);
    // skip empty lines and commented lines
    if(words.empty() || words[0][0] == '#')
      continue;

    // XXX Thomer:  The else clause also seems
    // to expect 2 words per line?
    if (words[0] == "node") {
      IPAddress ipaddr = atoi(words[1].c_str());
      assert(ipaddr > 0 && ipaddr <= _num);

      // what kind of node?
      Node *n = new Node(ipaddr);

      assert(!Network::Instance()->getnode(ipaddr));

      // add the node to the network
      send(Network::Instance()->nodechan(), &n);

    } else {

      // x,y coordinates
      vector<string> pair = split(words[0], ",");
      IPAddress ip1 = atoi(pair[0].c_str());
      IPAddress ip2 = atoi(pair[1].c_str());
      assert(ip1>0 && ip1 <= _num);
      assert(ip2>0 && ip2 <= _num);

      int lat = atoi(words[1].c_str());
      if (lat < 0) {
	lat = 0;
      }
      // latency between node1 and node2
      _pairwise[ip1 -1][ip2 -1] = (latency_t) lat;
    }
  }
}
<|endoftext|>