<commit_before>#include "Catch.hpp"

#include "RaZ/Utils/Ray.hpp"

namespace {

// Declaring rays to be tested
//
//        Ray 1      |       Ray 2       |      Ray 3
//                   |                   |
//          ^        |           ^       |      [ 1; 1 ]
//          |        |          /        |         /
//          |        |         /         |        /
//      [ 0; 0 ]     |    [ -1; -1 ]     |       v

const Raz::Ray ray1(Raz::Vec3f({ 0.f, 0.f, 0.f }), Raz::Axis::Y);
const Raz::Ray ray2(Raz::Vec3f({ -1.f, -1.f, 0.f }), Raz::Vec3f({ 1.f, 1.f, 0.f }).normalize());
const Raz::Ray ray3(Raz::Vec3f({ 1.f, 1.f, 0.f }), Raz::Vec3f({ -1.f, -1.f, 0.f }).normalize());

} // namespace

TEST_CASE("Ray-point intersection") {
  CHECK(ray1.intersects(ray1.getOrigin()));

  const Raz::Vec3f topPoint({ 0.f, 2.f, 0.f });
  const Raz::Vec3f topRightPoint({ 2.f, 2.f, 0.f });

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //        ^
  //        |
  //        x < [ 0; 0 ]
  CHECK(ray1.intersects(topPoint));
  CHECK_FALSE(ray1.intersects(topRightPoint));

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //          ^
  //         /
  //        x < [ 0; 0 ]
  CHECK_FALSE(ray2.intersects(topPoint));
  CHECK(ray2.intersects(topRightPoint));

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //             x < [ 1; 1 ]
  //            /
  //           v
  CHECK_FALSE(ray3.intersects(topPoint));
  CHECK_FALSE(ray3.intersects(topRightPoint));
}

TEST_CASE("Ray-sphere intersection") {
  const Raz::Sphere sphere1(Raz::Vec3f(0.f), 1.f);
  const Raz::Sphere sphere2(Raz::Vec3f({ 5.f, 10.f, 0.f }), 5.f);
  const Raz::Sphere sphere3(Raz::Vec3f({ -10.f, -10.f, 0.f }), 1.f);

  CHECK(ray1.intersects(sphere1));
  CHECK(ray2.intersects(sphere1));
  CHECK(ray3.intersects(sphere1));

  CHECK(ray1.intersects(sphere2));
  CHECK(ray2.intersects(sphere2));
  CHECK_FALSE(ray3.intersects(sphere2));

  CHECK_FALSE(ray1.intersects(sphere3));
  CHECK_FALSE(ray2.intersects(sphere3));
  CHECK(ray3.intersects(sphere3));
}

TEST_CASE("Ray-triangle intersection") {
  // These triangles are defined so that:
  //  - triangle1 is laying flat slightly above 0
  //  - triangle2 is standing, parallel to the Y/Z plane (facing the X direction)
  //  - triangle3 is crooked, its head pointing to [ -X; +Y ], slightly below 0
  const Raz::Triangle triangle1(Raz::Vec3f({ -3.f, 0.5f, 3.f }), Raz::Vec3f({ 0.f, 0.5f, -3.f }), Raz::Vec3f({ 3.f, 0.5f, 3.f }));
  const Raz::Triangle triangle2(Raz::Vec3f({ 0.5f, -0.5f, 3.f }), Raz::Vec3f({ 0.5f, -0.5f, -3.f }), Raz::Vec3f({ 0.5f, 3.f, 0.f }));
  const Raz::Triangle triangle3(Raz::Vec3f({ 0.f, -1.f, 1.f }), Raz::Vec3f({ -1.5f, -1.5f, 0.f }), Raz::Vec3f({ 0.f, -1.75f, -1.f }));

  CHECK(ray1.intersects(triangle1));
  CHECK(ray2.intersects(triangle1));
  CHECK(ray3.intersects(triangle1));

  CHECK_FALSE(ray1.intersects(triangle2));
  CHECK(ray2.intersects(triangle2));
  CHECK(ray3.intersects(triangle2));

  CHECK_FALSE(ray1.intersects(triangle3));
  CHECK_FALSE(ray2.intersects(triangle3));
  CHECK(ray3.intersects(triangle3));
}

TEST_CASE("Ray-AABB intersection") {
  //         _______________________
  //        /|                    /|
  //       / |                   / | / 1 -> [  1;  1; 1 ]
  //      |---------------------| < {  2 -> [  5;  5; 5 ]
  //      |  |                  |  | \ 3 -> [ -5; -5; 5 ]
  //      |  |                  |  |
  //      |  |                  |  |
  //      |  |                  |  |
  //      | /-------------------|-/
  //      |/ ^                  |/
  //      ---|-------------------
  //         |
  //  1 -> [  -1;  -1; -1 ]
  //  2 -> [   3;   3; -5 ]
  //  3 -> [ -10; -10; -5 ]

  const Raz::AABB aabb1(Raz::Vec3f(1.f), Raz::Vec3f(-1.f));
  const Raz::AABB aabb2(Raz::Vec3f(5.f), Raz::Vec3f({ 3.f, 3.f, -5.f }));
  const Raz::AABB aabb3(Raz::Vec3f({ -5.f, -5.f, 5.f }), Raz::Vec3f({ -10.f, -10.f, -5.f }));

  CHECK(ray1.intersects(aabb1));
  CHECK(ray2.intersects(aabb1));
  CHECK(ray3.intersects(aabb1));

  CHECK_FALSE(ray1.intersects(aabb2));
  CHECK(ray2.intersects(aabb2));
  CHECK_FALSE(ray3.intersects(aabb2));

  CHECK_FALSE(ray1.intersects(aabb3));
  CHECK_FALSE(ray2.intersects(aabb3));
  CHECK(ray3.intersects(aabb3));
}

TEST_CASE("Point projection") {
  const Raz::Vec3f topPoint({ 0.f, 2.f, 0.f });
  const Raz::Vec3f topRightPoint({ 2.f, 2.f, 0.f });

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //        ^
  //        |
  //        x < [ 0; 0 ]
  CHECK(ray1.computeProjection(topPoint) == topPoint);
  CHECK(ray1.computeProjection(topRightPoint) == topPoint);

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //          ^
  //         /
  //        x < [ 0; 0 ]
  CHECK(ray2.computeProjection(topPoint) == Raz::Vec3f({ 1.f, 1.f, 0.f }));
  CHECK(ray2.computeProjection(topRightPoint) == topRightPoint);

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //             x < [ 1; 1 ]
  //            /
  //           v
  CHECK(ray3.computeProjection(topPoint) == ray3.getOrigin());
  CHECK(ray3.computeProjection(topRightPoint) == ray3.getOrigin());
}
<commit_msg>[Tests/Ray] Added ray-plane intersection unit tests<commit_after>#include "Catch.hpp"

#include "RaZ/Utils/Ray.hpp"

namespace {

// Declaring rays to be tested
//
//        Ray 1      |       Ray 2       |      Ray 3
//                   |                   |
//          ^        |           ^       |      [ 1; 1 ]
//          |        |          /        |         /
//          |        |         /         |        /
//      [ 0; 0 ]     |    [ -1; -1 ]     |       v

const Raz::Ray ray1(Raz::Vec3f({ 0.f, 0.f, 0.f }), Raz::Axis::Y);
const Raz::Ray ray2(Raz::Vec3f({ -1.f, -1.f, 0.f }), Raz::Vec3f({ 1.f, 1.f, 0.f }).normalize());
const Raz::Ray ray3(Raz::Vec3f({ 1.f, 1.f, 0.f }), Raz::Vec3f({ -1.f, -1.f, 0.f }).normalize());

} // namespace

TEST_CASE("Ray-point intersection") {
  CHECK(ray1.intersects(ray1.getOrigin()));

  const Raz::Vec3f topPoint({ 0.f, 2.f, 0.f });
  const Raz::Vec3f topRightPoint({ 2.f, 2.f, 0.f });

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //        ^
  //        |
  //        x < [ 0; 0 ]
  CHECK(ray1.intersects(topPoint));
  CHECK_FALSE(ray1.intersects(topRightPoint));

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //          ^
  //         /
  //        x < [ 0; 0 ]
  CHECK_FALSE(ray2.intersects(topPoint));
  CHECK(ray2.intersects(topRightPoint));

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //             x < [ 1; 1 ]
  //            /
  //           v
  CHECK_FALSE(ray3.intersects(topPoint));
  CHECK_FALSE(ray3.intersects(topRightPoint));
}

TEST_CASE("Ray-plane intersection") {
  //       Plane 1      |      Plane 2      |      Plane 3      |      Plane 4
  //                    |                   |                   |
  //   \      normal    |    \              |              /    |
  //     \      ^       |      \            |            /      |        normal
  //       \   /        |        \          |          /        |          ^
  //         \/         |        / \        |        /  \       |          |
  //           \        |       /    \      |      /     \      |    ______|______
  //             \      |      v       \    |    /        v     |
  //               \    |   normal          |          normal   |     [ 0; 0.5 ]

  const Raz::Vec3f initPos({ 0.f, 0.5f, 0.f });
  const Raz::Plane plane1(initPos, Raz::Vec3f({ 1.f, 1.f, 0.f }).normalize());
  const Raz::Plane plane2(initPos, Raz::Vec3f({ -1.f, -1.f, 0.f }).normalize());
  const Raz::Plane plane3(initPos, Raz::Vec3f({ 1.f, -1.f, 0.f }).normalize());
  const Raz::Plane plane4(initPos, Raz::Axis::Y);

  CHECK_FALSE(ray1.intersects(plane1));
  CHECK_FALSE(ray2.intersects(plane1));
  CHECK(ray3.intersects(plane1));

  CHECK_FALSE(ray1.intersects(plane2));
  CHECK(ray2.intersects(plane2));
  CHECK_FALSE(ray3.intersects(plane2));

  CHECK_FALSE(ray1.intersects(plane3));
  CHECK_FALSE(ray2.intersects(plane3));
  CHECK_FALSE(ray3.intersects(plane3));

  CHECK_FALSE(ray1.intersects(plane4));
  CHECK_FALSE(ray2.intersects(plane4));
  CHECK(ray3.intersects(plane4));
}

TEST_CASE("Ray-sphere intersection") {
  const Raz::Sphere sphere1(Raz::Vec3f(0.f), 1.f);
  const Raz::Sphere sphere2(Raz::Vec3f({ 5.f, 10.f, 0.f }), 5.f);
  const Raz::Sphere sphere3(Raz::Vec3f({ -10.f, -10.f, 0.f }), 1.f);

  CHECK(ray1.intersects(sphere1));
  CHECK(ray2.intersects(sphere1));
  CHECK(ray3.intersects(sphere1));

  CHECK(ray1.intersects(sphere2));
  CHECK(ray2.intersects(sphere2));
  CHECK_FALSE(ray3.intersects(sphere2));

  CHECK_FALSE(ray1.intersects(sphere3));
  CHECK_FALSE(ray2.intersects(sphere3));
  CHECK(ray3.intersects(sphere3));
}

TEST_CASE("Ray-triangle intersection") {
  // These triangles are defined so that:
  //  - triangle1 is laying flat slightly above 0
  //  - triangle2 is standing, parallel to the Y/Z plane (facing the X direction)
  //  - triangle3 is crooked, its head pointing to [ -X; +Y ], slightly below 0
  const Raz::Triangle triangle1(Raz::Vec3f({ -3.f, 0.5f, 3.f }), Raz::Vec3f({ 0.f, 0.5f, -3.f }), Raz::Vec3f({ 3.f, 0.5f, 3.f }));
  const Raz::Triangle triangle2(Raz::Vec3f({ 0.5f, -0.5f, 3.f }), Raz::Vec3f({ 0.5f, -0.5f, -3.f }), Raz::Vec3f({ 0.5f, 3.f, 0.f }));
  const Raz::Triangle triangle3(Raz::Vec3f({ 0.f, -1.f, 1.f }), Raz::Vec3f({ -1.5f, -1.5f, 0.f }), Raz::Vec3f({ 0.f, -1.75f, -1.f }));

  CHECK(ray1.intersects(triangle1));
  CHECK(ray2.intersects(triangle1));
  CHECK(ray3.intersects(triangle1));

  CHECK_FALSE(ray1.intersects(triangle2));
  CHECK(ray2.intersects(triangle2));
  CHECK(ray3.intersects(triangle2));

  CHECK_FALSE(ray1.intersects(triangle3));
  CHECK_FALSE(ray2.intersects(triangle3));
  CHECK(ray3.intersects(triangle3));
}

TEST_CASE("Ray-AABB intersection") {
  //         _______________________
  //        /|                    /|
  //       / |                   / | / 1 -> [  1;  1; 1 ]
  //      |---------------------| < {  2 -> [  5;  5; 5 ]
  //      |  |                  |  | \ 3 -> [ -5; -5; 5 ]
  //      |  |                  |  |
  //      |  |                  |  |
  //      |  |                  |  |
  //      | /-------------------|-/
  //      |/ ^                  |/
  //      ---|-------------------
  //         |
  //  1 -> [  -1;  -1; -1 ]
  //  2 -> [   3;   3; -5 ]
  //  3 -> [ -10; -10; -5 ]

  const Raz::AABB aabb1(Raz::Vec3f(1.f), Raz::Vec3f(-1.f));
  const Raz::AABB aabb2(Raz::Vec3f(5.f), Raz::Vec3f({ 3.f, 3.f, -5.f }));
  const Raz::AABB aabb3(Raz::Vec3f({ -5.f, -5.f, 5.f }), Raz::Vec3f({ -10.f, -10.f, -5.f }));

  CHECK(ray1.intersects(aabb1));
  CHECK(ray2.intersects(aabb1));
  CHECK(ray3.intersects(aabb1));

  CHECK_FALSE(ray1.intersects(aabb2));
  CHECK(ray2.intersects(aabb2));
  CHECK_FALSE(ray3.intersects(aabb2));

  CHECK_FALSE(ray1.intersects(aabb3));
  CHECK_FALSE(ray2.intersects(aabb3));
  CHECK(ray3.intersects(aabb3));
}

TEST_CASE("Point projection") {
  const Raz::Vec3f topPoint({ 0.f, 2.f, 0.f });
  const Raz::Vec3f topRightPoint({ 2.f, 2.f, 0.f });

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //        ^
  //        |
  //        x < [ 0; 0 ]
  CHECK(ray1.computeProjection(topPoint) == topPoint);
  CHECK(ray1.computeProjection(topRightPoint) == topPoint);

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //          ^
  //         /
  //        x < [ 0; 0 ]
  CHECK(ray2.computeProjection(topPoint) == Raz::Vec3f({ 1.f, 1.f, 0.f }));
  CHECK(ray2.computeProjection(topRightPoint) == topRightPoint);

  //     topPoint  topRightPoint
  //     [ 0; 2 ]    [ 2; 2 ]
  //
  //             x < [ 1; 1 ]
  //            /
  //           v
  CHECK(ray3.computeProjection(topPoint) == ray3.getOrigin());
  CHECK(ray3.computeProjection(topRightPoint) == ray3.getOrigin());
}
<|endoftext|>


<commit_before>/// \author James Hughes
/// \date   November 2013

#include "GlobalTestEnvironment.hpp"
#include "SpireTestFixture.hpp"
#include <spire/src/FileUtil.h>
#include <spire/src/GLMathUtil.h>
#include <arc-ball/ArcBall.hpp>

void compareFBOWithExistingFile(const std::string& filename)
{
  // Print out the frame and compare it.
#ifdef TEST_OUTPUT_IMAGES
  {
    std::string imageName = filename;

    std::string targetImage = TEST_IMAGE_OUTPUT_DIR;
    targetImage += "/" + imageName;
    GlobalTestEnvironment::instance()->getBatchEnvironment()->writeFBO(targetImage);

    EXPECT_TRUE(CPM_SPIRE_NS::fileExists(targetImage)) << "Failed to write output image! " << targetImage;

#ifdef TEST_PERCEPTUAL_COMPARE
    // Perform the perceptual comparison using the given regression directory.
    std::string compImage = TEST_IMAGE_COMPARE_DIR;
    compImage += "/" + imageName;

    ASSERT_TRUE(CPM_SPIRE_NS::fileExists(compImage)) << "Failed to find comparison image! " << compImage;
    // Test using perceptula comparison program that the user has provided
    // (hopefully).
    std::string command = TEST_PERCEPTUAL_COMPARE_BINARY;
    command += " -threshold 50 ";
    command += targetImage + " " + compImage;

    // Usually the return code of std::system is implementation specific. But the
    // majority of systems end up returning the exit code of the program.
    if (std::system(command.c_str()) != 0)
    {
      // The images are NOT the same. Alert the user.
      FAIL() << "Perceptual compare of " << imageName << " failed.";
    }
#endif
  }
#endif
}

TEST_F(SpireTestFixture, TestQuadRotation)
{
  // Test various functions in Object and ObjectPass.
  std::vector<float> vboData =
  {
    -1.0f,  1.0f,  0.0f,
     1.0f,  1.0f,  0.0f,
    -1.0f, -1.0f,  0.0f,
     1.0f, -1.0f,  0.0f
  };
  std::vector<std::string> attribNames = {"aPos"};

  std::vector<uint16_t> iboData =
  {
    0, 1, 2, 3
  };
  CPM_SPIRE_NS::Interface::IBO_TYPE iboType = CPM_SPIRE_NS::Interface::IBO_16BIT;

  // This is pretty contorted interface due to the marshalling between
  // std::vector<float> and std::vector<uint8_t>. In practice, you would want
  // to calculate the size of your VBO and using one std::vector<uint8_t> and
  // reserve the necessary space in it. Then cast it's contents to floats or
  // uint16_t as necessary (attributes can have a wide array of types, including
  // half floats).
  uint8_t*  rawBegin;
  size_t    rawSize;

  // Copy vboData into vector of uint8_t. Using std::copy.
  std::shared_ptr<std::vector<uint8_t>> rawVBO(new std::vector<uint8_t>());
  rawSize = vboData.size() * (sizeof(float) / sizeof(uint8_t));
  rawVBO->reserve(rawSize);
  rawBegin = reinterpret_cast<uint8_t*>(&vboData[0]);
  rawVBO->assign(rawBegin, rawBegin + rawSize);

  // Copy iboData into vector of uint8_t. Using std::vector::assign.
  std::shared_ptr<std::vector<uint8_t>> rawIBO(new std::vector<uint8_t>());
  rawSize = iboData.size() * (sizeof(uint16_t) / sizeof(uint8_t));
  rawIBO->reserve(rawSize);
  rawBegin = reinterpret_cast<uint8_t*>(&iboData[0]);
  rawIBO->assign(rawBegin, rawBegin + rawSize);

  // Add necessary VBO's and IBO's
  std::string vbo1 = "vbo1";
  std::string ibo1 = "ibo1";
  mSpire->addVBO(vbo1, rawVBO, attribNames);
  mSpire->addIBO(ibo1, rawIBO, iboType);

  std::string obj1 = "obj1";
  mSpire->addObject(obj1);

  std::string shader1 = "UniformColor";
  mSpire->addPersistentShader(
      shader1,
      { std::make_tuple("UniformColor.vsh", CPM_SPIRE_NS::Interface::VERTEX_SHADER),
        std::make_tuple("UniformColor.fsh", CPM_SPIRE_NS::Interface::FRAGMENT_SHADER),
      });
  mSpire->addPassToObject(obj1, shader1, vbo1, ibo1, CPM_SPIRE_NS::Interface::TRIANGLE_STRIP);

  mSpire->removeIBO(ibo1);
  mSpire->removeVBO(vbo1);

  mSpire->addObjectPassUniform(obj1, "uColor", glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));

  // Build projection matrix
  float aspect = static_cast<float>(640) / static_cast<float>(480);
  glm::mat4 projection = glm::perspective(0.59f, aspect, 1.0f, 2000.0f);

  glm::mat4 cam;
  glm::mat4 ivp;
  glm::vec4 translation = glm::vec4(0.0f, 0.0f, 5.0f, 1.0f);
  float zDist = 5.0f;

  // Construct first 'no rotation'.
  {
    cam[3] = translation;
    ivp = projection * glm::affineInverse(cam);
    mSpire->addObjectGlobalUniform(obj1, "uProjIVObject", ivp);

    beginFrame();
    mSpire->renderObject(obj1);
    compareFBOWithExistingFile("noRotation.png");
  }

  // Build first rotation about the y axis.
  {
    CPM_ARC_BALL_NS::ArcBall arcball(glm::vec3(0.0f, 0.0f, 0.0f), 0.9f);
    glm::vec2 centerSS(0.0f, 0.0f);   // center screen space.
    glm::vec2 rightSS(0.25f, 0.0f);   // far left
    arcball.beginDrag(centerSS);
    arcball.drag(rightSS);
    glm::mat4 camRot = arcball.getTransformation();

    camRot[3].xyz() = glm::vec3(camRot[2].xyz()) * zDist;
    ivp = projection * glm::affineInverse(camRot);
    mSpire->addObjectGlobalUniform(obj1, "uProjIVObject", ivp);

    beginFrame();
    mSpire->renderObject(obj1);
    compareFBOWithExistingFile("rotRight_Centered.png");
  }

  // Build second rotation about the y axis.
  {
    CPM_ARC_BALL_NS::ArcBall arcball(glm::vec3(0.0f, 0.0f, 0.0f), 0.9f);
    glm::vec2 centerSS(0.0f, 0.0f);   // center screen space.
    glm::vec2 rightSS(-0.25f, 0.0f);   // far left
    arcball.beginDrag(centerSS);
    arcball.drag(rightSS);
    glm::mat4 camRot = arcball.getTransformation();

    camRot[3].xyz() = glm::vec3(camRot[2].xyz()) * zDist;
    ivp = projection * glm::affineInverse(camRot);
    mSpire->addObjectGlobalUniform(obj1, "uProjIVObject", ivp);

    beginFrame();
    mSpire->renderObject(obj1);
    compareFBOWithExistingFile("rotLeft_Centered.png");
  }

  // Build first rotation about the x axis.
  {
    CPM_ARC_BALL_NS::ArcBall arcball(glm::vec3(0.0f, 0.0f, 0.0f), 0.9f);
    glm::vec2 centerSS(0.0f, 0.0f);   // center screen space.
    glm::vec2 rightSS(0.0f, 0.35f);
    arcball.beginDrag(centerSS);
    arcball.drag(rightSS);
    glm::mat4 camRot = arcball.getTransformation();

    camRot[3].xyz() = glm::vec3(camRot[2].xyz()) * zDist;
    ivp = projection * glm::affineInverse(camRot);
    mSpire->addObjectGlobalUniform(obj1, "uProjIVObject", ivp);

    beginFrame();
    mSpire->renderObject(obj1);
    compareFBOWithExistingFile("rotUp_Centered.png");
  }

  // Build first rotation about the x axis.
  {
    CPM_ARC_BALL_NS::ArcBall arcball(glm::vec3(0.0f, 0.0f, 0.0f), 0.9f);
    glm::vec2 centerSS(0.0f, 0.0f);   // center screen space.
    glm::vec2 rightSS(0.0f, -0.35f);
    arcball.beginDrag(centerSS);
    arcball.drag(rightSS);
    glm::mat4 camRot = arcball.getTransformation();

    camRot[3].xyz() = glm::vec3(camRot[2].xyz()) * zDist;
    ivp = projection * glm::affineInverse(camRot);
    mSpire->addObjectGlobalUniform(obj1, "uProjIVObject", ivp);

    beginFrame();
    mSpire->renderObject(obj1);
    compareFBOWithExistingFile("rotDown_Centered.png");
  }
}

<commit_msg>Change pixel threshold.<commit_after>/// \author James Hughes
/// \date   November 2013

#include "GlobalTestEnvironment.hpp"
#include "SpireTestFixture.hpp"
#include <spire/src/FileUtil.h>
#include <spire/src/GLMathUtil.h>
#include <arc-ball/ArcBall.hpp>

void compareFBOWithExistingFile(const std::string& filename)
{
  // Print out the frame and compare it.
#ifdef TEST_OUTPUT_IMAGES
  {
    std::string imageName = filename;

    std::string targetImage = TEST_IMAGE_OUTPUT_DIR;
    targetImage += "/" + imageName;
    GlobalTestEnvironment::instance()->getBatchEnvironment()->writeFBO(targetImage);

    EXPECT_TRUE(CPM_SPIRE_NS::fileExists(targetImage)) << "Failed to write output image! " << targetImage;

#ifdef TEST_PERCEPTUAL_COMPARE
    // Perform the perceptual comparison using the given regression directory.
    std::string compImage = TEST_IMAGE_COMPARE_DIR;
    compImage += "/" + imageName;

    ASSERT_TRUE(CPM_SPIRE_NS::fileExists(compImage)) << "Failed to find comparison image! " << compImage;
    // Test using perceptula comparison program that the user has provided
    // (hopefully).
    std::string command = TEST_PERCEPTUAL_COMPARE_BINARY;
    command += " -threshold 400 ";
    command += targetImage + " " + compImage;

    // Usually the return code of std::system is implementation specific. But the
    // majority of systems end up returning the exit code of the program.
    if (std::system(command.c_str()) != 0)
    {
      // The images are NOT the same. Alert the user.
      FAIL() << "Perceptual compare of " << imageName << " failed.";
    }
#endif
  }
#endif
}

TEST_F(SpireTestFixture, TestQuadRotation)
{
  // Test various functions in Object and ObjectPass.
  std::vector<float> vboData =
  {
    -1.0f,  1.0f,  0.0f,
     1.0f,  1.0f,  0.0f,
    -1.0f, -1.0f,  0.0f,
     1.0f, -1.0f,  0.0f
  };
  std::vector<std::string> attribNames = {"aPos"};

  std::vector<uint16_t> iboData =
  {
    0, 1, 2, 3
  };
  CPM_SPIRE_NS::Interface::IBO_TYPE iboType = CPM_SPIRE_NS::Interface::IBO_16BIT;

  // This is pretty contorted interface due to the marshalling between
  // std::vector<float> and std::vector<uint8_t>. In practice, you would want
  // to calculate the size of your VBO and using one std::vector<uint8_t> and
  // reserve the necessary space in it. Then cast it's contents to floats or
  // uint16_t as necessary (attributes can have a wide array of types, including
  // half floats).
  uint8_t*  rawBegin;
  size_t    rawSize;

  // Copy vboData into vector of uint8_t. Using std::copy.
  std::shared_ptr<std::vector<uint8_t>> rawVBO(new std::vector<uint8_t>());
  rawSize = vboData.size() * (sizeof(float) / sizeof(uint8_t));
  rawVBO->reserve(rawSize);
  rawBegin = reinterpret_cast<uint8_t*>(&vboData[0]);
  rawVBO->assign(rawBegin, rawBegin + rawSize);

  // Copy iboData into vector of uint8_t. Using std::vector::assign.
  std::shared_ptr<std::vector<uint8_t>> rawIBO(new std::vector<uint8_t>());
  rawSize = iboData.size() * (sizeof(uint16_t) / sizeof(uint8_t));
  rawIBO->reserve(rawSize);
  rawBegin = reinterpret_cast<uint8_t*>(&iboData[0]);
  rawIBO->assign(rawBegin, rawBegin + rawSize);

  // Add necessary VBO's and IBO's
  std::string vbo1 = "vbo1";
  std::string ibo1 = "ibo1";
  mSpire->addVBO(vbo1, rawVBO, attribNames);
  mSpire->addIBO(ibo1, rawIBO, iboType);

  std::string obj1 = "obj1";
  mSpire->addObject(obj1);

  std::string shader1 = "UniformColor";
  mSpire->addPersistentShader(
      shader1,
      { std::make_tuple("UniformColor.vsh", CPM_SPIRE_NS::Interface::VERTEX_SHADER),
        std::make_tuple("UniformColor.fsh", CPM_SPIRE_NS::Interface::FRAGMENT_SHADER),
      });
  mSpire->addPassToObject(obj1, shader1, vbo1, ibo1, CPM_SPIRE_NS::Interface::TRIANGLE_STRIP);

  mSpire->removeIBO(ibo1);
  mSpire->removeVBO(vbo1);

  mSpire->addObjectPassUniform(obj1, "uColor", glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));

  // Build projection matrix
  float aspect = static_cast<float>(640) / static_cast<float>(480);
  glm::mat4 projection = glm::perspective(0.59f, aspect, 1.0f, 2000.0f);

  glm::mat4 cam;
  glm::mat4 ivp;
  glm::vec4 translation = glm::vec4(0.0f, 0.0f, 5.0f, 1.0f);
  float zDist = 5.0f;

  // Construct first 'no rotation'.
  {
    cam[3] = translation;
    ivp = projection * glm::affineInverse(cam);
    mSpire->addObjectGlobalUniform(obj1, "uProjIVObject", ivp);

    beginFrame();
    mSpire->renderObject(obj1);
    compareFBOWithExistingFile("noRotation.png");
  }

  // Build first rotation about the y axis.
  {
    CPM_ARC_BALL_NS::ArcBall arcball(glm::vec3(0.0f, 0.0f, 0.0f), 0.9f);
    glm::vec2 centerSS(0.0f, 0.0f);   // center screen space.
    glm::vec2 rightSS(0.25f, 0.0f);   // far left
    arcball.beginDrag(centerSS);
    arcball.drag(rightSS);
    glm::mat4 camRot = arcball.getTransformation();

    camRot[3].xyz() = glm::vec3(camRot[2].xyz()) * zDist;
    ivp = projection * glm::affineInverse(camRot);
    mSpire->addObjectGlobalUniform(obj1, "uProjIVObject", ivp);

    beginFrame();
    mSpire->renderObject(obj1);
    compareFBOWithExistingFile("rotRight_Centered.png");
  }

  // Build second rotation about the y axis.
  {
    CPM_ARC_BALL_NS::ArcBall arcball(glm::vec3(0.0f, 0.0f, 0.0f), 0.9f);
    glm::vec2 centerSS(0.0f, 0.0f);   // center screen space.
    glm::vec2 rightSS(-0.25f, 0.0f);   // far left
    arcball.beginDrag(centerSS);
    arcball.drag(rightSS);
    glm::mat4 camRot = arcball.getTransformation();

    camRot[3].xyz() = glm::vec3(camRot[2].xyz()) * zDist;
    ivp = projection * glm::affineInverse(camRot);
    mSpire->addObjectGlobalUniform(obj1, "uProjIVObject", ivp);

    beginFrame();
    mSpire->renderObject(obj1);
    compareFBOWithExistingFile("rotLeft_Centered.png");
  }

  // Build first rotation about the x axis.
  {
    CPM_ARC_BALL_NS::ArcBall arcball(glm::vec3(0.0f, 0.0f, 0.0f), 0.9f);
    glm::vec2 centerSS(0.0f, 0.0f);   // center screen space.
    glm::vec2 rightSS(0.0f, 0.35f);
    arcball.beginDrag(centerSS);
    arcball.drag(rightSS);
    glm::mat4 camRot = arcball.getTransformation();

    camRot[3].xyz() = glm::vec3(camRot[2].xyz()) * zDist;
    ivp = projection * glm::affineInverse(camRot);
    mSpire->addObjectGlobalUniform(obj1, "uProjIVObject", ivp);

    beginFrame();
    mSpire->renderObject(obj1);
    compareFBOWithExistingFile("rotUp_Centered.png");
  }

  // Build first rotation about the x axis.
  {
    CPM_ARC_BALL_NS::ArcBall arcball(glm::vec3(0.0f, 0.0f, 0.0f), 0.9f);
    glm::vec2 centerSS(0.0f, 0.0f);   // center screen space.
    glm::vec2 rightSS(0.0f, -0.35f);
    arcball.beginDrag(centerSS);
    arcball.drag(rightSS);
    glm::mat4 camRot = arcball.getTransformation();

    camRot[3].xyz() = glm::vec3(camRot[2].xyz()) * zDist;
    ivp = projection * glm::affineInverse(camRot);
    mSpire->addObjectGlobalUniform(obj1, "uProjIVObject", ivp);

    beginFrame();
    mSpire->renderObject(obj1);
    compareFBOWithExistingFile("rotDown_Centered.png");
  }
}

<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include "src/Options.hpp"
#include "src/Cluster.hpp"

using namespace std;
int main(int argc, char *argv[]){

    cout << argv[0] << endl;
    Options options;

    int n_subdomOnCluster;
    string path2data;

    int var = 5;
    if (argc == 2) {
       var = atoi(argv[1]);
    }
    switch (var)
    {
        case (0):
            // small variant: 8 subdom, each 3x3x3 elements
            n_subdomOnCluster = 8;
            path2data = "../data/";
            break;
        case (1):
            // larger variant: 27 subdom, each 10x10x10 elements
            n_subdomOnCluster = 27;
            path2data = "../data1/";
            break;
        case (2):
            // larger variant: 8 subdom, each 6x6x6 elements
            n_subdomOnCluster = 8;
            path2data = "../data2/";
            break;
        case (3):
            // 2nd larger variant: 27 subdom, each 5x5x5 elements
            n_subdomOnCluster = 27;
            path2data = "../data3/";
            break;
        case (4):
            // 2nd larger variant: 27 subdom, each 5x5x5 elements
            // 'kernel' gluing
            n_subdomOnCluster = 27;
            path2data = "../data4/";
            break;
        case (5):
            // data are created in application
            // and 'path2data' is setup for dumped files
            path2data = "../data5/";
            break;
    }

    options.set_values(n_subdomOnCluster, path2data);
//
    Cluster cluster(options);
    cout << "----------------- done -----------------\n" ;
    return 0;
}
<commit_msg>size of mesh (X Y Z x y z) from command line<commit_after>#include <iostream>
#include <string>
#include "src/Options.hpp"
#include "src/Cluster.hpp"

using namespace std;
int main(int argc, char *argv[]){

    cout << argv[0] << endl;
    Options options;

    int n_subdomOnCluster;
    string path2data;

    path2data = "../data/";
    options.set_values(n_subdomOnCluster, path2data);

    if (argc > 1) {
       options.meshSetting.N[0] =  atoi(argv[1]);
    }
    if (argc == 2) {
       options.meshSetting.N[1] =  atoi(argv[2]);
    }
    if (argc == 3) {
       options.meshSetting.N[2] =  atoi(argv[3]);
    }
    if (argc > 4) {
       options.meshSetting.n[0] =  atoi(argv[4]);
    }
    if (argc > 5) {
       options.meshSetting.n[1] =  atoi(argv[5]);
    }
    if (argc > 6) {
       options.meshSetting.n[2] =  atoi(argv[6]);
    }

//    if (argc == 1) {
//       var = atoi(argv[1]);
//    }
//
//    switch (var)
//    {
//        case (0):
//            // small variant: 8 subdom, each 3x3x3 elements
//            n_subdomOnCluster = 8;
//            path2data = "../data/";
//            break;
//        case (1):
//            // larger variant: 27 subdom, each 10x10x10 elements
//            n_subdomOnCluster = 27;
//            path2data = "../data1/";
//            break;
//        case (2):
//            // larger variant: 8 subdom, each 6x6x6 elements
//            n_subdomOnCluster = 8;
//            path2data = "../data2/";
//            break;
//        case (3):
//            // 2nd larger variant: 27 subdom, each 5x5x5 elements
//            n_subdomOnCluster = 27;
//            path2data = "../data3/";
//            break;
//        case (4):
//            // 2nd larger variant: 27 subdom, each 5x5x5 elements
//            // 'kernel' gluing
//            n_subdomOnCluster = 27;
//            path2data = "../data4/";
//            break;
//        case (5):
//            // data are created in application
//            // and 'path2data' is setup for dumped files
//            path2data = "../data5/";
//            break;
//    }

//
    Cluster cluster(options);
    cout << "----------------- done -----------------\n" ;
    return 0;
}
<|endoftext|>


<commit_before>#include "geometry/epoch.hpp"
#include "geometry/named_quantities.hpp"
#include "geometry/grassmann.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "integrators/symplectic_runge_kutta_nyström_integrator.hpp"
#include "physics/solar_system.hpp"
#include "quantities/elementary_functions.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "testing_utilities/numerics.hpp"

namespace principia {

using astronomy::ICRFJ2000Equator;
using geometry::JulianDate;
using integrators::McLachlanAtela1992Order5Optimal;
using quantities::ArcCos;
using quantities::si::Kilo;
using quantities::si::Metre;
using quantities::si::Milli;
using quantities::si::Minute;
using quantities::si::Nano;
using testing_utilities::AbsoluteError;
using ::testing::AllOf;
using ::testing::Gt;
using ::testing::Lt;

namespace physics {

class EclipseTest : public testing::Test {
 protected:
  EclipseTest() {
    solar_system_1950_.Initialize(
        SOLUTION_DIR / "astronomy" / "gravity_model.proto.txt",
        SOLUTION_DIR / "astronomy" /
            "initial_state_jd_2433282_500000000.proto.txt");
  }

  SolarSystem<ICRFJ2000Equator> solar_system_1950_;
};

TEST_F(EclipseTest, Dummy) {
  auto ephemeris = solar_system_1950_.MakeEphemeris(
      McLachlanAtela1992Order5Optimal<Position<ICRFJ2000Equator>>(),
      45 * Minute, 5 * Milli(Metre));

  ephemeris->Prolong(JulianDate(2433374.5));  // Prolong just past date of eclipse
                                              // (Eclipse was 1950-04-02 but JD
                                              // is 1950-04-03:00:00:00).
  // Pass body to Ephemeris.trajectory.
  auto const sun = solar_system_1950_.massive_body(*ephemeris, "Sun");
  auto const earth = solar_system_1950_.massive_body(*ephemeris, "Earth");
  auto const moon = solar_system_1950_.massive_body(*ephemeris, "Moon");

  // MassiveBody eventually needs radius information. Or non-hardcoded data from
  // https://github.com/mockingbirdnest/Principia/blob/master/astronomy/gravity_model.proto.txt
  auto const r_sun = 696000.0 * Kilo(Metre);
  auto const r_earth = 6378.1363 * Kilo(Metre);
  auto const r_moon = 1738.0 * Kilo(Metre);

  // Dates are TDB Julian Day for 1948-04-02.
  auto const P1 = JulianDate(2433374.25788409);  // 18:10:49 UT
  auto const U1 = JulianDate(2433374.29850909);  // 19:09:19
  auto const U2 = JulianDate(2433374.354979);    // 20:30:38
  auto const U3 = JulianDate(2433374.37367113);  // 20:57:33
  auto const U4 = JulianDate(2433374.43016419);  // 22:18:54
  auto const P4 = JulianDate(2433374.47075446);  // 23:17:21

  // Lunar eclipse -- U1 (time is start of umbral phase).
  auto q_sun = ephemeris->trajectory(sun)->EvaluatePosition(U1, nullptr);
  auto q_moon = ephemeris->trajectory(moon)->EvaluatePosition(U1, nullptr);
  auto q_earth = ephemeris->trajectory(earth)->EvaluatePosition(U1, nullptr);

  // Check body angles at target time.
  // Earth/Sun lineup.
  auto half_sun_earth_aperture = ArcSin((r_sun - r_earth) / (q_sun - q_earth).Norm());
  auto q_U14 =
      q_earth + Normalize(q_earth - q_sun) * (r_earth + r_moon) / Sin(half_sun_earth_aperture);
  // Earth/Moon lineup for U14.
  auto half_earth_moon_aperture = ArcCos(InnerProduct(q_U14 - q_earth, q_U14 - q_moon) /
                      ((q_U14 - q_moon).Norm() * (q_U14 - q_earth).Norm()));
  // Do the angles work?
  EXPECT_THAT(AbsoluteError(half_sun_earth_aperture, half_earth_moon_aperture),
              AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian)))) <<
              NAMED(half_sun_earth_aperture) << ", " << NAMED(half_earth_moon_aperture);

  // Lunar eclipse -- U2 (time is start of full eclipse).
  q_sun = ephemeris->trajectory(sun)->EvaluatePosition(U2, nullptr);
  q_moon = ephemeris->trajectory(moon)->EvaluatePosition(U2, nullptr);
  q_earth = ephemeris->trajectory(earth)->EvaluatePosition(U2, nullptr);

  // Check body angles at target time.
  // Earth/Sun lineup.
  half_sun_earth_aperture = ArcSin((r_sun - r_earth) / (q_sun - q_earth).Norm());
  auto q_U23 =
      q_earth + Normalize(q_earth - q_sun) * (r_earth - r_moon) / Sin(half_sun_earth_aperture);
  // Earth/Moon lineup for U23.
  half_earth_moon_aperture = ArcCos(InnerProduct(q_U23 - q_earth, q_U23 - q_moon) /
                     ((q_U23 - q_moon).Norm() * (q_U23 - q_earth).Norm()));
  // Do the angles work?
  EXPECT_THAT(AbsoluteError(half_sun_earth_aperture, half_earth_moon_aperture),
              AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian)))) <<
              NAMED(half_sun_earth_aperture) << ", " << NAMED(half_earth_moon_aperture);

  // Lunar eclipse -- U3 (time is end of full eclipse).
  q_sun = ephemeris->trajectory(sun)->EvaluatePosition(U3, nullptr);
  q_moon = ephemeris->trajectory(moon)->EvaluatePosition(U3, nullptr);
  q_earth = ephemeris->trajectory(earth)->EvaluatePosition(U3, nullptr);

  // Check body angles at target time.
  // Earth/Sun lineup.
  half_sun_earth_aperture = ArcSin((r_sun - r_earth) / (q_sun - q_earth).Norm());
  q_U23 =
      q_earth + Normalize(q_earth - q_sun) * (r_earth - r_moon) / Sin(half_sun_earth_aperture);
  // Earth/Moon lineup for U23.
  half_earth_moon_aperture = ArcCos(InnerProduct(q_U23 - q_earth, q_U23 - q_moon) /
                ((q_U23 - q_moon).Norm() * (q_U23 - q_earth).Norm()));
  // Do the angles work?
  EXPECT_THAT(AbsoluteError(half_sun_earth_aperture, half_earth_moon_aperture),
              AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian)))) <<
              NAMED(half_sun_earth_aperture) << ", " << NAMED(half_earth_moon_aperture);

  // Lunar eclipse -- U4 (time is end of umbral phase).
  q_sun = ephemeris->trajectory(sun)->EvaluatePosition(U4, nullptr);
  q_moon = ephemeris->trajectory(moon)->EvaluatePosition(U4, nullptr);
  q_earth = ephemeris->trajectory(earth)->EvaluatePosition(U4, nullptr);

  // Check body angles at target time.
  // Earth/Sun lineup.
  half_sun_earth_aperture = ArcSin((r_sun - r_earth) / (q_sun - q_earth).Norm());
  q_U14 =
      q_earth + Normalize(q_earth - q_sun) * (r_earth + r_moon) / Sin(half_sun_earth_aperture);
  // Earth/Moon lineup for U14.
  half_earth_moon_aperture = ArcCos(InnerProduct(q_U14 - q_earth, q_U14 - q_moon) /
                 ((q_U14 - q_moon).Norm() * (q_U14 - q_earth).Norm()));
  // Do the angles work?
  EXPECT_THAT(AbsoluteError(half_sun_earth_aperture, half_earth_moon_aperture),
              AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian)))) <<
              NAMED(half_sun_earth_aperture) << ", " << NAMED(half_earth_moon_aperture);

  // Later on for additional accuracy: 2 * ArcTan((x_norm_y -
  // y_normx).Norm(),(x_norm_y + y_norm_x).Norm())
  // x_norm_y = x * y.Norm() and y_norm_x = y * x.Norm()

  // Future: check 2048-01-01 Lunar eclipse.
  // P1 = 03:52:39 UT
  // U1 = 05:05:17 UT
  // U2 = 06:24:27
  // U3 = 07:20:23
  // U4 = 08:39:33
  // P4 = 09:52:05
  // etimes = {2469076.66235167, 2469076.71279148, 2469076.76776833,
  // 2469076.80661092, 2469076.86158778, 2469076.91195815};
}

}  // namespace physics
}  // namespace principia
<commit_msg>*CLANG* formatting fixed.<commit_after>#include "geometry/epoch.hpp"
#include "geometry/named_quantities.hpp"
#include "geometry/grassmann.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "integrators/symplectic_runge_kutta_nyström_integrator.hpp"
#include "physics/solar_system.hpp"
#include "quantities/elementary_functions.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "testing_utilities/numerics.hpp"

namespace principia {

using astronomy::ICRFJ2000Equator;
using geometry::JulianDate;
using integrators::McLachlanAtela1992Order5Optimal;
using quantities::ArcCos;
using quantities::si::Kilo;
using quantities::si::Metre;
using quantities::si::Milli;
using quantities::si::Minute;
using quantities::si::Nano;
using testing_utilities::AbsoluteError;
using ::testing::AllOf;
using ::testing::Gt;
using ::testing::Lt;

namespace physics {

class EclipseTest : public testing::Test {
 protected:
  EclipseTest() {
    solar_system_1950_.Initialize(
        SOLUTION_DIR / "astronomy" / "gravity_model.proto.txt",
        SOLUTION_DIR / "astronomy" /
            "initial_state_jd_2433282_500000000.proto.txt");
  }

  SolarSystem<ICRFJ2000Equator> solar_system_1950_;
};

TEST_F(EclipseTest, Dummy) {
  auto ephemeris = solar_system_1950_.MakeEphemeris(
      McLachlanAtela1992Order5Optimal<Position<ICRFJ2000Equator>>(),
      45 * Minute, 5 * Milli(Metre));

  ephemeris->Prolong(JulianDate(2433374.5));  // Prolong just past date of eclipse
                                              // (Eclipse was 1950-04-02 but JD
                                              // is 1950-04-03:00:00:00).
  // Pass body to Ephemeris.trajectory.
  auto const sun = solar_system_1950_.massive_body(*ephemeris, "Sun");
  auto const earth = solar_system_1950_.massive_body(*ephemeris, "Earth");
  auto const moon = solar_system_1950_.massive_body(*ephemeris, "Moon");

  // MassiveBody eventually needs radius information. Or non-hardcoded data from
  // https://github.com/mockingbirdnest/Principia/blob/master/astronomy/gravity_model.proto.txt
  auto const r_sun = 696000.0 * Kilo(Metre);
  auto const r_earth = 6378.1363 * Kilo(Metre);
  auto const r_moon = 1738.0 * Kilo(Metre);

  // Dates are TDB Julian Day for 1948-04-02.
  auto const P1 = JulianDate(2433374.25788409);  // 18:10:49 UT
  auto const U1 = JulianDate(2433374.29850909);  // 19:09:19
  auto const U2 = JulianDate(2433374.354979);    // 20:30:38
  auto const U3 = JulianDate(2433374.37367113);  // 20:57:33
  auto const U4 = JulianDate(2433374.43016419);  // 22:18:54
  auto const P4 = JulianDate(2433374.47075446);  // 23:17:21

  // Lunar eclipse -- U1 (time is start of umbral phase).
  auto q_sun = ephemeris->trajectory(sun)->EvaluatePosition(U1, nullptr);
  auto q_moon = ephemeris->trajectory(moon)->EvaluatePosition(U1, nullptr);
  auto q_earth = ephemeris->trajectory(earth)->EvaluatePosition(U1, nullptr);

  // Check body angles at target time.
  // Earth/Sun lineup.
  auto half_sun_earth_aperture = ArcSin((r_sun - r_earth) / (q_sun - q_earth).Norm());
  auto q_U14 =
      q_earth + Normalize(q_earth - q_sun) * (r_earth + r_moon) / Sin(half_sun_earth_aperture);
  // Earth/Moon lineup for U14.
  auto half_earth_moon_aperture = ArcCos(InnerProduct(q_U14 - q_earth, q_U14 - q_moon) /
                      ((q_U14 - q_moon).Norm() * (q_U14 - q_earth).Norm()));
  // Do the angles work?
  EXPECT_THAT(AbsoluteError(half_sun_earth_aperture, half_earth_moon_aperture),
              AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian)))) <<
              NAMED(half_sun_earth_aperture) << ", " << NAMED(half_earth_moon_aperture);

  // Lunar eclipse -- U2 (time is start of full eclipse).
  q_sun = ephemeris->trajectory(sun)->EvaluatePosition(U2, nullptr);
  q_moon = ephemeris->trajectory(moon)->EvaluatePosition(U2, nullptr);
  q_earth = ephemeris->trajectory(earth)->EvaluatePosition(U2, nullptr);

  // Check body angles at target time.
  // Earth/Sun lineup.
  half_sun_earth_aperture = ArcSin((r_sun - r_earth) / (q_sun - q_earth).Norm());
  auto q_U23 =
      q_earth + Normalize(q_earth - q_sun) * (r_earth - r_moon) / Sin(half_sun_earth_aperture);
  // Earth/Moon lineup for U23.
  half_earth_moon_aperture = ArcCos(InnerProduct(q_U23 - q_earth, q_U23 - q_moon) /
                     ((q_U23 - q_moon).Norm() * (q_U23 - q_earth).Norm()));
  // Do the angles work?
  EXPECT_THAT(AbsoluteError(half_sun_earth_aperture, half_earth_moon_aperture),
              AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian)))) <<
              NAMED(half_sun_earth_aperture) << ", " << NAMED(half_earth_moon_aperture);

  // Lunar eclipse -- U3 (time is end of full eclipse).
  q_sun = ephemeris->trajectory(sun)->EvaluatePosition(U3, nullptr);
  q_moon = ephemeris->trajectory(moon)->EvaluatePosition(U3, nullptr);
  q_earth = ephemeris->trajectory(earth)->EvaluatePosition(U3, nullptr);

  // Check body angles at target time.
  // Earth/Sun lineup.
  half_sun_earth_aperture = ArcSin((r_sun - r_earth) / (q_sun - q_earth).Norm());
  q_U23 =
      q_earth + Normalize(q_earth - q_sun) * (r_earth - r_moon) / Sin(half_sun_earth_aperture);
  // Earth/Moon lineup for U23.
  half_earth_moon_aperture = ArcCos(InnerProduct(q_U23 - q_earth, q_U23 - q_moon) /
                ((q_U23 - q_moon).Norm() * (q_U23 - q_earth).Norm()));
  // Do the angles work?
  EXPECT_THAT(AbsoluteError(half_sun_earth_aperture, half_earth_moon_aperture),
              AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian)))) <<
              NAMED(half_sun_earth_aperture) << ", " << NAMED(half_earth_moon_aperture);

  // Lunar eclipse -- U4 (time is end of umbral phase).
  q_sun = ephemeris->trajectory(sun)->EvaluatePosition(U4, nullptr);
  q_moon = ephemeris->trajectory(moon)->EvaluatePosition(U4, nullptr);
  q_earth = ephemeris->trajectory(earth)->EvaluatePosition(U4, nullptr);

  // Check body angles at target time.
  // Earth/Sun lineup.
  half_sun_earth_aperture = ArcSin((r_sun - r_earth) / (q_sun - q_earth).Norm());
  q_U14 =
      q_earth + Normalize(q_earth - q_sun) * (r_earth + r_moon) / Sin(half_sun_earth_aperture);
  // Earth/Moon lineup for U14.
  half_earth_moon_aperture = ArcCos(InnerProduct(q_U14 - q_earth, q_U14 - q_moon) /
                 ((q_U14 - q_moon).Norm() * (q_U14 - q_earth).Norm()));
  // Do the angles work?
  EXPECT_THAT(AbsoluteError(half_sun_earth_aperture, half_earth_moon_aperture),
              AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian)))) <<
              NAMED(half_sun_earth_aperture) << ", " << NAMED(half_earth_moon_aperture);

  // Later on for additional accuracy: 2 * ArcTan((x_norm_y -
  // y_normx).Norm(),(x_norm_y + y_norm_x).Norm())
  // x_norm_y = x * y.Norm() and y_norm_x = y * x.Norm()

  // Future: check 2048-01-01 Lunar eclipse.
  // P1 = 03:52:39 UT
  // U1 = 05:05:17 UT
  // U2 = 06:24:27
  // U3 = 07:20:23
  // U4 = 08:39:33
  // P4 = 09:52:05
  // etimes = {2469076.66235167, 2469076.71279148, 2469076.76776833,
  // 2469076.80661092, 2469076.86158778, 2469076.91195815};
}

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


<commit_before>//===--- MicrosoftCXXABI.cpp - Emit LLVM Code from ASTs for a Module ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This provides C++ code generation targeting the Microsoft Visual C++ ABI.
// The class in this file generates structures that follow the Microsoft
// Visual C++ ABI, which is actually not very well documented at all outside
// of Microsoft.
//
//===----------------------------------------------------------------------===//

#include "CGCXXABI.h"
#include "CodeGenModule.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"

using namespace clang;
using namespace CodeGen;

namespace {

class MicrosoftCXXABI : public CGCXXABI {
public:
  MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}

  void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
                                 CXXCtorType Type,
                                 CanQualType &ResTy,
                                 SmallVectorImpl<CanQualType> &ArgTys) {
    // 'this' is already in place
    // TODO: 'for base' flag
  }

  void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
                                CXXDtorType Type,
                                CanQualType &ResTy,
                                SmallVectorImpl<CanQualType> &ArgTys) {
    // 'this' is already in place
    // TODO: 'for base' flag
  }

  void BuildInstanceFunctionParams(CodeGenFunction &CGF,
                                   QualType &ResTy,
                                   FunctionArgList &Params) {
    BuildThisParam(CGF, Params);
    // TODO: 'for base' flag
  }

  void EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
    EmitThisParam(CGF);
    // TODO: 'for base' flag
  }

  // ==== Notes on array cookies =========
  //
  // MSVC seems to only use cookies when the class has a destructor; a
  // two-argument usual array deallocation function isn't sufficient.
  //
  // For example, this code prints "100" and "1":
  //   struct A {
  //     char x;
  //     void *operator new[](size_t sz) {
  //       printf("%u\n", sz);
  //       return malloc(sz);
  //     }
  //     void operator delete[](void *p, size_t sz) {
  //       printf("%u\n", sz);
  //       free(p);
  //     }
  //   };
  //   int main() {
  //     A *p = new A[100];
  //     delete[] p;
  //   }
  // Whereas it prints "104" and "104" if you give A a destructor.
};

}

CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
  return new MicrosoftCXXABI(CGM);
}

<commit_msg>ErrorUnsupported on array cookies in the MS C++ ABI code; patch by Timur Iskhodzhanov.<commit_after>//===--- MicrosoftCXXABI.cpp - Emit LLVM Code from ASTs for a Module ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This provides C++ code generation targeting the Microsoft Visual C++ ABI.
// The class in this file generates structures that follow the Microsoft
// Visual C++ ABI, which is actually not very well documented at all outside
// of Microsoft.
//
//===----------------------------------------------------------------------===//

#include "CGCXXABI.h"
#include "CodeGenModule.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"

using namespace clang;
using namespace CodeGen;

namespace {

class MicrosoftCXXABI : public CGCXXABI {
public:
  MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}

  void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
                                 CXXCtorType Type,
                                 CanQualType &ResTy,
                                 SmallVectorImpl<CanQualType> &ArgTys) {
    // 'this' is already in place
    // TODO: 'for base' flag
  }

  void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
                                CXXDtorType Type,
                                CanQualType &ResTy,
                                SmallVectorImpl<CanQualType> &ArgTys) {
    // 'this' is already in place
    // TODO: 'for base' flag
  }

  void BuildInstanceFunctionParams(CodeGenFunction &CGF,
                                   QualType &ResTy,
                                   FunctionArgList &Params) {
    BuildThisParam(CGF, Params);
    // TODO: 'for base' flag
  }

  void EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
    EmitThisParam(CGF);
    // TODO: 'for base' flag
  }

  // ==== Notes on array cookies =========
  //
  // MSVC seems to only use cookies when the class has a destructor; a
  // two-argument usual array deallocation function isn't sufficient.
  //
  // For example, this code prints "100" and "1":
  //   struct A {
  //     char x;
  //     void *operator new[](size_t sz) {
  //       printf("%u\n", sz);
  //       return malloc(sz);
  //     }
  //     void operator delete[](void *p, size_t sz) {
  //       printf("%u\n", sz);
  //       free(p);
  //     }
  //   };
  //   int main() {
  //     A *p = new A[100];
  //     delete[] p;
  //   }
  // Whereas it prints "104" and "104" if you give A a destructor.
  void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
                       const CXXDeleteExpr *expr,
                       QualType ElementType, llvm::Value *&NumElements,
                       llvm::Value *&AllocPtr, CharUnits &CookieSize) {
    CGF.CGM.ErrorUnsupported(expr, "don't know how to handle array cookies "
                                   "in the Microsoft C++ ABI");
  }
};

}

CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
  return new MicrosoftCXXABI(CGM);
}

<|endoftext|>


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

  Program: 3D Slicer

  Copyright (c) Kitware Inc.

  See COPYRIGHT.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  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.

  This file was originally developed by Julien Finet, Kitware Inc.
  and was partially funded by NIH grant 3P41RR013218-12S1

==============================================================================*/

// Qt includes
#include <QDebug>
#include <QTimer>

// qMRML includes
#include "qMRMLIGTLIOModel.h"

// MRML includes
#include <vtkMRMLDisplayableHierarchyNode.h>
#include <vtkMRMLDisplayableNode.h>
#include <vtkMRMLDisplayNode.h>
#include <vtkMRMLScene.h>

// VTK includes
#include <vtkCollection.h>

// OpenIGTLink IF includes
#include "vtkMRMLIGTLConnectorNode.h"

#include "qMRMLIGTLIOModel_p.h"

//------------------------------------------------------------------------------
qMRMLIGTLIOModelPrivate::qMRMLIGTLIOModelPrivate(qMRMLIGTLIOModel& object)
  : qMRMLSceneModelPrivate(object)
{
}

//------------------------------------------------------------------------------
QStandardItem* qMRMLIGTLIOModelPrivate::insertExtraItem2(int row, QStandardItem* parent,
                                              const QString& text,
                                              const QString& extraType,
                                              const Qt::ItemFlags& flags)
{
  Q_ASSERT(parent);

  QStandardItem* item = new QStandardItem;
  item->setData(extraType, qMRMLSceneModel::UIDRole);
  if (text == "separator")
    {
    item->setData("separator", Qt::AccessibleDescriptionRole);
    }
  else
    {
    item->setText(text);
    }
  item->setFlags(flags);
  QList<QStandardItem*> items;
  items << item;

  QStandardItem* item0 = new QStandardItem;
  item0->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
  items << item0 << item0 << item0;
  parent->insertRow(row, items);

  // update extra item cache info (for faster retrieval)
  QMap<QString, QVariant> extraItems = parent->data(qMRMLSceneModel::ExtraItemsRole).toMap();
  extraItems[extraType] = extraItems[extraType].toStringList() << text;
  parent->setData(extraItems, qMRMLSceneModel::ExtraItemsRole );

  return item;
}

//------------------------------------------------------------------------------
qMRMLIGTLIOModel::qMRMLIGTLIOModel(QObject *vparent)
  :Superclass(new qMRMLIGTLIOModelPrivate(*this), vparent)
{
  Q_D(qMRMLIGTLIOModel);
  d->init(/*new qMRMLSceneModelItemHelperFactory*/);

  this->setListenNodeModifiedEvent(true);
  this->setIDColumn(-1);
  this->setCheckableColumn(qMRMLIGTLIOModel::VisualizationColumn);
  this->setColumnCount(4);
  this->setHorizontalHeaderLabels(QStringList() << "Name" << "MRML Type" << "IGTL Type" << "Vis");
}

//------------------------------------------------------------------------------
qMRMLIGTLIOModel::qMRMLIGTLIOModel(qMRMLIGTLIOModelPrivate* pimpl, QObject *parent)
  :Superclass(pimpl, parent)
{
}

//------------------------------------------------------------------------------
qMRMLIGTLIOModel::~qMRMLIGTLIOModel()
{

}

//-----------------------------------------------------------------------------
/// Set and observe the logic
//-----------------------------------------------------------------------------
void qMRMLIGTLIOModel::setLogic(vtkSlicerOpenIGTLinkIFLogic* logic)
{
  if (!logic)
    {
    return;
    }
  this->Logic = logic;
}

//------------------------------------------------------------------------------
QStandardItem* qMRMLIGTLIOModel::insertNode(vtkMRMLNode* node, QStandardItem* parent, int row)
{
  QStandardItem* insertedItem = this->Superclass::insertNode(node, parent, row);
  if (this->listenNodeModifiedEvent() &&
      node->IsA("vtkMRMLIGTLConnectorNode"))
    {
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::ConnectedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::DisconnectedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::ActivatedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::DeactivatedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::NewDeviceEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    }
  return insertedItem;
}

//------------------------------------------------------------------------------
//void qMRMLIGTLIOModel::updateItemFromNode(QStandardItem* item, vtkMRMLNode* node, int column)
void qMRMLIGTLIOModel::updateItemDataFromNode(QStandardItem* item, vtkMRMLNode* node, int column)
{
  Q_D(qMRMLIGTLIOModel);

  //this->Superclass::updateItemFromNode(item, node, column);
  vtkMRMLIGTLConnectorNode* cnode = vtkMRMLIGTLConnectorNode::SafeDownCast(node);
  if (!cnode)
    {
    return;
    }

  switch (column)
    {
    case qMRMLIGTLIOModel::NameColumn:
      {
      item->setText(cnode->GetName());
      insertIOTree(cnode);
      break;
      }
    case qMRMLIGTLIOModel::TypeColumn:
      {
      Q_ASSERT(cnode->GetType() < vtkMRMLIGTLConnectorNode::NUM_TYPE);
      //item->setText(QString(vtkMRMLIGTLConnectorNode::ConnectorTypeStr[cnode->GetType()]));
      item->setText("");
      break;
      }
    case qMRMLIGTLIOModel::StatusColumn:
      {
      Q_ASSERT(cnode->GetState() < vtkMRMLIGTLConnectorNode::NUM_STATE);
      //item->setText(QString(vtkMRMLIGTLConnectorNode::ConnectorStateStr[cnode->GetState()]));
      item->setText("");
      break;
      }
    default:
      break;
    }
}

//------------------------------------------------------------------------------
void qMRMLIGTLIOModel::addNodeToCurrentBranch(vtkMRMLNode* node)
{
  Q_D(qMRMLIGTLIOModel);

}

//------------------------------------------------------------------------------
void qMRMLIGTLIOModel::updateIOTreeBranch(vtkMRMLIGTLConnectorNode* node, QStandardItem* item, qMRMLIGTLIOModel::Direction dir)
{
  // List incoming data
  if (node == NULL)
    {
    return;
    }

  int nnodes;
  if (dir == qMRMLIGTLIOModel::INCOMING)
    {
    nnodes = node->GetNumberOfIncomingMRMLNodes();
    }
  else
    {
    nnodes = node->GetNumberOfOutgoingMRMLNodes();
    }

  for (int i = 0; i < nnodes; i ++)
    {
    vtkMRMLNode* inode;
    if (dir == qMRMLIGTLIOModel::INCOMING)
      {
      inode = node->GetIncomingMRMLNode(i);
      }
    else
      {
      inode = node->GetOutgoingMRMLNode(i);
      }
    if (inode != NULL)
      {
      QList<QStandardItem*> items;

      QStandardItem* item0 = new QStandardItem;
      item0->setText(inode->GetName());
      item0->setData("IOTree", qMRMLSceneModel::UIDRole);
      item0->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
      items << item0;

      QStandardItem* item1 = new QStandardItem;
      item1->setText(inode->GetNodeTagName());
      item1->setData("IOTree", qMRMLSceneModel::UIDRole);
      item1->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
      items << item1;

      QStandardItem* item2 = new QStandardItem;
      item2->setData("IOTree", qMRMLSceneModel::UIDRole);
      item2->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
      vtkIGTLToMRMLBase* converter = node->GetConverterByNodeID(inode->GetID());
      if (converter)
        {
        item2->setText(converter->GetIGTLName());
        }
      else
        {
        item2->setText("--");
        }
      items << item2;

      item->insertRow(i, items);
      }
    //// update extra item cache info (for faster retrieval)
    //QMap<QString, QVariant> extraItems = nodeItem->data(qMRMLSceneModel::ExtraItemsRole).toMap();
    //extraItems[extraType] = extraItems[extraType].toStringList() << text;
    //parent->setData(extraItems, qMRMLSceneModel::ExtraItemsRole );
    }
}

//------------------------------------------------------------------------------
QStandardItem* qMRMLIGTLIOModel::insertIOTree(vtkMRMLNode* node)
{
  Q_D(qMRMLIGTLIOModel);

  // Check if the node is a connector node
  vtkMRMLIGTLConnectorNode * cnode = vtkMRMLIGTLConnectorNode::SafeDownCast(node);
  if (!cnode)
    {
    return NULL;
    }

  QStandardItem* nodeItem = this->itemFromNode(node);
  if (nodeItem == 0 || d == 0)
    {
    return NULL;
    }

  d->removeAllExtraItems(nodeItem, "IOTree");
  QStandardItem* inItem = d->insertExtraItem2(nodeItem->rowCount(), nodeItem,
                                              QString("IN"), "IOTree", Qt::ItemIsEnabled|Qt::ItemIsSelectable);
  updateIOTreeBranch(cnode, inItem, qMRMLIGTLIOModel::INCOMING);
  QStandardItem* outItem = d->insertExtraItem2(nodeItem->rowCount(), nodeItem,
                                               QString("OUT"), "IOTree", Qt::ItemIsEnabled|Qt::ItemIsSelectable);
  updateIOTreeBranch(cnode, outItem, qMRMLIGTLIOModel::OUTGOING);

  return nodeItem;

}

//------------------------------------------------------------------------------
QStandardItem* qMRMLIGTLIOModel::insertNode(vtkMRMLNode* node)
{
  //return this->Superclass::insertNode(node);

  Q_D(qMRMLIGTLIOModel);
  QStandardItem* nodeItem = this->itemFromNode(node);
  if (nodeItem != 0)
    {
    // It is possible that the node has been already added if it is the parent
    // of a child node already inserted.
    return nodeItem;
    }
  vtkMRMLNode* parentNode = this->parentNode(node);
  QStandardItem* parentItem =
    parentNode ? this->itemFromNode(parentNode) : this->mrmlSceneItem();
  if (!parentItem)
    {
    Q_ASSERT(parentNode);
    parentItem = this->insertNode(parentNode);
    Q_ASSERT(parentItem);
    }
  int min = this->preItems(parentItem).count();
  int max = parentItem->rowCount() - this->postItems(parentItem).count();
  int row = min + this->nodeIndex(node);
  if (row > max)
    {
    d->MisplacedNodes << node;
    row = max;
    }
  nodeItem = this->insertNode(node, parentItem, row);
  Q_ASSERT(this->itemFromNode(node) == nodeItem);

  insertIOTree(node);

  //QStringList sl;
  //sl << "IN" << "OUT";
  //setPostItems(sl, nodeItem);

  return nodeItem;

}

<commit_msg>ENH: adding visibility icon<commit_after>/*==============================================================================

  Program: 3D Slicer

  Copyright (c) Kitware Inc.

  See COPYRIGHT.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  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.

  This file was originally developed by Julien Finet, Kitware Inc.
  and was partially funded by NIH grant 3P41RR013218-12S1

==============================================================================*/

// Qt includes
#include <QDebug>
#include <QTimer>

// qMRML includes
#include "qMRMLIGTLIOModel.h"

// MRML includes
#include <vtkMRMLDisplayableHierarchyNode.h>
#include <vtkMRMLDisplayableNode.h>
#include <vtkMRMLDisplayNode.h>
#include <vtkMRMLScene.h>

// VTK includes
#include <vtkCollection.h>

// OpenIGTLink IF includes
#include "vtkMRMLIGTLConnectorNode.h"

#include "qMRMLIGTLIOModel_p.h"

//------------------------------------------------------------------------------
qMRMLIGTLIOModelPrivate::qMRMLIGTLIOModelPrivate(qMRMLIGTLIOModel& object)
  : qMRMLSceneModelPrivate(object)
{
}

//------------------------------------------------------------------------------
QStandardItem* qMRMLIGTLIOModelPrivate::insertExtraItem2(int row, QStandardItem* parent,
                                              const QString& text,
                                              const QString& extraType,
                                              const Qt::ItemFlags& flags)
{
  Q_ASSERT(parent);

  QStandardItem* item = new QStandardItem;
  item->setData(extraType, qMRMLSceneModel::UIDRole);
  if (text == "separator")
    {
    item->setData("separator", Qt::AccessibleDescriptionRole);
    }
  else
    {
    item->setText(text);
    }
  item->setFlags(flags);
  QList<QStandardItem*> items;
  items << item;

  QStandardItem* item0 = new QStandardItem;
  item0->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
  items << item0 << item0 << item0;
  parent->insertRow(row, items);

  // update extra item cache info (for faster retrieval)
  QMap<QString, QVariant> extraItems = parent->data(qMRMLSceneModel::ExtraItemsRole).toMap();
  extraItems[extraType] = extraItems[extraType].toStringList() << text;
  parent->setData(extraItems, qMRMLSceneModel::ExtraItemsRole );

  return item;
}

//------------------------------------------------------------------------------
qMRMLIGTLIOModel::qMRMLIGTLIOModel(QObject *vparent)
  :Superclass(new qMRMLIGTLIOModelPrivate(*this), vparent)
{
  Q_D(qMRMLIGTLIOModel);
  d->init(/*new qMRMLSceneModelItemHelperFactory*/);

  this->setListenNodeModifiedEvent(true);
  this->setIDColumn(-1);
  this->setCheckableColumn(qMRMLIGTLIOModel::VisualizationColumn);
  this->setColumnCount(4);
  this->setHorizontalHeaderLabels(QStringList() << "Name" << "MRML Type" << "IGTL Type" << "Vis");
}

//------------------------------------------------------------------------------
qMRMLIGTLIOModel::qMRMLIGTLIOModel(qMRMLIGTLIOModelPrivate* pimpl, QObject *parent)
  :Superclass(pimpl, parent)
{
}

//------------------------------------------------------------------------------
qMRMLIGTLIOModel::~qMRMLIGTLIOModel()
{

}

//-----------------------------------------------------------------------------
/// Set and observe the logic
//-----------------------------------------------------------------------------
void qMRMLIGTLIOModel::setLogic(vtkSlicerOpenIGTLinkIFLogic* logic)
{
  if (!logic)
    {
    return;
    }
  this->Logic = logic;
}

//------------------------------------------------------------------------------
QStandardItem* qMRMLIGTLIOModel::insertNode(vtkMRMLNode* node, QStandardItem* parent, int row)
{
  QStandardItem* insertedItem = this->Superclass::insertNode(node, parent, row);
  if (this->listenNodeModifiedEvent() &&
      node->IsA("vtkMRMLIGTLConnectorNode"))
    {
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::ConnectedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::DisconnectedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::ActivatedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::DeactivatedEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    qvtkConnect(node, vtkMRMLIGTLConnectorNode::NewDeviceEvent,
                this, SLOT(onMRMLNodeModified(vtkObject*)));
    }
  return insertedItem;
}

//------------------------------------------------------------------------------
//void qMRMLIGTLIOModel::updateItemFromNode(QStandardItem* item, vtkMRMLNode* node, int column)
void qMRMLIGTLIOModel::updateItemDataFromNode(QStandardItem* item, vtkMRMLNode* node, int column)
{
  Q_D(qMRMLIGTLIOModel);

  //this->Superclass::updateItemFromNode(item, node, column);
  vtkMRMLIGTLConnectorNode* cnode = vtkMRMLIGTLConnectorNode::SafeDownCast(node);
  if (!cnode)
    {
    return;
    }

  switch (column)
    {
    case qMRMLIGTLIOModel::NameColumn:
      {
      item->setText(cnode->GetName());
      insertIOTree(cnode);
      break;
      }
    case qMRMLIGTLIOModel::TypeColumn:
      {
      Q_ASSERT(cnode->GetType() < vtkMRMLIGTLConnectorNode::NUM_TYPE);
      //item->setText(QString(vtkMRMLIGTLConnectorNode::ConnectorTypeStr[cnode->GetType()]));
      item->setText("");
      break;
      }
    case qMRMLIGTLIOModel::StatusColumn:
      {
      Q_ASSERT(cnode->GetState() < vtkMRMLIGTLConnectorNode::NUM_STATE);
      //item->setText(QString(vtkMRMLIGTLConnectorNode::ConnectorStateStr[cnode->GetState()]));
      item->setText("");
      break;
      }
    default:
      break;
    }
}

//------------------------------------------------------------------------------
void qMRMLIGTLIOModel::addNodeToCurrentBranch(vtkMRMLNode* node)
{
  Q_D(qMRMLIGTLIOModel);

}

//------------------------------------------------------------------------------
void qMRMLIGTLIOModel::updateIOTreeBranch(vtkMRMLIGTLConnectorNode* node, QStandardItem* item, qMRMLIGTLIOModel::Direction dir)
{
  // List incoming data
  if (node == NULL)
    {
    return;
    }

  int nnodes;
  if (dir == qMRMLIGTLIOModel::INCOMING)
    {
    nnodes = node->GetNumberOfIncomingMRMLNodes();
    }
  else
    {
    nnodes = node->GetNumberOfOutgoingMRMLNodes();
    }

  for (int i = 0; i < nnodes; i ++)
    {
    vtkMRMLNode* inode;
    if (dir == qMRMLIGTLIOModel::INCOMING)
      {
      inode = node->GetIncomingMRMLNode(i);
      }
    else
      {
      inode = node->GetOutgoingMRMLNode(i);
      }
    if (inode != NULL)
      {
      QList<QStandardItem*> items;

      // Node name
      QStandardItem* item0 = new QStandardItem;
      item0->setText(inode->GetName());
      item0->setData("IOTree", qMRMLSceneModel::UIDRole);
      item0->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
      items << item0;

      // Node tag name
      QStandardItem* item1 = new QStandardItem;
      item1->setText(inode->GetNodeTagName());
      item1->setData("IOTree", qMRMLSceneModel::UIDRole);
      item1->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
      items << item1;

      // IGTL name
      QStandardItem* item2 = new QStandardItem;
      item2->setData("IOTree", qMRMLSceneModel::UIDRole);
      item2->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
      vtkIGTLToMRMLBase* converter = node->GetConverterByNodeID(inode->GetID());
      if (converter)
        {
        item2->setText(converter->GetIGTLName());
        }
      else
        {
        item2->setText("--");
        }
      items << item2;

      // Visible icon
      QStandardItem* item3 = new QStandardItem;
      const char * attr = inode->GetAttribute("IGTLVisible");
      if (attr && strcmp(attr, "true") == 0)
        {
        item3->setData(QPixmap(":/Icons/Small/SlicerVisible.png"),Qt::DecorationRole);
        }
      else
        {
        item3->setData(QPixmap(":/Icons/Small/SlicerInvisible.png"),Qt::DecorationRole);
        }
      item3->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable);
      items << item3;

      item->insertRow(i, items);
      }

    //// update extra item cache info (for faster retrieval)
    //QMap<QString, QVariant> extraItems = nodeItem->data(qMRMLSceneModel::ExtraItemsRole).toMap();
    //extraItems[extraType] = extraItems[extraType].toStringList() << text;
    //parent->setData(extraItems, qMRMLSceneModel::ExtraItemsRole );
    }
}

//------------------------------------------------------------------------------
QStandardItem* qMRMLIGTLIOModel::insertIOTree(vtkMRMLNode* node)
{
  Q_D(qMRMLIGTLIOModel);

  // Check if the node is a connector node
  vtkMRMLIGTLConnectorNode * cnode = vtkMRMLIGTLConnectorNode::SafeDownCast(node);
  if (!cnode)
    {
    return NULL;
    }

  QStandardItem* nodeItem = this->itemFromNode(node);
  if (nodeItem == 0 || d == 0)
    {
    return NULL;
    }

  d->removeAllExtraItems(nodeItem, "IOTree");
  QStandardItem* inItem = d->insertExtraItem2(nodeItem->rowCount(), nodeItem,
                                              QString("IN"), "IOTree", Qt::ItemIsEnabled|Qt::ItemIsSelectable);
  updateIOTreeBranch(cnode, inItem, qMRMLIGTLIOModel::INCOMING);
  QStandardItem* outItem = d->insertExtraItem2(nodeItem->rowCount(), nodeItem,
                                               QString("OUT"), "IOTree", Qt::ItemIsEnabled|Qt::ItemIsSelectable);
  updateIOTreeBranch(cnode, outItem, qMRMLIGTLIOModel::OUTGOING);

  return nodeItem;

}

//------------------------------------------------------------------------------
QStandardItem* qMRMLIGTLIOModel::insertNode(vtkMRMLNode* node)
{
  //return this->Superclass::insertNode(node);

  Q_D(qMRMLIGTLIOModel);
  QStandardItem* nodeItem = this->itemFromNode(node);
  if (nodeItem != 0)
    {
    // It is possible that the node has been already added if it is the parent
    // of a child node already inserted.
    return nodeItem;
    }
  vtkMRMLNode* parentNode = this->parentNode(node);
  QStandardItem* parentItem =
    parentNode ? this->itemFromNode(parentNode) : this->mrmlSceneItem();
  if (!parentItem)
    {
    Q_ASSERT(parentNode);
    parentItem = this->insertNode(parentNode);
    Q_ASSERT(parentItem);
    }
  int min = this->preItems(parentItem).count();
  int max = parentItem->rowCount() - this->postItems(parentItem).count();
  int row = min + this->nodeIndex(node);
  if (row > max)
    {
    d->MisplacedNodes << node;
    row = max;
    }
  nodeItem = this->insertNode(node, parentItem, row);
  Q_ASSERT(this->itemFromNode(node) == nodeItem);

  insertIOTree(node);

  //QStringList sl;
  //sl << "IN" << "OUT";
  //setPostItems(sl, nodeItem);

  return nodeItem;

}

<|endoftext|>