<commit_before>
/*
 * Copyright 2010 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkPDFFormXObject.h"

#include "SkMatrix.h"
#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFUtils.h"
#include "SkStream.h"
#include "SkTypes.h"

SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) {
    // We don't want to keep around device because we'd have two copies
    // of content, so reference or copy everything we need (content and
    // resources).
    device->getResources(&fResources, false);

    SkRefPtr<SkStream> content = device->content();
    content->unref();  // SkRefPtr and content() both took a reference.
    setData(content.get());

    insertName("Type", "XObject");
    insertName("Subtype", "Form");
    SkSafeUnref(this->insert("BBox", device->copyMediaBox()));
    insert("Resources", device->getResourceDict());

    // We invert the initial transform and apply that to the xobject so that
    // it doesn't get applied twice. We can't just undo it because it's
    // embedded in things like shaders and images.
    if (!device->initialTransform().isIdentity()) {
        SkMatrix inverse;
        if (!device->initialTransform().invert(&inverse)) {
            // The initial transform should be invertible.
            SkASSERT(false);
            inverse.reset();
        }
        insert("Matrix", SkPDFUtils::MatrixToArray(inverse))->unref();
    }

    // Right now SkPDFFormXObject is only used for saveLayer, which implies
    // isolated blending.  Do this conditionally if that changes.
    SkRefPtr<SkPDFDict> group = new SkPDFDict("Group");
    group->unref();  // SkRefPtr and new both took a reference.
    group->insertName("S", "Transparency");
    group->insert("I", new SkPDFBool(true))->unref();  // Isolated.
    insert("Group", group.get());
}

SkPDFFormXObject::~SkPDFFormXObject() {
    fResources.unrefAll();
}

void SkPDFFormXObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {
    GetResourcesHelper(&fResources, resourceList);
}
<commit_msg>PDF: Fail fast if in the tree of resources a child references a parent. Ideally I want a crash when the tree of resources became corrupt, not later when we try to finalize the pdf. Review URL: https://codereview.appspot.com/6740047<commit_after>
/*
 * Copyright 2010 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkPDFFormXObject.h"

#include "SkMatrix.h"
#include "SkPDFCatalog.h"
#include "SkPDFDevice.h"
#include "SkPDFUtils.h"
#include "SkStream.h"
#include "SkTypes.h"

SkPDFFormXObject::SkPDFFormXObject(SkPDFDevice* device) {
    // We don't want to keep around device because we'd have two copies
    // of content, so reference or copy everything we need (content and
    // resources).
    device->getResources(&fResources, false);

    // Fail fast if in the tree of resources a child references a parent.
    // If there is an issue, getResources will end up consuming all memory.
    // TODO: A better approach might be for all SkPDFObject to keep track
    // of possible cycles.
#ifdef SK_DEBUG
    SkTDArray<SkPDFObject*> dummy_resourceList;
    getResources(&dummy_resourceList);
#endif

    SkRefPtr<SkStream> content = device->content();
    content->unref();  // SkRefPtr and content() both took a reference.
    setData(content.get());

    insertName("Type", "XObject");
    insertName("Subtype", "Form");
    SkSafeUnref(this->insert("BBox", device->copyMediaBox()));
    insert("Resources", device->getResourceDict());

    // We invert the initial transform and apply that to the xobject so that
    // it doesn't get applied twice. We can't just undo it because it's
    // embedded in things like shaders and images.
    if (!device->initialTransform().isIdentity()) {
        SkMatrix inverse;
        if (!device->initialTransform().invert(&inverse)) {
            // The initial transform should be invertible.
            SkASSERT(false);
            inverse.reset();
        }
        insert("Matrix", SkPDFUtils::MatrixToArray(inverse))->unref();
    }

    // Right now SkPDFFormXObject is only used for saveLayer, which implies
    // isolated blending.  Do this conditionally if that changes.
    SkRefPtr<SkPDFDict> group = new SkPDFDict("Group");
    group->unref();  // SkRefPtr and new both took a reference.
    group->insertName("S", "Transparency");
    group->insert("I", new SkPDFBool(true))->unref();  // Isolated.
    insert("Group", group.get());
}

SkPDFFormXObject::~SkPDFFormXObject() {
    fResources.unrefAll();
}

void SkPDFFormXObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {
    GetResourcesHelper(&fResources, resourceList);
}
<|endoftext|>


<commit_before>/*
* Copyright (C) 2007-2013 German Aerospace Center (DLR/SC)
*
* Created: 2010-08-13 Markus Litz <Markus.Litz@dlr.de>
* Changed: $Id: main.cpp 203 2012-09-25 08:47:55Z martinsiggel $
*
* Version: $Revision: 203 $
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <iostream>
#include <fstream>
#include <clocale>

#include <QString>
#include <QtGui/QtGui>
#include <QtGui/QPlastiqueStyle>
#include <QMessageBox>

#include "TIGLViewerApplication.h"
#include "TIGLViewerWindow.h"
#include "CommandLineParameters.h"

using namespace std;

int parseArguments(QStringList);
void showHelp(QString);

int main(int argc, char *argv[])
{
    TIGLViewerApplication app( argc, argv );

#ifdef __APPLE__
    if (!getenv("CSF_GraphicShr")){
        static char env[64];
        strcpy(env,"CSF_GraphicShr=@executable_path/libTKOpenGl.dylib");
        putenv(env);
    }
#endif

#if defined __linux__
    // we need to set us locale as we use "." for decimal point
    putenv("LC_NUMERIC=C");
#elif defined __APPLE__
    setlocale(LC_NUMERIC, "C");
#endif

    int retval = parseArguments(app.arguments());
    if (retval != 0) {
        showHelp(app.arguments().at(0));
        return retval;
    }

    TIGLViewerWindow *window = new TIGLViewerWindow();
    window->show();

    if (!PARAMS.controlFile.isEmpty()){
        if (window->getMyOCC()) {
            window->getMyOCC()->repaint();
        }
        window->setInitialControlFile(PARAMS.controlFile);
    }

    // if a filename is given, open the configuration
    if (!PARAMS.initialFilename.isEmpty()) {
        if (window->getMyOCC()) {
            window->getMyOCC()->repaint();
        }
        window->setInitialCpacsFileName(PARAMS.initialFilename);
    }

    retval = app.exec();
    window->hide();
    delete window;
    return retval;
}

/**
 * Show a dialog with command line information.
 */
void showHelp(QString appName)
{
    QString helpText = appName + " [--help] [--filename <filename>]\n\n";
    helpText += "  --help                      This help page\n";
    helpText += "  --filename <filename>    Initial CPACS file to open and display.\n";
    helpText += "  --modelUID <uid>         Initial model uid open and display.\n";
    helpText += "  --windowtitle <title>    The titel of the TIGLViewer window.\n";
    helpText += "  --controlFile <filename>    Name of the control file.\n";
    helpText += "  --JediMode <on|off>      Makes you some kind of superhero like CPACS-Ninja.\n";

    QMessageBox::information(0, "TIGLViewer Argument Error",
                                 helpText,
                                 QMessageBox::Ok );
}

/**
 * Parsing the command line arguments. The values will be saved
 * in a global structure "PARAMS".
 */
int parseArguments(QStringList argList)
{
    for (int i = 1; i < argList.size(); i++) {
        QString arg = argList.at(i);
        if (arg.compare("--help") == 0) {
            return -1;
        }
        else if (arg.compare("--filename") == 0) {
            if (i+1 >= argList.size()) {
                cout << "missing filename" << endl;
                return -1;
            }
            else {
                PARAMS.initialFilename = argList.at(++i);
            }
        }
        else if (arg.compare("--windowtitle") == 0) {
            if (i+1 >= argList.size()) {
                cout << "missing windowtitle" << endl;
                PARAMS.windowTitle = "TIGLViewer";
            }
            else {
                PARAMS.windowTitle = argList.at(++i);
            }
        }
        else if (arg.compare("--modelUID") == 0) {
            if (i+1 >= argList.size()) {
                cout << "missing modelUID" << endl;
                PARAMS.modelUID = "";
            }
            else {
                PARAMS.modelUID = argList.at(++i);
            }
        }
        else if (arg.compare("--controlFile") == 0) {
            if (i+1 >= argList.size()) {
                cout << "missing controlFile" << endl;
                PARAMS.controlFile = "";
            }
            else {
                PARAMS.controlFile = argList.at(++i);
            }
        }
        /* when there is a string behind the executable, we assume its the filename */
        else {
            PARAMS.initialFilename = arg;
        }
    }

    return 0;
}

<commit_msg>Fixed TIGLViewer for some Linux systems<commit_after>/*
* Copyright (C) 2007-2013 German Aerospace Center (DLR/SC)
*
* Created: 2010-08-13 Markus Litz <Markus.Litz@dlr.de>
* Changed: $Id: main.cpp 203 2012-09-25 08:47:55Z martinsiggel $
*
* Version: $Revision: 203 $
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <iostream>
#include <fstream>
#include <clocale>

#include <QString>
#include <QtGui/QtGui>
#include <QtGui/QPlastiqueStyle>
#include <QMessageBox>

#include "TIGLViewerApplication.h"
#include "TIGLViewerWindow.h"
#include "CommandLineParameters.h"

using namespace std;

int parseArguments(QStringList);
void showHelp(QString);

int main(int argc, char *argv[])
{
    TIGLViewerApplication app( argc, argv );

#ifdef __APPLE__
    if (!getenv("CSF_GraphicShr")){
        static char env[64];
        strcpy(env,"CSF_GraphicShr=@executable_path/libTKOpenGl.dylib");
        putenv(env);
    }
#endif

#if defined __linux__
    // we need to set us locale as we use "." for decimal point
    putenv("LC_NUMERIC=C");
    setlocale(LC_NUMERIC, "C");
#elif defined __APPLE__
    setlocale(LC_NUMERIC, "C");
#endif

    int retval = parseArguments(app.arguments());
    if (retval != 0) {
        showHelp(app.arguments().at(0));
        return retval;
    }

    TIGLViewerWindow *window = new TIGLViewerWindow();
    window->show();

    if (!PARAMS.controlFile.isEmpty()){
        if (window->getMyOCC()) {
            window->getMyOCC()->repaint();
        }
        window->setInitialControlFile(PARAMS.controlFile);
    }

    // if a filename is given, open the configuration
    if (!PARAMS.initialFilename.isEmpty()) {
        if (window->getMyOCC()) {
            window->getMyOCC()->repaint();
        }
        window->setInitialCpacsFileName(PARAMS.initialFilename);
    }

    retval = app.exec();
    window->hide();
    delete window;
    return retval;
}

/**
 * Show a dialog with command line information.
 */
void showHelp(QString appName)
{
    QString helpText = appName + " [--help] [--filename <filename>]\n\n";
    helpText += "  --help                      This help page\n";
    helpText += "  --filename <filename>    Initial CPACS file to open and display.\n";
    helpText += "  --modelUID <uid>         Initial model uid open and display.\n";
    helpText += "  --windowtitle <title>    The titel of the TIGLViewer window.\n";
    helpText += "  --controlFile <filename>    Name of the control file.\n";
    helpText += "  --JediMode <on|off>      Makes you some kind of superhero like CPACS-Ninja.\n";

    QMessageBox::information(0, "TIGLViewer Argument Error",
                                 helpText,
                                 QMessageBox::Ok );
}

/**
 * Parsing the command line arguments. The values will be saved
 * in a global structure "PARAMS".
 */
int parseArguments(QStringList argList)
{
    for (int i = 1; i < argList.size(); i++) {
        QString arg = argList.at(i);
        if (arg.compare("--help") == 0) {
            return -1;
        }
        else if (arg.compare("--filename") == 0) {
            if (i+1 >= argList.size()) {
                cout << "missing filename" << endl;
                return -1;
            }
            else {
                PARAMS.initialFilename = argList.at(++i);
            }
        }
        else if (arg.compare("--windowtitle") == 0) {
            if (i+1 >= argList.size()) {
                cout << "missing windowtitle" << endl;
                PARAMS.windowTitle = "TIGLViewer";
            }
            else {
                PARAMS.windowTitle = argList.at(++i);
            }
        }
        else if (arg.compare("--modelUID") == 0) {
            if (i+1 >= argList.size()) {
                cout << "missing modelUID" << endl;
                PARAMS.modelUID = "";
            }
            else {
                PARAMS.modelUID = argList.at(++i);
            }
        }
        else if (arg.compare("--controlFile") == 0) {
            if (i+1 >= argList.size()) {
                cout << "missing controlFile" << endl;
                PARAMS.controlFile = "";
            }
            else {
                PARAMS.controlFile = argList.at(++i);
            }
        }
        /* when there is a string behind the executable, we assume its the filename */
        else {
            PARAMS.initialFilename = arg;
        }
    }

    return 0;
}

<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef HTTP_METHODS_HPP
#define HTTP_METHODS_HPP

#include <string>
#include <ostream>

namespace http {

  enum Method {
    GET, POST, PUT, DELETE, OPTIONS, HEAD, TRACE, CONNECT, PATCH,
    INVALID = 0xffff
  };

  namespace method {

    /** Get method string from method code **/
    inline const std::string& str(const Method m) {

      static std::array<std::string, 10> strings
      {
        {
         "GET", "POST", "PUT", "DELETE", "OPTIONS",
         "HEAD", "TRACE", "CONNECT", "PATCH", "INVALID"
        }
      };

      if ((m >= 0) and (m < (strings.size() - 1))) {
        return strings[m];
      }

      return strings[strings.size() - 1];
    }

    /**
     * Get a code mapping from an HTTP
     * method
     *
     * @param method - The HTTP method
     *
     * @return - The code mapped to the method
     **/
    inline Method code(const std::string& method) noexcept {

      if (method == str(GET))     return GET;
      if (method == str(POST))    return POST;
      if (method == str(PUT))     return PUT;
      if (method == str(DELETE))  return DELETE;
      if (method == str(OPTIONS)) return OPTIONS;
      if (method == str(HEAD))    return HEAD;
      if (method == str(TRACE))   return TRACE;
      if (method == str(CONNECT)) return CONNECT;
      if (method == str(PATCH))   return PATCH;

      return INVALID;
    }

  } // namespace method

  std::ostream& operator << (std::ostream& output_device, const Method m) {
    return output_device << http::method::str(m);
  }

} // namespace http

#endif // HTTP_METHODS_HPP
<commit_msg>Added missing include...<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef HTTP_METHODS_HPP
#define HTTP_METHODS_HPP

#include <array>
#include <string>
#include <ostream>

namespace http {

  enum Method {
    GET, POST, PUT, DELETE, OPTIONS, HEAD, TRACE, CONNECT, PATCH,
    INVALID = 0xffff
  };

  namespace method {

    /** Get method string from method code **/
    inline const std::string& str(const Method m) {

      static std::array<std::string, 10> strings
      {
        {
         "GET", "POST", "PUT", "DELETE", "OPTIONS",
         "HEAD", "TRACE", "CONNECT", "PATCH", "INVALID"
        }
      };

      if ((m >= 0) and (m < (strings.size() - 1))) {
        return strings[m];
      }

      return strings[strings.size() - 1];
    }

    /**
     * Get a code mapping from an HTTP
     * method
     *
     * @param method - The HTTP method
     *
     * @return - The code mapped to the method
     **/
    inline Method code(const std::string& method) noexcept {

      if (method == str(GET))     return GET;
      if (method == str(POST))    return POST;
      if (method == str(PUT))     return PUT;
      if (method == str(DELETE))  return DELETE;
      if (method == str(OPTIONS)) return OPTIONS;
      if (method == str(HEAD))    return HEAD;
      if (method == str(TRACE))   return TRACE;
      if (method == str(CONNECT)) return CONNECT;
      if (method == str(PATCH))   return PATCH;

      return INVALID;
    }

  } // namespace method

  std::ostream& operator << (std::ostream& output_device, const Method m) {
    return output_device << http::method::str(m);
  }

} // namespace http

#endif // HTTP_METHODS_HPP
<|endoftext|>


<commit_before>#include "common/dev_config.h"

#include "ISprite.h"

#include "ISymbol.h"

#include "common/Math.h"
#include "common/Matrix.h"
#include "common/color_trans.h"
#include "common/Exception.h"
#include "common/config.h"
#include "dataset/BVFactory.h"
#include "dataset/AbstractBV.h"
#include "dataset/SpriteFactory.h"
#include "view/SpritePropertySetting.h"

#ifdef OPEN_SCREEN_CACHE
#include "render/SpriteRenderer.h"
#include "render/SpatialIndex.h"
#endif // OPEN_SCREEN_CACHE

#include <cmath>

namespace d2d
{

ISprite::ISprite()
	: m_observer(NULL)
{
	multiCol.set(1, 1, 1, 1);
	addCol.set(0, 0, 0, 0);
	r_trans.set(1, 0, 0, 1);
	g_trans.set(0, 1, 0, 1);
	b_trans.set(0, 0, 1, 1);

	clip = false;

	visiable = editable = true;

	m_angle = 0.0f;
	m_scale.set(1, 1);
	m_shear.set(0, 0);
	m_xMirror = m_yMirror = false;
	m_perspective.set(0, 0);
	m_bounding = NULL;

	m_blend_mode = BM_NORMAL;
	m_filter_mode = FM_NORMAL;

	m_is_anchor = false;
}

ISprite::ISprite(const ISprite& sprite)
	: m_observer(NULL)
{
	name = sprite.name;
	multiCol = sprite.multiCol;
	addCol = sprite.addCol;
	clip = sprite.clip;
	r_trans = sprite.r_trans;
	g_trans = sprite.g_trans;
	b_trans = sprite.b_trans;

	visiable = sprite.visiable;
	editable = sprite.editable;
	tag = sprite.tag;

	m_pos = sprite.m_pos;
	m_angle = sprite.m_angle;
	m_offset = sprite.m_offset;
	m_scale = sprite.m_scale;
	m_shear = sprite.m_shear;
	m_xMirror = sprite.m_xMirror;
	m_yMirror = sprite.m_yMirror;
	m_perspective = sprite.m_perspective;
	m_bounding = sprite.m_bounding->Clone();

	m_blend_mode = sprite.m_blend_mode;
	m_filter_mode = sprite.m_filter_mode;

	m_is_anchor = sprite.m_is_anchor;
}

ISprite::~ISprite()
{
	delete m_bounding;
	SpriteFactory::Instance()->remove(this);
}

ISprite* ISprite::Clone() const
{
	return NULL;
}

void ISprite::ClearUserData(bool deletePtr)
{
	delete m_userData, m_userData = NULL;
}

void ISprite::Load(const Json::Value& val)
{
	// info
	name = val["name"].asString();
	tag = val["tag"].asString();
	clip = val["clip"].asBool();

	// color
	std::string str = val["multi color"].asString();
	if (str.empty())
		multiCol = Colorf(1, 1, 1, 1);
	else
		multiCol = transColor(str, PT_BGRA);
	str = val["add color"].asString();
	if (str.empty())
		addCol = Colorf(0, 0, 0, 0);
	else
		addCol = transColor(str, PT_ABGR);

	str = val["r trans"].asString();
	if (str.empty())
		r_trans = Colorf(1, 0, 0, 1);
	else
		r_trans = transColor(str, PT_RGBA);
	str = val["g trans"].asString();
	if (str.empty())
		g_trans = Colorf(0, 1, 0, 1);
	else
		g_trans = transColor(str, PT_RGBA);
	str = val["b trans"].asString();
	if (str.empty())
		b_trans = Colorf(0, 0, 1, 1);
	else
		b_trans = transColor(str, PT_RGBA);

	// scale
	float sx, sy;
	if (val["scale"].isNull())
	{
		sx = val["x scale"].asDouble();
		sy = val["y scale"].asDouble();
	}
	else
	{
		sx = sy = val["scale"].asDouble();
	}
	SetScale(sx, sy);

	// shear
	float kx, ky;
	if (!val["x shear"].isNull())
	{
		kx = val["x shear"].asDouble();
		ky = val["y shear"].asDouble();
	}
	else
	{
		kx = ky = 0;
	}
	SetShear(kx, ky);

	// mirror
	bool mx = val["x mirror"].asBool();
	bool my = val["y mirror"].asBool();
	SetMirror(mx, my);

	// perspective
	if (!val["x perspective"].isNull())
	{
		Vector persp;
		persp.x = val["x perspective"].asDouble();
		persp.y = val["y perspective"].asDouble();
		SetPerspective(persp);
	}

	// offset
	float ox, oy;
	if (!val["x offset"].isNull())
	{
		ox = val["x offset"].asDouble();
		oy = val["y offset"].asDouble();
	}
	else
	{
		ox = oy = 0;
	}
	SetOffset(Vector(ox, oy));

	// translate
	float x = val["position"]["x"].asDouble();
	float y = val["position"]["y"].asDouble();
	if (fabs(x) >= FLT_MAX || fabs(y) >= FLT_MAX) {
		throw Exception("sprite pos err, filepath: %s, name: %s", val["filepath"].asString().c_str(), name.c_str());
	}

	// rotate
	float angle = val["angle"].asDouble();
	SetTransform(Vector(x, y), angle);

	// filter
	if (!val["filter"].isNull()) {
		std::string disc = val["filter"].asString();
		if (Config::Instance()->IsRenderOpen()) {
			m_filter_mode = FilterModes::Instance()->GetIDFromNameEN(disc);
		}
	}

	// anchor
	m_is_anchor = val["anchor"].asBool();
}

void ISprite::Store(Json::Value& val) const
{
	val["name"] = name;
	val["tag"] = tag;
	val["clip"] = clip;

	val["multi color"] = transColor(multiCol, PT_BGRA);
	val["add color"] = transColor(addCol, PT_ABGR);
	val["r trans"] = transColor(r_trans, PT_RGBA);
	val["g trans"] = transColor(g_trans, PT_RGBA);
	val["b trans"] = transColor(b_trans, PT_RGBA);

	val["position"]["x"] = m_pos.x;
	val["position"]["y"] = m_pos.y;

	val["angle"] = m_angle;

	val["x scale"] = m_scale.x;
	val["y scale"] = m_scale.y;

	val["x shear"] = m_shear.x;
	val["y shear"] = m_shear.y;

	val["x mirror"] = m_xMirror;
	val["y mirror"] = m_yMirror;

	val["x offset"] = m_offset.x;
	val["y offset"] = m_offset.y;

	val["x perspective"] = m_perspective.x;
	val["y perspective"] = m_perspective.y;

	if (Config::Instance()->IsRenderOpen()) {
		val["filter"] = FilterModes::Instance()->GetNameENFromID(m_filter_mode);
	}

	val["anchor"] = m_is_anchor;
}

void ISprite::BuildBounding()
{
	if (!m_bounding) {
		m_bounding = BVFactory::createBV(e_obb);
	}
	const ISymbol& symbol = GetSymbol();
	Rect rect(symbol.GetSize(this));
	if (!rect.isValid()) {
		return;
	}

	if (m_offset.x == 0 && m_offset.y == 0) {
		m_offset.set(rect.xCenter(), rect.yCenter());
	}
	rect.scale(m_scale.x, m_scale.y);
	rect.shear(m_shear.x, m_shear.y);
	m_bounding->initFromRect(rect);
	m_bounding->SetTransform(m_pos, m_offset, m_angle);
}

IPropertySetting* ISprite::CreatePropertySetting(EditPanelImpl* stage)
{
	return new SpritePropertySetting(stage, this);
}

void ISprite::SetTransform(const Vector& position, float angle)
{
	if (m_pos != position) Translate(position - m_pos);
	if (m_angle != angle) Rotate(angle - m_angle);
}

void ISprite::SetScale(float xScale, float yScale)
{
	Vector dscale;
	dscale.x = xScale / m_scale.x;
	dscale.y = yScale / m_scale.y;

	Vector old_offset = m_offset;
	Vector new_offset(m_offset.x * dscale.x, m_offset.y * dscale.y);
	m_offset = new_offset;

	Translate(old_offset - new_offset);

	//////////////////////////////////////////////////////////////////////////

// 	Matrix mat_old, mat_new;
// 	mat_old.scale(m_scale.x, m_scale.y);
// 	mat_new.scale(xScale, yScale);
//
// 	Vector offset = Math::transVector(m_offset, mat_new) - Math::transVector(m_offset, mat_old);
//
// 	m_offset += offset;
// 	translate(-offset);

	//////////////////////////////////////////////////////////////////////////

	m_scale.set(xScale, yScale);
	BuildBounding();
 }

void ISprite::SetShear(float xShear, float yShear)
{
	Matrix mat_old, mat_new;
	mat_old.shear(m_shear.x, m_shear.y);
	mat_new.shear(xShear, yShear);

	Vector offset = Math::transVector(m_offset, mat_new) - Math::transVector(m_offset, mat_old);

	m_offset += offset;
	Translate(-offset);

	m_shear.set(xShear, yShear);
	BuildBounding();
}

bool ISprite::IsContain(const Vector& pos) const
{
	return m_bounding ? m_bounding->isContain(pos) : false;
}

bool ISprite::IsIntersect(const Rect& rect) const
{
	return m_bounding ? m_bounding->isIntersect(rect) : false;
}

void ISprite::Translate(const Vector& offset)
{
#ifdef OPEN_SCREEN_CACHE
	bool find = SpatialIndex::Instance()->Remove(this);
	if (find) {
		SpriteRenderer::Instance()->InvalidRect(this);
	}
#endif // OPEN_SCREEN_CACHE

	if (m_observer)
		m_observer->Translate(this, offset);

	m_pos += offset;
	if (m_bounding) {
		m_bounding->SetTransform(m_pos, m_offset, m_angle);
	}

#ifdef OPEN_SCREEN_CACHE
	if (find) {
		SpriteRenderer::Instance()->InvalidRect(this);
		SpatialIndex::Instance()->Insert(this);
	}
#endif // OPEN_SCREEN_CACHE
}

void ISprite::Rotate(float delta)
{
#ifdef OPEN_SCREEN_CACHE
	SpatialIndex::Instance()->Remove(this);
#endif // OPEN_SCREEN_CACHE

	if (m_observer)
		m_observer->Rotate(this, delta);

	m_angle += delta;

	if (m_bounding) {
		m_bounding->SetTransform(m_pos, m_offset, m_angle);
	}

#ifdef OPEN_SCREEN_CACHE
	SpatialIndex::Instance()->Insert(this);
#endif // OPEN_SCREEN_CACHE
}

void ISprite::SetOffset(const Vector& offset)
{
	// rotate + offset -> offset + rotate
	Vector old_center = GetCenter();
	m_offset = offset;
	Vector new_center = GetCenter();
	m_pos += (old_center - new_center);

	if (m_bounding) {
		m_bounding->SetTransform(m_pos, m_offset, m_angle);
	}
}

void ISprite::SetMirror(bool xMirror, bool yMirror)
{
	bool x_dirty = xMirror != m_xMirror,
		 y_dirty = yMirror != m_yMirror;

	if (x_dirty) {
		m_offset.x = -m_offset.x;
	}
	if (y_dirty) {
		m_offset.y = -m_offset.y;
	}

	m_xMirror = xMirror; m_yMirror = yMirror;
	if (m_bounding) {
		m_bounding->SetMirror(x_dirty, y_dirty);
		m_bounding->SetTransform(m_pos, m_offset, m_angle);
	}
}

Vector ISprite::GetCenter() const
{
	d2d::Vector center_offset = Math::rotateVector(-m_offset, m_angle) + m_offset;
	d2d::Vector center = m_pos + center_offset;
	return center;
}

d2d::Rect ISprite::GetRect() const
{
	std::vector<Vector> bound;
	GetBounding()->getBoundPos(bound);
	d2d::Rect rect;
	for (int i = 0, n = bound.size(); i < n; ++i) {
		rect.combine(bound[i]);
	}
	return rect;
}

void ISprite::GetTransMatrix(Matrix& mt) const
{
	const float xScale = m_xMirror ? -m_scale.x : m_scale.x,
		yScale = m_yMirror ? -m_scale.y : m_scale.y;

	d2d::Vector center = GetCenter();
	mt.setTransformation(center.x, center.y, m_angle,
		xScale, yScale, 0, 0, m_shear.x, m_shear.y);
}

Matrix ISprite::GetTransInvMatrix() const
{
	d2d::Matrix mat;
	mat.rotate(-m_angle);
	mat.shear(-m_shear.x, -m_shear.y);
	mat.translate(-m_pos.x/m_scale.x, -m_pos.y/m_scale.y);
	mat.scale(1/m_scale.x, 1/m_scale.y);
	return mat;
}

//////////////////////////////////////////////////////////////////////////
// class SpriteCmp
//////////////////////////////////////////////////////////////////////////

SpriteCmp::SpriteCmp(Type type /*= e_file*/)
	: m_type(type)
{
}

bool SpriteCmp::operator() (const ISprite* s0, const ISprite* s1) const
{
	switch (m_type)
	{
	case e_file:
		return s0->GetSymbol().GetFilepath() < s1->GetSymbol().GetFilepath();
	case e_x:
		return s0->GetPosition().x < s1->GetPosition().x;
	case e_y:
		return s0->GetPosition().y < s1->GetPosition().y;
	case e_x_invert:
		return s0->GetPosition().x > s1->GetPosition().x;
	case e_y_invert:
		return s0->GetPosition().y > s1->GetPosition().y;
	default:
		return s0->GetSymbol().GetFilepath() < s1->GetSymbol().GetFilepath();
	}
}

} // d2d<commit_msg>[FIXED] sprite offset init<commit_after>#include "common/dev_config.h"

#include "ISprite.h"

#include "ISymbol.h"

#include "common/Math.h"
#include "common/Matrix.h"
#include "common/color_trans.h"
#include "common/Exception.h"
#include "common/config.h"
#include "dataset/BVFactory.h"
#include "dataset/AbstractBV.h"
#include "dataset/SpriteFactory.h"
#include "view/SpritePropertySetting.h"

#ifdef OPEN_SCREEN_CACHE
#include "render/SpriteRenderer.h"
#include "render/SpatialIndex.h"
#endif // OPEN_SCREEN_CACHE

#include <cmath>

namespace d2d
{

ISprite::ISprite()
	: m_observer(NULL)
{
	multiCol.set(1, 1, 1, 1);
	addCol.set(0, 0, 0, 0);
	r_trans.set(1, 0, 0, 1);
	g_trans.set(0, 1, 0, 1);
	b_trans.set(0, 0, 1, 1);

	clip = false;

	visiable = editable = true;

	m_angle = 0.0f;
	m_offset.setInvalid();
	m_scale.set(1, 1);
	m_shear.set(0, 0);
	m_xMirror = m_yMirror = false;
	m_perspective.set(0, 0);
	m_bounding = NULL;

	m_blend_mode = BM_NORMAL;
	m_filter_mode = FM_NORMAL;

	m_is_anchor = false;
}

ISprite::ISprite(const ISprite& sprite)
	: m_observer(NULL)
{
	name = sprite.name;
	multiCol = sprite.multiCol;
	addCol = sprite.addCol;
	clip = sprite.clip;
	r_trans = sprite.r_trans;
	g_trans = sprite.g_trans;
	b_trans = sprite.b_trans;

	visiable = sprite.visiable;
	editable = sprite.editable;
	tag = sprite.tag;

	m_pos = sprite.m_pos;
	m_angle = sprite.m_angle;
	m_offset = sprite.m_offset;
	m_scale = sprite.m_scale;
	m_shear = sprite.m_shear;
	m_xMirror = sprite.m_xMirror;
	m_yMirror = sprite.m_yMirror;
	m_perspective = sprite.m_perspective;
	m_bounding = sprite.m_bounding->Clone();

	m_blend_mode = sprite.m_blend_mode;
	m_filter_mode = sprite.m_filter_mode;

	m_is_anchor = sprite.m_is_anchor;
}

ISprite::~ISprite()
{
	delete m_bounding;
	SpriteFactory::Instance()->remove(this);
}

ISprite* ISprite::Clone() const
{
	return NULL;
}

void ISprite::ClearUserData(bool deletePtr)
{
	delete m_userData, m_userData = NULL;
}

void ISprite::Load(const Json::Value& val)
{
	// info
	name = val["name"].asString();
	tag = val["tag"].asString();
	clip = val["clip"].asBool();

	// color
	std::string str = val["multi color"].asString();
	if (str.empty())
		multiCol = Colorf(1, 1, 1, 1);
	else
		multiCol = transColor(str, PT_BGRA);
	str = val["add color"].asString();
	if (str.empty())
		addCol = Colorf(0, 0, 0, 0);
	else
		addCol = transColor(str, PT_ABGR);

	str = val["r trans"].asString();
	if (str.empty())
		r_trans = Colorf(1, 0, 0, 1);
	else
		r_trans = transColor(str, PT_RGBA);
	str = val["g trans"].asString();
	if (str.empty())
		g_trans = Colorf(0, 1, 0, 1);
	else
		g_trans = transColor(str, PT_RGBA);
	str = val["b trans"].asString();
	if (str.empty())
		b_trans = Colorf(0, 0, 1, 1);
	else
		b_trans = transColor(str, PT_RGBA);

	// scale
	float sx, sy;
	if (val["scale"].isNull())
	{
		sx = val["x scale"].asDouble();
		sy = val["y scale"].asDouble();
	}
	else
	{
		sx = sy = val["scale"].asDouble();
	}
	SetScale(sx, sy);

	// shear
	float kx, ky;
	if (!val["x shear"].isNull())
	{
		kx = val["x shear"].asDouble();
		ky = val["y shear"].asDouble();
	}
	else
	{
		kx = ky = 0;
	}
	SetShear(kx, ky);

	// mirror
	bool mx = val["x mirror"].asBool();
	bool my = val["y mirror"].asBool();
	SetMirror(mx, my);

	// perspective
	if (!val["x perspective"].isNull())
	{
		Vector persp;
		persp.x = val["x perspective"].asDouble();
		persp.y = val["y perspective"].asDouble();
		SetPerspective(persp);
	}

	// offset
	float ox, oy;
	if (!val["x offset"].isNull())
	{
		ox = val["x offset"].asDouble();
		oy = val["y offset"].asDouble();
	}
	else
	{
		ox = oy = 0;
	}
	SetOffset(Vector(ox, oy));

	// translate
	float x = val["position"]["x"].asDouble();
	float y = val["position"]["y"].asDouble();
	if (fabs(x) >= FLT_MAX || fabs(y) >= FLT_MAX) {
		throw Exception("sprite pos err, filepath: %s, name: %s", val["filepath"].asString().c_str(), name.c_str());
	}

	// rotate
	float angle = val["angle"].asDouble();
	SetTransform(Vector(x, y), angle);

	// filter
	if (!val["filter"].isNull()) {
		std::string disc = val["filter"].asString();
		if (Config::Instance()->IsRenderOpen()) {
			m_filter_mode = FilterModes::Instance()->GetIDFromNameEN(disc);
		}
	}

	// anchor
	m_is_anchor = val["anchor"].asBool();
}

void ISprite::Store(Json::Value& val) const
{
	val["name"] = name;
	val["tag"] = tag;
	val["clip"] = clip;

	val["multi color"] = transColor(multiCol, PT_BGRA);
	val["add color"] = transColor(addCol, PT_ABGR);
	val["r trans"] = transColor(r_trans, PT_RGBA);
	val["g trans"] = transColor(g_trans, PT_RGBA);
	val["b trans"] = transColor(b_trans, PT_RGBA);

	val["position"]["x"] = m_pos.x;
	val["position"]["y"] = m_pos.y;

	val["angle"] = m_angle;

	val["x scale"] = m_scale.x;
	val["y scale"] = m_scale.y;

	val["x shear"] = m_shear.x;
	val["y shear"] = m_shear.y;

	val["x mirror"] = m_xMirror;
	val["y mirror"] = m_yMirror;

	val["x offset"] = m_offset.x;
	val["y offset"] = m_offset.y;

	val["x perspective"] = m_perspective.x;
	val["y perspective"] = m_perspective.y;

	if (Config::Instance()->IsRenderOpen()) {
		val["filter"] = FilterModes::Instance()->GetNameENFromID(m_filter_mode);
	}

	val["anchor"] = m_is_anchor;
}

void ISprite::BuildBounding()
{
	if (!m_bounding) {
		m_bounding = BVFactory::createBV(e_obb);
	}
	const ISymbol& symbol = GetSymbol();
	Rect rect(symbol.GetSize(this));
	if (!rect.isValid()) {
		return;
	}

	if (!m_offset.isValid()) {
		m_offset.set(rect.xCenter(), rect.yCenter());
	}
	rect.scale(m_scale.x, m_scale.y);
	rect.shear(m_shear.x, m_shear.y);
	m_bounding->initFromRect(rect);
	m_bounding->SetTransform(m_pos, m_offset, m_angle);
}

IPropertySetting* ISprite::CreatePropertySetting(EditPanelImpl* stage)
{
	return new SpritePropertySetting(stage, this);
}

void ISprite::SetTransform(const Vector& position, float angle)
{
	if (m_pos != position) Translate(position - m_pos);
	if (m_angle != angle) Rotate(angle - m_angle);
}

void ISprite::SetScale(float xScale, float yScale)
{
	Vector dscale;
	dscale.x = xScale / m_scale.x;
	dscale.y = yScale / m_scale.y;

	Vector old_offset = m_offset;
	Vector new_offset(m_offset.x * dscale.x, m_offset.y * dscale.y);
	m_offset = new_offset;

	Translate(old_offset - new_offset);

	//////////////////////////////////////////////////////////////////////////

// 	Matrix mat_old, mat_new;
// 	mat_old.scale(m_scale.x, m_scale.y);
// 	mat_new.scale(xScale, yScale);
//
// 	Vector offset = Math::transVector(m_offset, mat_new) - Math::transVector(m_offset, mat_old);
//
// 	m_offset += offset;
// 	translate(-offset);

	//////////////////////////////////////////////////////////////////////////

	m_scale.set(xScale, yScale);
	BuildBounding();
 }

void ISprite::SetShear(float xShear, float yShear)
{
	Matrix mat_old, mat_new;
	mat_old.shear(m_shear.x, m_shear.y);
	mat_new.shear(xShear, yShear);

	Vector offset = Math::transVector(m_offset, mat_new) - Math::transVector(m_offset, mat_old);

	m_offset += offset;
	Translate(-offset);

	m_shear.set(xShear, yShear);
	BuildBounding();
}

bool ISprite::IsContain(const Vector& pos) const
{
	return m_bounding ? m_bounding->isContain(pos) : false;
}

bool ISprite::IsIntersect(const Rect& rect) const
{
	return m_bounding ? m_bounding->isIntersect(rect) : false;
}

void ISprite::Translate(const Vector& offset)
{
#ifdef OPEN_SCREEN_CACHE
	bool find = SpatialIndex::Instance()->Remove(this);
	if (find) {
		SpriteRenderer::Instance()->InvalidRect(this);
	}
#endif // OPEN_SCREEN_CACHE

	if (m_observer)
		m_observer->Translate(this, offset);

	m_pos += offset;
	if (m_bounding) {
		m_bounding->SetTransform(m_pos, m_offset, m_angle);
	}

#ifdef OPEN_SCREEN_CACHE
	if (find) {
		SpriteRenderer::Instance()->InvalidRect(this);
		SpatialIndex::Instance()->Insert(this);
	}
#endif // OPEN_SCREEN_CACHE
}

void ISprite::Rotate(float delta)
{
#ifdef OPEN_SCREEN_CACHE
	SpatialIndex::Instance()->Remove(this);
#endif // OPEN_SCREEN_CACHE

	if (m_observer)
		m_observer->Rotate(this, delta);

	m_angle += delta;

	if (m_bounding) {
		m_bounding->SetTransform(m_pos, m_offset, m_angle);
	}

#ifdef OPEN_SCREEN_CACHE
	SpatialIndex::Instance()->Insert(this);
#endif // OPEN_SCREEN_CACHE
}

void ISprite::SetOffset(const Vector& offset)
{
	// rotate + offset -> offset + rotate
	Vector old_center = GetCenter();
	m_offset = offset;
	Vector new_center = GetCenter();
	m_pos += (old_center - new_center);

	if (m_bounding) {
		m_bounding->SetTransform(m_pos, m_offset, m_angle);
	}
}

void ISprite::SetMirror(bool xMirror, bool yMirror)
{
	bool x_dirty = xMirror != m_xMirror,
		 y_dirty = yMirror != m_yMirror;

	if (x_dirty) {
		m_offset.x = -m_offset.x;
	}
	if (y_dirty) {
		m_offset.y = -m_offset.y;
	}

	m_xMirror = xMirror; m_yMirror = yMirror;
	if (m_bounding) {
		m_bounding->SetMirror(x_dirty, y_dirty);
		m_bounding->SetTransform(m_pos, m_offset, m_angle);
	}
}

Vector ISprite::GetCenter() const
{
	d2d::Vector center_offset = Math::rotateVector(-m_offset, m_angle) + m_offset;
	d2d::Vector center = m_pos + center_offset;
	return center;
}

d2d::Rect ISprite::GetRect() const
{
	std::vector<Vector> bound;
	GetBounding()->getBoundPos(bound);
	d2d::Rect rect;
	for (int i = 0, n = bound.size(); i < n; ++i) {
		rect.combine(bound[i]);
	}
	return rect;
}

void ISprite::GetTransMatrix(Matrix& mt) const
{
	const float xScale = m_xMirror ? -m_scale.x : m_scale.x,
		yScale = m_yMirror ? -m_scale.y : m_scale.y;

	d2d::Vector center = GetCenter();
	mt.setTransformation(center.x, center.y, m_angle,
		xScale, yScale, 0, 0, m_shear.x, m_shear.y);
}

Matrix ISprite::GetTransInvMatrix() const
{
	d2d::Matrix mat;
	mat.rotate(-m_angle);
	mat.shear(-m_shear.x, -m_shear.y);
	mat.translate(-m_pos.x/m_scale.x, -m_pos.y/m_scale.y);
	mat.scale(1/m_scale.x, 1/m_scale.y);
	return mat;
}

//////////////////////////////////////////////////////////////////////////
// class SpriteCmp
//////////////////////////////////////////////////////////////////////////

SpriteCmp::SpriteCmp(Type type /*= e_file*/)
	: m_type(type)
{
}

bool SpriteCmp::operator() (const ISprite* s0, const ISprite* s1) const
{
	switch (m_type)
	{
	case e_file:
		return s0->GetSymbol().GetFilepath() < s1->GetSymbol().GetFilepath();
	case e_x:
		return s0->GetPosition().x < s1->GetPosition().x;
	case e_y:
		return s0->GetPosition().y < s1->GetPosition().y;
	case e_x_invert:
		return s0->GetPosition().x > s1->GetPosition().x;
	case e_y_invert:
		return s0->GetPosition().y > s1->GetPosition().y;
	default:
		return s0->GetSymbol().GetFilepath() < s1->GetSymbol().GetFilepath();
	}
}

} // d2d<|endoftext|>


<commit_before>/*    Copyright (c) 2010-2019, Delft University of Technology
 *    All rigths reserved
 *
 *    This file is part of the Tudat. Redistribution and use in source and
 *    binary forms, with or without modification, are permitted exclusively
 *    under the terms of the Modified BSD license. You should have received
 *    a copy of the license with this file. If not, please or visit:
 *    http://tudat.tudelft.nl/LICENSE.
 *
 */

#include "Tudat/Astrodynamics/Ephemerides/tleEphemeris.h"
#include "Tudat/Astrodynamics/BasicAstrodynamics/unitConversions.h"
#include "Tudat/External/SpiceInterface/spiceInterface.h"
#include "Tudat/External/SofaInterface/earthOrientation.h"
#include "Tudat/External/SofaInterface/sofaTimeConversions.h"
#include "boost/algorithm/string.hpp"

namespace tudat
{

namespace ephemerides
{

	TleEphemeris::TleEphemeris( const std::string &referenceFrameOrigin, const std::string &referenceFrameOrientation,
							   const std::shared_ptr< Tle > tle_ptr, const bool useSDP ) :
							   Ephemeris( referenceFrameOrigin, referenceFrameOrientation )
	{
		if( referenceFrameOrigin != "Earth" )
		{
			throw std::runtime_error( "Error: TleEphemeris only supports an Earth-centered reference frame." );
		}
		if( useSDP )
		{
			throw std::runtime_error( "TLE SDP propagator requested, which is not yet implemented." );
		}
		useSDP_ = useSDP;
		tle_ = tle_ptr;
		// Create table with ephemeris data
		// Create interpolator based on table

	}

	Eigen::Vector6d TleEphemeris::getCartesianState( double secondsSinceEpoch )
	{
		// Call Spice interface to retrieve the spacecraft's state from the TLE in the True Equator, Mean Equinox frame (see
		// Vallado: Fundamentals of Astrodynamics and Applications 4th ed. (2013)). This frame is idiosyncratic in nature and
		// therefore needs to be converted to an intermediate standard reference frame.
		const Eigen::Vector6d cartesianStateAtEpochTEME =
				spice_interface::getCartesianStateFromTleAtEpoch( secondsSinceEpoch, tle_ );

		Eigen::Vector3d positionTEME = cartesianStateAtEpochTEME.head( 3 );
		Eigen::Vector3d velocityTEME = cartesianStateAtEpochTEME.tail( 3 );

		// First, rotate to the True Of Date (TOD) frame.
		double equationOfEquinoxes = sofa_interface::calculateEquationOfEquinoxes( secondsSinceEpoch );

		// Rotate around pole (z-axis)
		Eigen::AngleAxisd rotationObject = Eigen::AngleAxisd( equationOfEquinoxes, Eigen::Vector3d::UnitZ( ) );
		Eigen::Vector3d positionTOD = rotationObject.toRotationMatrix( ) * positionTEME;
		Eigen::Vector3d velocityTOD = rotationObject.toRotationMatrix( ) * velocityTEME;

		// These angles (zeta, z, and theta) do not really have descriptive names. For a description of the precession geometry and these angles,
		// see pages 226-228 and figure 3-31 in Vallado (2013).
		double precessionAngleModToGcrfZeta;
		double precessionAngleModToGcrfZ;
		double precessionAngleModToGcrfTheta;
		sofa_interface::getPrecessionAngles(precessionAngleModToGcrfZeta, precessionAngleModToGcrfZ, precessionAngleModToGcrfTheta,
				secondsSinceEpoch );

		// Now that we have our state vector in the TOD frame, we need to obtain the combined precession + nutation matrix from Sofa
		// (according to the 1976/1980 model)
		Eigen::Matrix3d precessionNutationMatrix = sofa_interface::getPrecessionNutationMatrix( secondsSinceEpoch );
		// Multiply by inverted matrix to get to J2000
		Eigen::Vector3d  positionJ2000 = precessionNutationMatrix.transpose( ) * positionTOD;
		Eigen::Vector3d  velocityJ2000 = precessionNutationMatrix.transpose( ) * velocityTOD;

		if( referenceFrameOrientation_ == "J2000" )
		{
			Eigen::Vector6d stateJ2000;
			stateJ2000 << positionJ2000, velocityJ2000;
			return stateJ2000;
		}
		else if( referenceFrameOrientation_ == "ECLIPJ2000" )
		{
			Eigen::Quaterniond itrsToEclipticQuaternion = spice_interface::computeRotationQuaternionBetweenFrames(
					"J2000", "ECLIPJ2000", secondsSinceEpoch );
			Eigen::Vector3d positionEclipJ2000 = itrsToEclipticQuaternion * positionJ2000;
			Eigen::Vector3d velocityEclipJ2000 = itrsToEclipticQuaternion * velocityJ2000;
			Eigen::Vector6d stateEclipJ2000;
			stateEclipJ2000 << positionEclipJ2000, velocityEclipJ2000;
			return stateEclipJ2000;
		}
		else
		{
			throw std::runtime_error( "TLE state conversion to target frame " + referenceFrameOrientation_ + " is currently unsupported." );
		}

		return cartesianStateAtEpochTEME;
	}

	Tle::Tle( const std::string& lines )
	{
		// First of all, the TLE lines to be checked for validity: they shall not be empty, contain more than 69 characters
		// or have an invalid checksum.
		// Although unlikely, TLEs can become corrupted due to (un)intentional changes or data corruption during transmission.

		// Check if string is not empty
		if( lines.empty() )
		{
			throw std::runtime_error( "Error: TLE class was instantiated with string object, but string is empty." );
		}
		std::vector< std::string > tleLines;
		boost::algorithm::split( tleLines, lines, boost::is_any_of( "\n" ) );
		if( tleLines.size() != 2 )
		{
			throw std::runtime_error( "Error: TLE class was instantiated with string object, but string contains more than 2 lines." );
		}
		// Check line length
		for( std::string& line : tleLines )
		{
			if( line.length() != 69 )
			{
				throw std::runtime_error("Error: TLE class was instantiated with string object, but one or more lines contain an invalid "
							 "number of characters." );
			}
			// TODO: checksum verification
			int checksum = 0;
			for( unsigned int i = 0; i < line.length( ) - 1; i++ )
			{
				char c = line[ i ];
				if( c == '-' )
				{
					checksum++;
				}
				else if( std::isdigit( c ) )
				{
					checksum += static_cast< int >( c ) - 48;
				}
				// Else do nothing
			}
			checksum %= 10;
			if(checksum == static_cast< int >( line[ 68 ] ) - 48 )
			{
				std::cout << "TLE checksum verified." << std::endl;
			}
			else
			{
				throw std::runtime_error( "TLE checksum invalid!" );
			}
		}

		// Parse TLE
		std::string line1 = tleLines.at( 0 );
		std::string line2 = tleLines.at( 1 );

		int epochYear = std::stoi( line1.substr( 18, 2 ) );
		double epochDayFraction = std::stod( line1.substr( 20, 12 ) );
		std::cout << "Epoch year: " << epochYear << "\nDay fraction: " << epochDayFraction << std::endl;

		// Convert to seconds since J2000
		// TLE day number starts with a 1, so a day fraction of 1.0 would mean Jan 1st, 0:00. Hence, we have to subtract 1.5 days
		// in seconds to obtain number of seconds since Jan 1st, noon (as dictated by J2000).
		// TODO: fix calculation (does not account for leap days!)
		if( epochYear < 57 )
		{
			epochYear += 2000;
		}
		else
		{
			epochYear += 1900;
		}
		// TLE day numbering starts with 1, whereas Tudat assumes January 1st to be number 0
		boost::gregorian::date date = basic_astrodynamics::convertYearAndDaysInYearToDate( epochYear, std::floor( epochDayFraction ) - 1 );
		auto jdSinceJ2000 = basic_astrodynamics::calculateJulianDaySinceEpoch< double >( date, epochDayFraction );
		epoch_ = (epochYear - 2000) * physical_constants::JULIAN_YEAR + ( epochDayFraction - 1.5 ) * physical_constants::JULIAN_DAY;

		double bStar = std::stod( line1.substr( 53, 6 ) );
		double bStarExp = std::stod( line1.substr( 59, 2 ) );
		bStar_ = bStar * std::pow( 10, bStarExp - 5 );

		// Convert angles to radians
		inclination_ = unit_conversions::convertDegreesToRadians( std::stod( line2.substr( 8, 7 ) ) );
		rightAscension_ = unit_conversions::convertDegreesToRadians( std::stod( line2.substr( 17, 8 ) ) );

		std::string eccentricityString = "0." + line2.substr( 26, 7 );
		eccentricity_ = std::stod( eccentricityString );

		argOfPerigee_ = unit_conversions::convertDegreesToRadians( std::stod( line2.substr( 34, 8 ) ) );
		meanAnomaly_ = unit_conversions::convertDegreesToRadians( std::stod( line2.substr( 43, 8 ) ) );

		// Convert mean motion to radians per min (as opposed to rev/day as given in TLE)
		double meanMotionRevDay = std::stod( line2.substr( 52, 11 ) );
		meanMotion_ = meanMotionRevDay * 2.0 * mathematical_constants::PI / ( 60 * 24 );
	}

	Tle::Tle( const std::string& tleLine1, const std::string& tleLine2 )
	{
		throw std::runtime_error( "Error constructing TLE object: two string initialization not yet implemented." );
	}

    Tle::Tle( const double *spiceElements )
	{
		for( double &spiceElement : spiceElements_ )
		{
			spiceElement = *spiceElements;
			spiceElements++;
		}
	}

}
}
<commit_msg>Removed leftover debug statements + improved runtime error message<commit_after>/*    Copyright (c) 2010-2019, Delft University of Technology
 *    All rigths reserved
 *
 *    This file is part of the Tudat. Redistribution and use in source and
 *    binary forms, with or without modification, are permitted exclusively
 *    under the terms of the Modified BSD license. You should have received
 *    a copy of the license with this file. If not, please or visit:
 *    http://tudat.tudelft.nl/LICENSE.
 *
 */

#include "Tudat/Astrodynamics/Ephemerides/tleEphemeris.h"
#include "Tudat/Astrodynamics/BasicAstrodynamics/unitConversions.h"
#include "Tudat/External/SpiceInterface/spiceInterface.h"
#include "Tudat/External/SofaInterface/earthOrientation.h"
#include "Tudat/External/SofaInterface/sofaTimeConversions.h"
#include "boost/algorithm/string.hpp"

namespace tudat
{

namespace ephemerides
{

	TleEphemeris::TleEphemeris( const std::string &referenceFrameOrigin, const std::string &referenceFrameOrientation,
							   const std::shared_ptr< Tle > tle_ptr, const bool useSDP ) :
							   Ephemeris( referenceFrameOrigin, referenceFrameOrientation )
	{
		if( referenceFrameOrigin != "Earth" )
		{
			throw std::runtime_error( "Error: TleEphemeris only supports an Earth-centered reference frame." );
		}
		if( useSDP )
		{
			throw std::runtime_error( "TLE SDP propagator requested, which is not yet implemented." );
		}
		useSDP_ = useSDP;
		tle_ = tle_ptr;
		// Create table with ephemeris data
		// Create interpolator based on table

	}

	Eigen::Vector6d TleEphemeris::getCartesianState( double secondsSinceEpoch )
	{
		// Call Spice interface to retrieve the spacecraft's state from the TLE in the True Equator, Mean Equinox frame (see
		// Vallado: Fundamentals of Astrodynamics and Applications 4th ed. (2013)). This frame is idiosyncratic in nature and
		// therefore needs to be converted to an intermediate standard reference frame.
		const Eigen::Vector6d cartesianStateAtEpochTEME =
				spice_interface::getCartesianStateFromTleAtEpoch( secondsSinceEpoch, tle_ );

		Eigen::Vector3d positionTEME = cartesianStateAtEpochTEME.head( 3 );
		Eigen::Vector3d velocityTEME = cartesianStateAtEpochTEME.tail( 3 );

		// First, rotate to the True Of Date (TOD) frame.
		double equationOfEquinoxes = sofa_interface::calculateEquationOfEquinoxes( secondsSinceEpoch );

		// Rotate around pole (z-axis)
		Eigen::AngleAxisd rotationObject = Eigen::AngleAxisd( equationOfEquinoxes, Eigen::Vector3d::UnitZ( ) );
		Eigen::Vector3d positionTOD = rotationObject.toRotationMatrix( ) * positionTEME;
		Eigen::Vector3d velocityTOD = rotationObject.toRotationMatrix( ) * velocityTEME;

		// These angles (zeta, z, and theta) do not really have descriptive names. For a description of the precession geometry and these angles,
		// see pages 226-228 and figure 3-31 in Vallado (2013).
		double precessionAngleModToGcrfZeta;
		double precessionAngleModToGcrfZ;
		double precessionAngleModToGcrfTheta;
		sofa_interface::getPrecessionAngles(precessionAngleModToGcrfZeta, precessionAngleModToGcrfZ, precessionAngleModToGcrfTheta,
				secondsSinceEpoch );

		// Now that we have our state vector in the TOD frame, we need to obtain the combined precession + nutation matrix from Sofa
		// (according to the 1976/1980 model)
		Eigen::Matrix3d precessionNutationMatrix = sofa_interface::getPrecessionNutationMatrix( secondsSinceEpoch );
		// Multiply by inverted matrix to get to J2000
		Eigen::Vector3d  positionJ2000 = precessionNutationMatrix.transpose( ) * positionTOD;
		Eigen::Vector3d  velocityJ2000 = precessionNutationMatrix.transpose( ) * velocityTOD;

		if( referenceFrameOrientation_ == "J2000" )
		{
			Eigen::Vector6d stateJ2000;
			stateJ2000 << positionJ2000, velocityJ2000;
			return stateJ2000;
		}
		else if( referenceFrameOrientation_ == "ECLIPJ2000" )
		{
			Eigen::Quaterniond itrsToEclipticQuaternion = spice_interface::computeRotationQuaternionBetweenFrames(
					"J2000", "ECLIPJ2000", secondsSinceEpoch );
			Eigen::Vector3d positionEclipJ2000 = itrsToEclipticQuaternion * positionJ2000;
			Eigen::Vector3d velocityEclipJ2000 = itrsToEclipticQuaternion * velocityJ2000;
			Eigen::Vector6d stateEclipJ2000;
			stateEclipJ2000 << positionEclipJ2000, velocityEclipJ2000;
			return stateEclipJ2000;
		}
		else
		{
			throw std::runtime_error( "TLE state conversion to target frame " + referenceFrameOrientation_ + " is currently unsupported." );
		}

		return cartesianStateAtEpochTEME;
	}

	Tle::Tle( const std::string& lines )
	{
		// First of all, the TLE lines to be checked for validity: they shall not be empty, contain more than 69 characters
		// or have an invalid checksum.
		// Although unlikely, TLEs can become corrupted due to (un)intentional changes or data corruption during transmission.

		// Check if string is not empty
		if( lines.empty() )
		{
			throw std::runtime_error( "Error: TLE class was instantiated with string object, but string is empty." );
		}
		std::vector< std::string > tleLines;
		boost::algorithm::split( tleLines, lines, boost::is_any_of( "\n" ) );
		if( tleLines.size() != 2 )
		{
			throw std::runtime_error( "Error: TLE class was instantiated with string object, but string contains more than 2 lines." );
		}
		// Check line length
		for( std::string line : tleLines )
		{
			if( line.length( ) != 69 )
			{
				std::cout << line << std::endl;
				std::string s( 1, line.at( 0 ) );
				throw std::runtime_error("Error: TLE class was instantiated with string object, but line " + s +
				" contains an invalid number of characters (counted " + std::to_string( line.length( ) ) + " characters)" );
			}
			// Checksum
			int checksum = 0;
			for( unsigned int i = 0; i < line.length( ) - 1; i++ )
			{
				char c = line[ i ];
				if( c == '-' )
				{
					checksum++;
				}
				else if( std::isdigit( c ) )
				{
					checksum += static_cast< int >( c ) - 48;
				}
				// Else do nothing
			}
			checksum %= 10;
			if(checksum == static_cast< int >( line[ 68 ] ) - 48 )
			{
				// std::cout << "TLE checksum verified." << std::endl;
			}
			else
			{
				throw std::runtime_error( "TLE checksum invalid!" );
			}
		}

		// Parse TLE
		std::string line1 = tleLines.at( 0 );
		std::string line2 = tleLines.at( 1 );

		int epochYear = std::stoi( line1.substr( 18, 2 ) );
		double epochDayFraction = std::stod( line1.substr( 20, 12 ) );

		// Convert to seconds since J2000
		// TLE day number starts with a 1, so a day fraction of 1.0 would mean Jan 1st, 0:00. Hence, we have to subtract 1.5 days
		// in seconds to obtain number of seconds since Jan 1st, noon (as dictated by J2000).
		if( epochYear < 57 )
		{
			epochYear += 2000;
		}
		else
		{
			epochYear += 1900;
		}
		// TLE day numbering starts with 1, whereas Tudat assumes January 1st to be number 0
		boost::gregorian::date date = basic_astrodynamics::convertYearAndDaysInYearToDate( epochYear, std::floor( epochDayFraction ) - 1 );
		epoch_ = ( epochYear - 2000 ) * physical_constants::JULIAN_YEAR + ( epochDayFraction - 1.5 ) * physical_constants::JULIAN_DAY;

		double bStar = std::stod( line1.substr( 53, 6 ) );
		double bStarExp = std::stod( line1.substr( 59, 2 ) );
		bStar_ = bStar * std::pow( 10, bStarExp - 5 );

		// Convert angles to radians
		inclination_ = unit_conversions::convertDegreesToRadians( std::stod( line2.substr( 8, 7 ) ) );
		rightAscension_ = unit_conversions::convertDegreesToRadians( std::stod( line2.substr( 17, 8 ) ) );

		std::string eccentricityString = "0." + line2.substr( 26, 7 );
		eccentricity_ = std::stod( eccentricityString );

		argOfPerigee_ = unit_conversions::convertDegreesToRadians( std::stod( line2.substr( 34, 8 ) ) );
		meanAnomaly_ = unit_conversions::convertDegreesToRadians( std::stod( line2.substr( 43, 8 ) ) );

		// Convert mean motion to radians per min (as opposed to rev/day as given in TLE)
		double meanMotionRevDay = std::stod( line2.substr( 52, 11 ) );
		meanMotion_ = meanMotionRevDay * 2.0 * mathematical_constants::PI / ( 60 * 24 );
	}

	Tle::Tle( const std::string& tleLine1, const std::string& tleLine2 )
	{
		throw std::runtime_error( "Error constructing TLE object: two string initialization not yet implemented." );
	}

    Tle::Tle( const double *spiceElements )
	{
		for( double &spiceElement : spiceElements_ )
		{
			spiceElement = *spiceElements;
			spiceElements++;
		}
	}

}
}
<|endoftext|>


<commit_before>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

    Lasercake 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 3 of the License, or
    (at your option) any later version.

    Lasercake 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 Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "specific_object_types.hpp"

#include "data_structures/bbox_collision_detector_iteration.hpp"

namespace /* anonymous */ {

typedef polygon_rational_type rational;

struct beam_first_contact_finder {
  beam_first_contact_finder(world const& w, line_segment beam, object_or_tile_identifier ignore):w_(w),beam_(beam) {ignores_.insert(ignore);}
  typedef rational cost_type;
  typedef optional_rational result_type;
  static const uint64_t too_large = (1ULL << 32) - 1;
  bool bbox_is_too_large(world_collision_detector::bounding_box const& bbox) const {
    return (bbox.size_minus_one(X) >= too_large || bbox.size_minus_one(Y) >= too_large || bbox.size_minus_one(Z) >= too_large);
  }
  result_type min_cost(world_collision_detector::bounding_box const& bbox) const {
    // hack - avoid overflow - don't try to filter out too-large regions
    if(bbox_is_too_large(bbox)) return rational(0);
    return get_first_intersection(beam_, bbox);
  }
  result_type cost(object_or_tile_identifier id, world_collision_detector::bounding_box const& bbox) const {
    // hack - avoid overflow - effect: incredibly large objects can't be hit by lasers
    if(bbox_is_too_large(bbox)) return result_type();
    if(ignores_.find(id) != ignores_.end()) return result_type();
    // as an optimization, use tile bounding-boxes directly
    // (i.e. without converting to shape first)
    if (tile_location const* tlocp = id.get_tile_location()) {
      return get_first_intersection(beam_, fine_bounding_box_of_tile(tlocp->coords()));
    }
    else {
      return w_.get_detail_shape_of_object_or_tile(id).first_intersection(beam_);
    }
  }
private:
  world const& w_;
  line_segment beam_;
  unordered_set<object_or_tile_identifier> ignores_;
};

void fire_standard_laser(world& w, object_identifier my_id, vector3<fine_scalar> location, vector3<fine_scalar> facing) {
  facing = facing * tile_width * 2 / facing.magnitude_within_32_bits();
  const line_segment beam(location, location + facing * 50);
  beam_first_contact_finder finder(w, beam, my_id);
  if(auto hit = w.get_things_exposed_to_collision().find_least(finder)) {
    const object_or_tile_identifier hit_object = hit->object;
    const rational best_intercept_point = hit->cost;
    // TODO do I have to worry about overflow?
    w.add_laser_sfx(location, multiply_rational_into(facing * 50, best_intercept_point));
    if(tile_location const* locp = hit_object.get_tile_location()) {
      if (locp->stuff_at().contents() == ROCK) {
        w.replace_substance(*locp, ROCK, RUBBLE);
      }
    }
  }
  else {
    w.add_laser_sfx(location, facing * 50);
  }
}

const int robot_max_carrying_capacity = 4;

// Our robot "location" gets out of date relative to the personal_space_shape
// that the world defines us with (and changes due to velocity),
// so update it.
void update_location(vector3<fine_scalar>& location_, world& w, object_identifier id) {
  const bounding_box shape_bounds = w.get_object_personal_space_shapes().find(id)->second.bounds();
  const vector3<fine_scalar> middle = (shape_bounds.min() + shape_bounds.max()) / 2; //hmm, rounding.
  location_ = middle;
}

} /* end anonymous namespace */

shape robot::get_initial_personal_space_shape()const {
  return shape(bounding_box::min_and_max(
    location_ - vector3<fine_scalar>(tile_width * 3 / 10, tile_width * 3 / 10, tile_width * 3 / 10),
    location_ + vector3<fine_scalar>(tile_width * 3 / 10, tile_width * 3 / 10, tile_width * 3 / 10)
  ));
}

shape robot::get_initial_detail_shape()const {
  return get_initial_personal_space_shape();
}

void robot::update(world& w, object_identifier my_id) {
  update_location(location_, w, my_id);

  const bounding_box shape_bounds = w.get_object_personal_space_shapes().find(my_id)->second.bounds();
  const vector3<fine_scalar> middle = location_;
  const vector3<fine_scalar> bottom_middle(middle(X), middle(Y), shape_bounds.min(Z));
  const auto tiles_containing_bottom_middle = get_all_containing_tile_coordinates(bottom_middle);
  bool ground_below = false;
  for(vector3<tile_coordinate> tile_containing_bottom_middle : tiles_containing_bottom_middle) {
    if(w.make_tile_location(tile_containing_bottom_middle, COMPLETELY_IMAGINARY)
        .get_neighbor<zminus>(CONTENTS_ONLY)
        .stuff_at().contents()
      != AIR) {
      ground_below = true;
    }
  }
  if (ground_below) {
    // goal: decay towards levitating...
    fine_scalar target_height = (lower_bound_in_fine_units(get_max_containing_tile_coordinate(shape_bounds.min(Z), Z), Z) + tile_height * 5 / 4);
    fine_scalar deficiency = target_height - shape_bounds.min(Z);
    fine_scalar target_vel = gravity_acceleration_magnitude + deficiency * velocity_scale_factor / 8;
    if (velocity_.z < target_vel) {
      velocity_.z = std::min(velocity_.z + gravity_acceleration_magnitude * 5, target_vel);
    }
  }

  input_representation::input_news_t const& input_news = w.input_news();
  velocity_.x -= velocity_.x / 2;
  velocity_.y -= velocity_.y / 2;
  const fine_scalar xymag = i64sqrt(facing_.x*facing_.x + facing_.y*facing_.y);
  if (input_news.is_currently_pressed("x")) {
    velocity_.x = facing_.x * tile_width * velocity_scale_factor / 8 / xymag;
    velocity_.y = facing_.y * tile_width * velocity_scale_factor / 8 / xymag;
  }
  if (input_news.is_currently_pressed("right")) {
    fine_scalar new_facing_x = facing_.x + facing_.y / 20;
    fine_scalar new_facing_y = facing_.y - facing_.x / 20;
    facing_.x = new_facing_x; facing_.y = new_facing_y;
  }
  if (input_news.is_currently_pressed("left")) {
    fine_scalar new_facing_x = facing_.x - facing_.y / 20;
    fine_scalar new_facing_y = facing_.y + facing_.x / 20;
    facing_.x = new_facing_x; facing_.y = new_facing_y;
  }
  if (input_news.is_currently_pressed("up") != input_news.is_currently_pressed("down")) {
    const fine_scalar which_way = (input_news.is_currently_pressed("up") ? 1 : -1);
    const fine_scalar new_xymag = xymag - (which_way * facing_.z / 20);
    if (new_xymag > tile_width / 8) {
      facing_.z += which_way * xymag / 20;
      facing_.y = facing_.y * new_xymag / xymag;
      facing_.x = facing_.x * new_xymag / xymag;
    }
  }
  facing_ = facing_ * tile_width / facing_.magnitude_within_32_bits();

  vector3<fine_scalar> beam_delta = facing_ * 3 / 2;

  if (input_news.is_currently_pressed("c") || input_news.is_currently_pressed("v")) {
    beam_first_contact_finder finder(w, line_segment(location_, location_ + beam_delta), my_id);
    if(auto hit = w.get_things_exposed_to_collision().find_least(finder)) {
      // TODO do I have to worry about overflow?
      w.add_laser_sfx(location_, multiply_rational_into(beam_delta, hit->cost));
      if(tile_location const* locp = hit->object.get_tile_location()) {
        if (input_news.is_currently_pressed("c") && (carrying_ < robot_max_carrying_capacity) && (locp->stuff_at().contents() == ROCK || locp->stuff_at().contents() == RUBBLE)) {
          ++carrying_;
          w.replace_substance(*locp, locp->stuff_at().contents(), AIR);
        }
        /*if (carrying && locp->stuff_at().contents() == ROCK) {
          w.replace_substance(*locp, ROCK, RUBBLE);
        }*/
      }
    }
    else {
      w.add_laser_sfx(location_, beam_delta);
      if (input_news.is_currently_pressed("v") && (carrying_ > 0)) {
        --carrying_;
        const tile_location target_loc = w.make_tile_location(get_random_containing_tile_coordinates(location_ + beam_delta, w.get_rng()), FULL_REALIZATION);
        w.replace_substance(target_loc, AIR, RUBBLE);
      }
    }
  }
  if (input_news.is_currently_pressed("b")) {
    const vector3<fine_scalar> offset(-facing_.y / 4, facing_.x / 4, 0);
    fire_standard_laser(w, my_id, location_ + offset, facing_);
    fire_standard_laser(w, my_id, location_ - offset, facing_);
  }
}

shape laser_emitter::get_initial_personal_space_shape()const {
  return shape(bounding_box::min_and_max(
    location_ - vector3<fine_scalar>(tile_width * 4 / 10, tile_width * 4 / 10, tile_width * 4 / 10),
    location_ + vector3<fine_scalar>(tile_width * 4 / 10, tile_width * 4 / 10, tile_width * 4 / 10)
  ));
}

shape laser_emitter::get_initial_detail_shape()const {
  return get_initial_personal_space_shape();
}

void laser_emitter::update(world& w, object_identifier my_id) {
  update_location(location_, w, my_id);

  const boost::random::uniform_int_distribution<get_primitive_int_type<fine_scalar>::type> random_delta(-1023, 1023);
  for (int i = 0; i < 100; ++i) {
    do {
      facing_.x = random_delta(w.get_rng());
      facing_.y = random_delta(w.get_rng());
      facing_.z = random_delta(w.get_rng());
    } while (facing_.magnitude_within_32_bits_is_greater_than(1023) || facing_.magnitude_within_32_bits_is_less_than(512));

    fire_standard_laser(w, my_id, location_, facing_);
  }
}

<commit_msg>move robot's float_above_ground ability into a function<commit_after>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

    Lasercake 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 3 of the License, or
    (at your option) any later version.

    Lasercake 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 Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "specific_object_types.hpp"

#include "data_structures/bbox_collision_detector_iteration.hpp"

namespace /* anonymous */ {

typedef polygon_rational_type rational;

struct beam_first_contact_finder {
  beam_first_contact_finder(world const& w, line_segment beam, object_or_tile_identifier ignore):w_(w),beam_(beam) {ignores_.insert(ignore);}
  typedef rational cost_type;
  typedef optional_rational result_type;
  static const uint64_t too_large = (1ULL << 32) - 1;
  bool bbox_is_too_large(world_collision_detector::bounding_box const& bbox) const {
    return (bbox.size_minus_one(X) >= too_large || bbox.size_minus_one(Y) >= too_large || bbox.size_minus_one(Z) >= too_large);
  }
  result_type min_cost(world_collision_detector::bounding_box const& bbox) const {
    // hack - avoid overflow - don't try to filter out too-large regions
    if(bbox_is_too_large(bbox)) return rational(0);
    return get_first_intersection(beam_, bbox);
  }
  result_type cost(object_or_tile_identifier id, world_collision_detector::bounding_box const& bbox) const {
    // hack - avoid overflow - effect: incredibly large objects can't be hit by lasers
    if(bbox_is_too_large(bbox)) return result_type();
    if(ignores_.find(id) != ignores_.end()) return result_type();
    // as an optimization, use tile bounding-boxes directly
    // (i.e. without converting to shape first)
    if (tile_location const* tlocp = id.get_tile_location()) {
      return get_first_intersection(beam_, fine_bounding_box_of_tile(tlocp->coords()));
    }
    else {
      return w_.get_detail_shape_of_object_or_tile(id).first_intersection(beam_);
    }
  }
private:
  world const& w_;
  line_segment beam_;
  unordered_set<object_or_tile_identifier> ignores_;
};

void fire_standard_laser(world& w, object_identifier my_id, vector3<fine_scalar> location, vector3<fine_scalar> facing) {
  facing = facing * tile_width * 2 / facing.magnitude_within_32_bits();
  const line_segment beam(location, location + facing * 50);
  beam_first_contact_finder finder(w, beam, my_id);
  if(auto hit = w.get_things_exposed_to_collision().find_least(finder)) {
    const object_or_tile_identifier hit_object = hit->object;
    const rational best_intercept_point = hit->cost;
    // TODO do I have to worry about overflow?
    w.add_laser_sfx(location, multiply_rational_into(facing * 50, best_intercept_point));
    if(tile_location const* locp = hit_object.get_tile_location()) {
      if (locp->stuff_at().contents() == ROCK) {
        w.replace_substance(*locp, ROCK, RUBBLE);
      }
    }
  }
  else {
    w.add_laser_sfx(location, facing * 50);
  }
}

const int robot_max_carrying_capacity = 4;

// Our robot "location" gets out of date relative to the personal_space_shape
// that the world defines us with (and changes due to velocity),
// so update it.
void update_location(vector3<fine_scalar>& location_, world& w, object_identifier id) {
  const bounding_box shape_bounds = w.get_object_personal_space_shapes().find(id)->second.bounds();
  const vector3<fine_scalar> middle = (shape_bounds.min() + shape_bounds.max()) / 2; //hmm, rounding.
  location_ = middle;
}

void float_above_ground(vector3<fine_scalar>& velocity_, world& w, object_identifier id) {
  const bounding_box shape_bounds = w.get_object_personal_space_shapes().find(id)->second.bounds();
  const vector3<fine_scalar> middle = (shape_bounds.min() + shape_bounds.max()) / 2; //hmm, rounding.
  const vector3<fine_scalar> bottom_middle(middle(X), middle(Y), shape_bounds.min(Z));
  const auto tiles_containing_bottom_middle = get_all_containing_tile_coordinates(bottom_middle);
  bool ground_below = false;
  for(vector3<tile_coordinate> tile_containing_bottom_middle : tiles_containing_bottom_middle) {
    if(w.make_tile_location(tile_containing_bottom_middle, COMPLETELY_IMAGINARY)
        .get_neighbor<zminus>(CONTENTS_ONLY)
        .stuff_at().contents()
      != AIR) {
      ground_below = true;
    }
  }
  if (ground_below) {
    // goal: decay towards levitating...
    fine_scalar target_height = (lower_bound_in_fine_units(get_max_containing_tile_coordinate(shape_bounds.min(Z), Z), Z) + tile_height * 5 / 4);
    fine_scalar deficiency = target_height - shape_bounds.min(Z);
    fine_scalar target_vel = gravity_acceleration_magnitude + deficiency * velocity_scale_factor / 8;
    if (velocity_.z < target_vel) {
      velocity_.z = std::min(velocity_.z + gravity_acceleration_magnitude * 5, target_vel);
    }
  }
}

} /* end anonymous namespace */

shape robot::get_initial_personal_space_shape()const {
  return shape(bounding_box::min_and_max(
    location_ - vector3<fine_scalar>(tile_width * 3 / 10, tile_width * 3 / 10, tile_width * 3 / 10),
    location_ + vector3<fine_scalar>(tile_width * 3 / 10, tile_width * 3 / 10, tile_width * 3 / 10)
  ));
}

shape robot::get_initial_detail_shape()const {
  return get_initial_personal_space_shape();
}

void robot::update(world& w, object_identifier my_id) {
  update_location(location_, w, my_id);
  float_above_ground(velocity_, w, my_id);

  input_representation::input_news_t const& input_news = w.input_news();
  velocity_.x -= velocity_.x / 2;
  velocity_.y -= velocity_.y / 2;
  const fine_scalar xymag = i64sqrt(facing_.x*facing_.x + facing_.y*facing_.y);
  if (input_news.is_currently_pressed("x")) {
    velocity_.x = facing_.x * tile_width * velocity_scale_factor / 8 / xymag;
    velocity_.y = facing_.y * tile_width * velocity_scale_factor / 8 / xymag;
  }
  if (input_news.is_currently_pressed("right")) {
    fine_scalar new_facing_x = facing_.x + facing_.y / 20;
    fine_scalar new_facing_y = facing_.y - facing_.x / 20;
    facing_.x = new_facing_x; facing_.y = new_facing_y;
  }
  if (input_news.is_currently_pressed("left")) {
    fine_scalar new_facing_x = facing_.x - facing_.y / 20;
    fine_scalar new_facing_y = facing_.y + facing_.x / 20;
    facing_.x = new_facing_x; facing_.y = new_facing_y;
  }
  if (input_news.is_currently_pressed("up") != input_news.is_currently_pressed("down")) {
    const fine_scalar which_way = (input_news.is_currently_pressed("up") ? 1 : -1);
    const fine_scalar new_xymag = xymag - (which_way * facing_.z / 20);
    if (new_xymag > tile_width / 8) {
      facing_.z += which_way * xymag / 20;
      facing_.y = facing_.y * new_xymag / xymag;
      facing_.x = facing_.x * new_xymag / xymag;
    }
  }
  facing_ = facing_ * tile_width / facing_.magnitude_within_32_bits();

  vector3<fine_scalar> beam_delta = facing_ * 3 / 2;

  if (input_news.is_currently_pressed("c") || input_news.is_currently_pressed("v")) {
    beam_first_contact_finder finder(w, line_segment(location_, location_ + beam_delta), my_id);
    if(auto hit = w.get_things_exposed_to_collision().find_least(finder)) {
      // TODO do I have to worry about overflow?
      w.add_laser_sfx(location_, multiply_rational_into(beam_delta, hit->cost));
      if(tile_location const* locp = hit->object.get_tile_location()) {
        if (input_news.is_currently_pressed("c") && (carrying_ < robot_max_carrying_capacity) && (locp->stuff_at().contents() == ROCK || locp->stuff_at().contents() == RUBBLE)) {
          ++carrying_;
          w.replace_substance(*locp, locp->stuff_at().contents(), AIR);
        }
        /*if (carrying && locp->stuff_at().contents() == ROCK) {
          w.replace_substance(*locp, ROCK, RUBBLE);
        }*/
      }
    }
    else {
      w.add_laser_sfx(location_, beam_delta);
      if (input_news.is_currently_pressed("v") && (carrying_ > 0)) {
        --carrying_;
        const tile_location target_loc = w.make_tile_location(get_random_containing_tile_coordinates(location_ + beam_delta, w.get_rng()), FULL_REALIZATION);
        w.replace_substance(target_loc, AIR, RUBBLE);
      }
    }
  }
  if (input_news.is_currently_pressed("b")) {
    const vector3<fine_scalar> offset(-facing_.y / 4, facing_.x / 4, 0);
    fire_standard_laser(w, my_id, location_ + offset, facing_);
    fire_standard_laser(w, my_id, location_ - offset, facing_);
  }
}

shape laser_emitter::get_initial_personal_space_shape()const {
  return shape(bounding_box::min_and_max(
    location_ - vector3<fine_scalar>(tile_width * 4 / 10, tile_width * 4 / 10, tile_width * 4 / 10),
    location_ + vector3<fine_scalar>(tile_width * 4 / 10, tile_width * 4 / 10, tile_width * 4 / 10)
  ));
}

shape laser_emitter::get_initial_detail_shape()const {
  return get_initial_personal_space_shape();
}

void laser_emitter::update(world& w, object_identifier my_id) {
  update_location(location_, w, my_id);

  const boost::random::uniform_int_distribution<get_primitive_int_type<fine_scalar>::type> random_delta(-1023, 1023);
  for (int i = 0; i < 100; ++i) {
    do {
      facing_.x = random_delta(w.get_rng());
      facing_.y = random_delta(w.get_rng());
      facing_.z = random_delta(w.get_rng());
    } while (facing_.magnitude_within_32_bits_is_greater_than(1023) || facing_.magnitude_within_32_bits_is_less_than(512));

    fire_standard_laser(w, my_id, location_, facing_);
  }
}

<|endoftext|>


<commit_before>#include "testing/testing.hpp"

#include "drape/drape_tests/img.hpp"

#include <QtGui/QPainter>

#include "qt_tstfrm/test_main_loop.hpp"

#include "drape/glyph_manager.hpp"
#include "platform/platform.hpp"

#include "std/cstring.hpp"
#include "std/function.hpp"
#include "std/bind.hpp"

namespace
{
  class GlyphRenderer
  {
  public:
    GlyphRenderer()
    {
      dp::GlyphManager::Params args;
      args.m_uniBlocks = "unicode_blocks.txt";
      args.m_whitelist = "fonts_whitelist.txt";
      args.m_blacklist = "fonts_blacklist.txt";
      GetPlatform().GetFontNames(args.m_fonts);

      m_mng = new dp::GlyphManager(args);
    }

    ~GlyphRenderer()
    {
      delete m_mng;
    }

    void RenderGlyphs(QPaintDevice * device)
    {
      vector<dp::GlyphManager::Glyph> glyphs;
      glyphs.push_back(m_mng->GetGlyph(0x58));
      glyphs.push_back(m_mng->GetGlyph(0x79));
      glyphs.push_back(m_mng->GetGlyph(0x439));

      QPainter painter(device);
      painter.fillRect(QRectF(0.0, 0.0, device->width(), device->height()), Qt::white);

      QPoint pen(100, 100);
      for (dp::GlyphManager::Glyph & g : glyphs)
      {
        if (!g.m_image.m_data)
          continue;

        uint8_t * d = SharedBufferManager::GetRawPointer(g.m_image.m_data);

        QPoint currentPen = pen;
        currentPen.rx() += g.m_metrics.m_xOffset;
        currentPen.ry() -= g.m_metrics.m_yOffset;
        painter.drawImage(currentPen, CreateImage(g.m_image.m_width, g.m_image.m_height, d), QRect(0, 0, g.m_image.m_width, g.m_image.m_height));
        pen.rx() += g.m_metrics.m_xAdvance;
        pen.ry() += g.m_metrics.m_yAdvance;

        g.m_image.Destroy();
      }
    }

  private:
    dp::GlyphManager * m_mng;
  };
}

UNIT_TEST(GlyphLoadingTest)
{
  GlyphRenderer renderer;
  RunTestLoop("GlyphLoadingTest", bind(&GlyphRenderer::RenderGlyphs, &renderer, _1));
}
<commit_msg>[drape] make glyph mapping test more sociable<commit_after>#include "testing/testing.hpp"

#include "drape/drape_tests/img.hpp"

#include <QtGui/QPainter>

#include "qt_tstfrm/test_main_loop.hpp"

#include "drape/glyph_manager.hpp"
#include "platform/platform.hpp"

#include "std/cstring.hpp"
#include "std/function.hpp"
#include "std/bind.hpp"

namespace
{
  class GlyphRenderer
  {
  public:
    GlyphRenderer()
    {
      dp::GlyphManager::Params args;
      args.m_uniBlocks = "unicode_blocks.txt";
      args.m_whitelist = "fonts_whitelist.txt";
      args.m_blacklist = "fonts_blacklist.txt";
      GetPlatform().GetFontNames(args.m_fonts);

      m_mng = new dp::GlyphManager(args);
    }

    ~GlyphRenderer()
    {
      delete m_mng;
    }

    void RenderGlyphs(QPaintDevice * device)
    {
      vector<dp::GlyphManager::Glyph> glyphs;
      glyphs.push_back(m_mng->GetGlyph(0xC0));
      glyphs.push_back(m_mng->GetGlyph(0x79));
      glyphs.push_back(m_mng->GetGlyph(0x122));

      QPainter painter(device);
      painter.fillRect(QRectF(0.0, 0.0, device->width(), device->height()), Qt::white);

      QPoint pen(100, 100);
      for (dp::GlyphManager::Glyph & g : glyphs)
      {
        if (!g.m_image.m_data)
          continue;

        uint8_t * d = SharedBufferManager::GetRawPointer(g.m_image.m_data);

        QPoint currentPen = pen;
        currentPen.rx() += g.m_metrics.m_xOffset;
        currentPen.ry() -= g.m_metrics.m_yOffset;
        painter.drawImage(currentPen, CreateImage(g.m_image.m_width, g.m_image.m_height, d), QRect(0, 0, g.m_image.m_width, g.m_image.m_height));
        pen.rx() += g.m_metrics.m_xAdvance;
        pen.ry() += g.m_metrics.m_yAdvance;

        g.m_image.Destroy();
      }
    }

  private:
    dp::GlyphManager * m_mng;
  };
}

UNIT_TEST(GlyphLoadingTest)
{
  GlyphRenderer renderer;
  RunTestLoop("GlyphLoadingTest", bind(&GlyphRenderer::RenderGlyphs, &renderer, _1));
}
<|endoftext|>