<commit_before>#include "../../edgeElement.h"
#include "../../nodeElement.h"
#include "embeddedLinker.h"

#include <math.h>

#include <QDebug>
#include <QStyle>
#include <QGraphicsItem>
#include <QStyleOptionGraphicsItem>

#include "../../../view/editorViewScene.h"
#include "../../../mainwindow/mainWindow.h"
#include "../../private/reshapeEdgeCommand.h"

using namespace qReal;

EmbeddedLinker::EmbeddedLinker()
		: mEdge(NULL)
		, mMaster(NULL)
		, mColor(Qt::blue)
		, mPressed(false)
		, mTimeOfUpdate(0)
		, mTimer(new QTimer(this))
{
	mSize = SettingsManager::value("EmbeddedLinkerSize").toFloat();
	if (mSize > 10) {
		mSize *= 0.75;
	}
	mIndent = SettingsManager::value("EmbeddedLinkerIndent").toFloat();
	mIndent *= 0.8;
	if (mIndent > 17) {
		mIndent *= 0.7;
	}
	mRectangle = QRectF(-mSize, -mSize, mSize * 2, mSize * 2);
	mInnerRectangle = QRectF(-mSize / 2, -mSize / 2, mSize, mSize);
	setZValue(300);
	setFlag(ItemStacksBehindParent, false);

	setAcceptHoverEvents(true);

	connect(mTimer, SIGNAL(timeout()), this, SLOT(updateMasterEdge()));
}

EmbeddedLinker::~EmbeddedLinker()
{
}

NodeElement* EmbeddedLinker::getMaster()
{
	return mMaster;
}

void EmbeddedLinker::setMaster(NodeElement *element)
{
	mMaster = element;
	setParentItem(element);
}

void EmbeddedLinker::generateColor()
{
	int result = 0;
	mColor = QColor(result % 192 + 64, result % 128 + 128, result % 64 + 192).darker(0);
}
void EmbeddedLinker::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget*)
{
	Q_UNUSED(option);
	painter->save();

	QBrush brush;
	brush.setColor(mColor);
	brush.setStyle(Qt::SolidPattern);
	painter->setBrush(brush);
	painter->setOpacity(0.75);
	painter->setPen(mColor);

	mSize = SettingsManager::value("EmbeddedLinkerSize").toFloat();
	if (mSize > 10) {
		mSize *= 0.75;
	}
	mRectangle = QRectF(-mSize, -mSize, mSize * 2, mSize * 2);
	mInnerRectangle = QRectF(-mSize / 2, -mSize / 2, mSize, mSize);

	painter->drawEllipse(mRectangle);
	painter->setOpacity(0.9);
	painter->drawEllipse(mInnerRectangle);

	painter->restore();
}

void EmbeddedLinker::setDirected(const bool directed)
{
	this->mDirected = directed;
}

void EmbeddedLinker::initTitle()
{
	EditorManagerInterface const &editorManagerInterface
			= dynamic_cast<EditorViewScene*>(scene())->mainWindow()->editorManager();
	QString edgeTypeFriendly = editorManagerInterface.friendlyName(Id::loadFromString("qrm:/"+ mMaster->id().editor()
			+ "/" + mMaster->id().diagram() + "/" + mEdgeType.element()));

	float textWidth = edgeTypeFriendly.size()*10;
	float rectWidth = mMaster->boundingRect().right() - mMaster->boundingRect().left();
	float rectHeight = mMaster->boundingRect().bottom() - mMaster->boundingRect().top();

	int x = 0;
	int y = 0;
	if (scenePos().y() < mMaster->scenePos().y() + rectHeight/3)
		y = -boundingRect().height() - 10;
	else if (scenePos().y() > mMaster->scenePos().y() + 2*rectHeight/3)
		y = +boundingRect().height() - 10;

	if (scenePos().x() < mMaster->scenePos().x() + rectWidth/3)
		x = -boundingRect().width() - textWidth + 20;
	else if (scenePos().x() > mMaster->scenePos().x() + 2*rectWidth/3)
		x = +boundingRect().width() - 10;

	mTitle = new ElementTitle(static_cast<qreal>(x) / boundingRect().width()
			, static_cast<qreal>(y) / boundingRect().height(), edgeTypeFriendly, 0);
	mTitle->init(boundingRect());
	mTitle->setTextWidth(textWidth);
	mTitle->setParentItem(this);
}

void EmbeddedLinker::setEdgeType(const qReal::Id &edgeType)
{
	this->mEdgeType = edgeType;
	generateColor();
}

qReal::Id EmbeddedLinker::getEdgeType()
{
	return mEdgeType;
}

bool EmbeddedLinker::isDirected()
{
	return mDirected;
}

void EmbeddedLinker::takePosition(int index, int maxIndex)
{
	qreal const pi = 3.141592;
	QRectF const bounding = mMaster->boundingRect();

	qreal const top = bounding.topLeft().y();
	qreal const left = bounding.topLeft().x();
	qreal const right = bounding.bottomRight().x();
	qreal const bottom = bounding.bottomRight().y();
	qreal const height = bottom - top;
	qreal const width = right - left;

	qreal const angle = 2 * pi * index / maxIndex;

	int rW = width;
	int rH = height;
	if (rW < 150) {
		rW *= 1.5;
	} else {
		rW += 5;
	}
	if (rH < 150) {
		rH *= 1.5;
	} else {
		rH += 5;
	}

	// TODO: customize start angle
	qreal const px = left + width / 2 + rW * cos(angle) / 2;
	qreal const py = bottom - height / 2 + rH * sin(angle) / 2;

	// if linker covers master node:

	qreal min = py - top;
	if (min > bottom - py) {
		min = bottom - py;
	}
	if (min > px - left) {
		min = px - left;
	}
	if (min > right - px) {
		min = right - px;
	}

	qreal fx;
	qreal fy;
	mIndent = SettingsManager::value("EmbeddedLinkerIndent").toFloat();
	mIndent *= 0.8;
	if (mIndent > 17) {
		mIndent *= 0.7;
	}

	//obviously, top != left != right != bottom
	if ((bottom - py == min) || (py - top == min)) {
		fx = px;
		fy = bottom - py == min ? bottom + mIndent : top - mIndent;
	} else {
		fx = right - px == min ? right + mIndent : left - mIndent;
		fy = py;
	}

	setPos(fx, fy);
}

QRectF EmbeddedLinker::boundingRect() const {
	return mRectangle;
}

void EmbeddedLinker::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
	Q_UNUSED(event)
	mPressed = true;
	if (event->button() == Qt::LeftButton) {
		mEdge = NULL;
	}
}

void EmbeddedLinker::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
	mTimer->start(400);

	if (mPressed) {
		mPressed = false;
		EditorViewScene *scene = dynamic_cast<EditorViewScene*>(mMaster->scene());

		if (!scene) {
			return;
		}
		QString const type = "qrm:/" + mMaster->id().editor() + "/" +
							 mMaster->id().diagram() + "/" + mEdgeType.element();
		if (scene->mainWindow()->editorManager().hasElement(Id::loadFromString(type))) {
			mMaster->setConnectingState(true);
			// FIXME: I am raw. return strange pos() and inside me a small trash
			Id edgeId = scene->createElement(type, event->scenePos(), true, &mCreateEdgeCommand);
			mEdge = dynamic_cast<EdgeElement*>(scene->getElem(edgeId));
		}

		if (mEdge) {
			mMaster->setZValue(1);
			mEdge->setSrc(mMaster);
			mEdge->setDst(NULL);
			mEdge->highlight();
			mEdge->tuneForLinker();
			mEdge->placeEndTo(mEdge->mapFromScene(mapToScene(event->pos())));
			mMaster->arrangeLinks();
			mMaster->adjustLinks();
		}
	}

	if (mEdge) {
		if (mTimeOfUpdate == 14) {
			mTimeOfUpdate = 0;
			mEdge->adjustNeighborLinks();
			mEdge->arrangeSrcAndDst();
		} else {
			mTimeOfUpdate++;
		}
		mEdge->placeEndTo(mEdge->mapFromScene(mapToScene(event->pos())));
	}
}

void EmbeddedLinker::updateMasterEdge()
{
	mTimer->stop();
	mTimeOfUpdate = 0;

	if (mEdge) {
		mEdge->arrangeSrcAndDst();
		mEdge->adjustNeighborLinks();
	}
}

void EmbeddedLinker::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
	hide();
	mMaster->selectionState(false);
	EditorViewScene* scene = dynamic_cast<EditorViewScene*>(mMaster->scene());

	if (!mPressed && scene && mEdge) {
		mEdge->hide();
		QPointF const &eScenePos = event->scenePos();
		NodeElement *under = dynamic_cast<NodeElement*>(scene->itemAt(eScenePos, QTransform()));
		mEdge->show();
		int result = 0;

		commands::CreateElementCommand *createElementFromMenuCommand = NULL;
		if (!under) {
			result = scene->launchEdgeMenu(mEdge, mMaster, eScenePos, false, &createElementFromMenuCommand);
		} else {
			bool canBeConnected = false;
			foreach(PossibleEdge const &pEdge, mEdge->src()->getPossibleEdges()) {
				if (pEdge.first.second.element() == under->id().element()) {
					canBeConnected = true;
				}
			}

			if (under->isContainer()) {
				result = scene->launchEdgeMenu(mEdge, mMaster, eScenePos,
							canBeConnected, &createElementFromMenuCommand);
			} else {
				if (!canBeConnected) {
					result = -1;
				}
			}
		}
		NodeElement *target = dynamic_cast<NodeElement*>(scene->getLastCreated());

		if (result == -1) {
			mEdge = NULL;
		} else if ((result == 1) && target) {
			mEdge->setDst(target);
			target->storeGeometry();
		}
		if (result != -1) {
			mEdge->connectToPort();

			updateMasterEdge();
			// This will restore edge state after undo/redo
			commands::ReshapeEdgeCommand *reshapeEdge = new commands::ReshapeEdgeCommand(mEdge);
			reshapeEdge->startTracking();
			reshapeEdge->stopTracking();
			reshapeEdge->setUndoEnabled(false);
			if (createElementFromMenuCommand) {
				createElementFromMenuCommand->addPostAction(reshapeEdge);
				mCreateEdgeCommand->addPostAction(createElementFromMenuCommand);
			} else {
				mCreateEdgeCommand->addPostAction(reshapeEdge);
			}
		}
	}
	mPressed = false;
	mEdge = NULL;
}

<commit_msg>Improved check for connectivity.<commit_after>#include "../../edgeElement.h"
#include "../../nodeElement.h"
#include "embeddedLinker.h"

#include <math.h>

#include <QDebug>
#include <QStyle>
#include <QGraphicsItem>
#include <QStyleOptionGraphicsItem>

#include "../../../view/editorViewScene.h"
#include "../../../mainwindow/mainWindow.h"
#include "../../private/reshapeEdgeCommand.h"

using namespace qReal;

EmbeddedLinker::EmbeddedLinker()
		: mEdge(NULL)
		, mMaster(NULL)
		, mColor(Qt::blue)
		, mPressed(false)
		, mTimeOfUpdate(0)
		, mTimer(new QTimer(this))
{
	mSize = SettingsManager::value("EmbeddedLinkerSize").toFloat();
	if (mSize > 10) {
		mSize *= 0.75;
	}
	mIndent = SettingsManager::value("EmbeddedLinkerIndent").toFloat();
	mIndent *= 0.8;
	if (mIndent > 17) {
		mIndent *= 0.7;
	}
	mRectangle = QRectF(-mSize, -mSize, mSize * 2, mSize * 2);
	mInnerRectangle = QRectF(-mSize / 2, -mSize / 2, mSize, mSize);
	setZValue(300);
	setFlag(ItemStacksBehindParent, false);

	setAcceptHoverEvents(true);

	connect(mTimer, SIGNAL(timeout()), this, SLOT(updateMasterEdge()));
}

EmbeddedLinker::~EmbeddedLinker()
{
}

NodeElement* EmbeddedLinker::getMaster()
{
	return mMaster;
}

void EmbeddedLinker::setMaster(NodeElement *element)
{
	mMaster = element;
	setParentItem(element);
}

void EmbeddedLinker::generateColor()
{
	int result = 0;
	mColor = QColor(result % 192 + 64, result % 128 + 128, result % 64 + 192).darker(0);
}
void EmbeddedLinker::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget*)
{
	Q_UNUSED(option);
	painter->save();

	QBrush brush;
	brush.setColor(mColor);
	brush.setStyle(Qt::SolidPattern);
	painter->setBrush(brush);
	painter->setOpacity(0.75);
	painter->setPen(mColor);

	mSize = SettingsManager::value("EmbeddedLinkerSize").toFloat();
	if (mSize > 10) {
		mSize *= 0.75;
	}
	mRectangle = QRectF(-mSize, -mSize, mSize * 2, mSize * 2);
	mInnerRectangle = QRectF(-mSize / 2, -mSize / 2, mSize, mSize);

	painter->drawEllipse(mRectangle);
	painter->setOpacity(0.9);
	painter->drawEllipse(mInnerRectangle);

	painter->restore();
}

void EmbeddedLinker::setDirected(const bool directed)
{
	this->mDirected = directed;
}

void EmbeddedLinker::initTitle()
{
	EditorManagerInterface const &editorManagerInterface
			= dynamic_cast<EditorViewScene*>(scene())->mainWindow()->editorManager();
	QString edgeTypeFriendly = editorManagerInterface.friendlyName(Id::loadFromString("qrm:/"+ mMaster->id().editor()
			+ "/" + mMaster->id().diagram() + "/" + mEdgeType.element()));

	float textWidth = edgeTypeFriendly.size()*10;
	float rectWidth = mMaster->boundingRect().right() - mMaster->boundingRect().left();
	float rectHeight = mMaster->boundingRect().bottom() - mMaster->boundingRect().top();

	int x = 0;
	int y = 0;
	if (scenePos().y() < mMaster->scenePos().y() + rectHeight/3)
		y = -boundingRect().height() - 10;
	else if (scenePos().y() > mMaster->scenePos().y() + 2*rectHeight/3)
		y = +boundingRect().height() - 10;

	if (scenePos().x() < mMaster->scenePos().x() + rectWidth/3)
		x = -boundingRect().width() - textWidth + 20;
	else if (scenePos().x() > mMaster->scenePos().x() + 2*rectWidth/3)
		x = +boundingRect().width() - 10;

	mTitle = new ElementTitle(static_cast<qreal>(x) / boundingRect().width()
			, static_cast<qreal>(y) / boundingRect().height(), edgeTypeFriendly, 0);
	mTitle->init(boundingRect());
	mTitle->setTextWidth(textWidth);
	mTitle->setParentItem(this);
}

void EmbeddedLinker::setEdgeType(const qReal::Id &edgeType)
{
	this->mEdgeType = edgeType;
	generateColor();
}

qReal::Id EmbeddedLinker::getEdgeType()
{
	return mEdgeType;
}

bool EmbeddedLinker::isDirected()
{
	return mDirected;
}

void EmbeddedLinker::takePosition(int index, int maxIndex)
{
	qreal const pi = 3.141592;
	QRectF const bounding = mMaster->boundingRect();

	qreal const top = bounding.topLeft().y();
	qreal const left = bounding.topLeft().x();
	qreal const right = bounding.bottomRight().x();
	qreal const bottom = bounding.bottomRight().y();
	qreal const height = bottom - top;
	qreal const width = right - left;

	qreal const angle = 2 * pi * index / maxIndex;

	int rW = width;
	int rH = height;
	if (rW < 150) {
		rW *= 1.5;
	} else {
		rW += 5;
	}
	if (rH < 150) {
		rH *= 1.5;
	} else {
		rH += 5;
	}

	// TODO: customize start angle
	qreal const px = left + width / 2 + rW * cos(angle) / 2;
	qreal const py = bottom - height / 2 + rH * sin(angle) / 2;

	// if linker covers master node:

	qreal min = py - top;
	if (min > bottom - py) {
		min = bottom - py;
	}
	if (min > px - left) {
		min = px - left;
	}
	if (min > right - px) {
		min = right - px;
	}

	qreal fx;
	qreal fy;
	mIndent = SettingsManager::value("EmbeddedLinkerIndent").toFloat();
	mIndent *= 0.8;
	if (mIndent > 17) {
		mIndent *= 0.7;
	}

	//obviously, top != left != right != bottom
	if ((bottom - py == min) || (py - top == min)) {
		fx = px;
		fy = bottom - py == min ? bottom + mIndent : top - mIndent;
	} else {
		fx = right - px == min ? right + mIndent : left - mIndent;
		fy = py;
	}

	setPos(fx, fy);
}

QRectF EmbeddedLinker::boundingRect() const {
	return mRectangle;
}

void EmbeddedLinker::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
	Q_UNUSED(event)
	mPressed = true;
	if (event->button() == Qt::LeftButton) {
		mEdge = NULL;
	}
}

void EmbeddedLinker::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
	mTimer->start(400);

	if (mPressed) {
		mPressed = false;
		EditorViewScene *scene = dynamic_cast<EditorViewScene*>(mMaster->scene());

		if (!scene) {
			return;
		}
		QString const type = "qrm:/" + mMaster->id().editor() + "/" +
							 mMaster->id().diagram() + "/" + mEdgeType.element();
		if (scene->mainWindow()->editorManager().hasElement(Id::loadFromString(type))) {
			mMaster->setConnectingState(true);
			// FIXME: I am raw. return strange pos() and inside me a small trash
			Id edgeId = scene->createElement(type, event->scenePos(), true, &mCreateEdgeCommand);
			mEdge = dynamic_cast<EdgeElement*>(scene->getElem(edgeId));
		}

		if (mEdge) {
			mMaster->setZValue(1);
			mEdge->setSrc(mMaster);
			mEdge->setDst(NULL);
			mEdge->highlight();
			mEdge->tuneForLinker();
			mEdge->placeEndTo(mEdge->mapFromScene(mapToScene(event->pos())));
			mMaster->arrangeLinks();
			mMaster->adjustLinks();
		}
	}

	if (mEdge) {
		if (mTimeOfUpdate == 14) {
			mTimeOfUpdate = 0;
			mEdge->adjustNeighborLinks();
			mEdge->arrangeSrcAndDst();
		} else {
			mTimeOfUpdate++;
		}
		mEdge->placeEndTo(mEdge->mapFromScene(mapToScene(event->pos())));
	}
}

void EmbeddedLinker::updateMasterEdge()
{
	mTimer->stop();
	mTimeOfUpdate = 0;

	if (mEdge) {
		mEdge->arrangeSrcAndDst();
		mEdge->adjustNeighborLinks();
	}
}

void EmbeddedLinker::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
	hide();
	mMaster->selectionState(false);
	EditorViewScene* scene = dynamic_cast<EditorViewScene*>(mMaster->scene());

	if (!mPressed && scene && mEdge) {
		mEdge->hide();
		QPointF const &eScenePos = event->scenePos();
		NodeElement *under = dynamic_cast<NodeElement*>(scene->itemAt(eScenePos, QTransform()));
		mEdge->show();
		int result = 0;

		commands::CreateElementCommand *createElementFromMenuCommand = NULL;
		if (!under) {
			result = scene->launchEdgeMenu(mEdge, mMaster, eScenePos, false, &createElementFromMenuCommand);
		} else {
			bool canBeConnected = false;
			foreach(PossibleEdge const &pEdge, mEdge->src()->getPossibleEdges()) {
				if (pEdge.first.second.element() == under->id().element()) {
					canBeConnected = true;
				} else {
					// pEdge.second.first is true, if edge can connect items in only one direction.
					if (!pEdge.second.first) {
						canBeConnected = (pEdge.first.first.element() == under->id().element());
					}
				}
			}

			if (under->isContainer()) {
				result = scene->launchEdgeMenu(mEdge, mMaster, eScenePos,
							canBeConnected, &createElementFromMenuCommand);
			} else {
				if (!canBeConnected) {
					result = -1;
				}
			}
		}
		NodeElement *target = dynamic_cast<NodeElement*>(scene->getLastCreated());

		if (result == -1) {
			mEdge = NULL;
		} else if ((result == 1) && target) {
			mEdge->setDst(target);
			target->storeGeometry();
		}
		if (result != -1) {
			mEdge->connectToPort();

			updateMasterEdge();
			// This will restore edge state after undo/redo
			commands::ReshapeEdgeCommand *reshapeEdge = new commands::ReshapeEdgeCommand(mEdge);
			reshapeEdge->startTracking();
			reshapeEdge->stopTracking();
			reshapeEdge->setUndoEnabled(false);
			if (createElementFromMenuCommand) {
				createElementFromMenuCommand->addPostAction(reshapeEdge);
				mCreateEdgeCommand->addPostAction(createElementFromMenuCommand);
			} else {
				mCreateEdgeCommand->addPostAction(reshapeEdge);
			}
		}
	}
	mPressed = false;
	mEdge = NULL;
}

<|endoftext|>


<commit_before>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "host/client_session_desktop.h"

#include "base/logging.h"
#include "base/power_controller.h"
#include "base/codec/cursor_encoder.h"
#include "base/codec/scale_reducer.h"
#include "base/codec/video_encoder_vpx.h"
#include "base/codec/video_encoder_zstd.h"
#include "base/codec/video_util.h"
#include "base/desktop/frame.h"
#include "common/desktop_session_constants.h"
#include "host/desktop_session_proxy.h"
#include "host/system_info.h"
#include "host/win/updater_launcher.h"
#include "proto/desktop_internal.pb.h"

namespace host {

ClientSessionDesktop::ClientSessionDesktop(
    proto::SessionType session_type, std::unique_ptr<base::NetworkChannel> channel)
    : ClientSession(session_type, std::move(channel))
{
    // Nothing
}

ClientSessionDesktop::~ClientSessionDesktop() = default;

void ClientSessionDesktop::setDesktopSessionProxy(
    std::shared_ptr<DesktopSessionProxy> desktop_session_proxy)
{
    desktop_session_proxy_ = std::move(desktop_session_proxy);
    DCHECK(desktop_session_proxy_);
}

void ClientSessionDesktop::onMessageReceived(const base::ByteArray& buffer)
{
    incoming_message_.Clear();

    if (!base::parse(buffer, &incoming_message_))
    {
        LOG(LS_ERROR) << "Invalid message from client";
        return;
    }

    if (incoming_message_.has_mouse_event())
    {
        if (sessionType() != proto::SESSION_TYPE_DESKTOP_MANAGE)
            return;

        if (!scale_reducer_)
            return;

        const proto::MouseEvent& mouse_event = incoming_message_.mouse_event();

        int pos_x = static_cast<int>(
            static_cast<double>(mouse_event.x() * 100) / scale_reducer_->scaleFactorX());
        int pos_y = static_cast<int>(
            static_cast<double>(mouse_event.y() * 100) / scale_reducer_->scaleFactorY());

        proto::MouseEvent out_mouse_event;
        out_mouse_event.set_mask(mouse_event.mask());
        out_mouse_event.set_x(pos_x);
        out_mouse_event.set_y(pos_y);

        desktop_session_proxy_->injectMouseEvent(out_mouse_event);
    }
    else if (incoming_message_.has_key_event())
    {
        if (sessionType() == proto::SESSION_TYPE_DESKTOP_MANAGE)
            desktop_session_proxy_->injectKeyEvent(incoming_message_.key_event());
    }
    else if (incoming_message_.has_clipboard_event())
    {
        if (sessionType() == proto::SESSION_TYPE_DESKTOP_MANAGE)
            desktop_session_proxy_->injectClipboardEvent(incoming_message_.clipboard_event());
    }
    else if (incoming_message_.has_extension())
    {
        readExtension(incoming_message_.extension());
    }
    else if (incoming_message_.has_config())
    {
        readConfig(incoming_message_.config());
    }
    else
    {
        LOG(LS_WARNING) << "Unhandled message from client";
        return;
    }
}

void ClientSessionDesktop::onMessageWritten(size_t /* pending */)
{
    // Nothing
}

void ClientSessionDesktop::onStarted()
{
    const char* extensions;

    // Supported extensions are different for managing and viewing the desktop.
    if (sessionType() == proto::SESSION_TYPE_DESKTOP_MANAGE)
    {
        extensions = common::kSupportedExtensionsForManage;
    }
    else
    {
        DCHECK_EQ(sessionType(), proto::SESSION_TYPE_DESKTOP_VIEW);
        extensions = common::kSupportedExtensionsForView;
    }

    // Create a configuration request.
    proto::DesktopConfigRequest* request = outgoing_message_.mutable_config_request();

    // Add supported extensions and video encodings.
    request->set_extensions(extensions);
    request->set_video_encodings(common::kSupportedVideoEncodings);

    LOG(LS_INFO) << "Sending config request";
    LOG(LS_INFO) << "Supported extensions: " << request->extensions();
    LOG(LS_INFO) << "Supported video encodings: " << request->video_encodings();

    // Send the request.
    sendMessage(base::serialize(outgoing_message_));
}

void ClientSessionDesktop::encode(const base::Frame* frame, const base::MouseCursor* cursor)
{
    outgoing_message_.Clear();

    if (frame && video_encoder_ && scale_reducer_)
    {
        const base::Size& source_size = frame->size();

        if (preferred_size_.width() > source_size.width() ||
            preferred_size_.height() > source_size.height())
        {
            LOG(LS_INFO) << "Preferred size is larger than the original. "
                            "Original frame size will be used";
            preferred_size_ = source_size;
        }

        if (preferred_size_.isEmpty())
        {
            LOG(LS_INFO) << "Preferred size has not been set. Original frame size will be used";
            preferred_size_ = source_size;
        }

        const base::Frame* scaled_frame = scale_reducer_->scaleFrame(frame, preferred_size_);
        if (!scaled_frame)
        {
            LOG(LS_ERROR) << "No scaled frame";
            return;
        }

        proto::VideoPacket* packet = outgoing_message_.mutable_video_packet();

        // Encode the frame into a video packet.
        video_encoder_->encode(scaled_frame, packet);

        if (packet->has_format())
        {
            proto::Size* screen_size = packet->mutable_format()->mutable_screen_size();
            screen_size->set_width(frame->size().width());
            screen_size->set_height(frame->size().height());

            LOG(LS_INFO) << "Video packet has format";
            LOG(LS_INFO) << "Screen size: " << screen_size->width() << "x" << screen_size->height();
            LOG(LS_INFO) << "Video size: " << packet->format().video_rect().width() << "x"
                         << packet->format().video_rect().height();
        }
    }

    if (cursor && cursor_encoder_)
    {
        if (!cursor_encoder_->encode(*cursor, outgoing_message_.mutable_cursor_shape()))
            outgoing_message_.clear_cursor_shape();
    }

    if (outgoing_message_.has_video_packet() || outgoing_message_.has_cursor_shape())
        sendMessage(base::serialize(outgoing_message_));
}

void ClientSessionDesktop::setScreenList(const proto::ScreenList& list)
{
    outgoing_message_.Clear();

    proto::DesktopExtension* extension = outgoing_message_.mutable_extension();
    extension->set_name(common::kSelectScreenExtension);
    extension->set_data(list.SerializeAsString());

    sendMessage(base::serialize(outgoing_message_));
}

void ClientSessionDesktop::injectClipboardEvent(const proto::ClipboardEvent& event)
{
    if (sessionType() == proto::SESSION_TYPE_DESKTOP_MANAGE)
    {
        outgoing_message_.Clear();

        outgoing_message_.mutable_clipboard_event()->CopyFrom(event);
        sendMessage(base::serialize(outgoing_message_));
    }
}

void ClientSessionDesktop::readExtension(const proto::DesktopExtension& extension)
{
    if (extension.name() == common::kSelectScreenExtension)
    {
        proto::Screen screen;

        if (!screen.ParseFromString(extension.data()))
        {
            LOG(LS_ERROR) << "Unable to parse select screen extension data";
            return;
        }

        desktop_session_proxy_->selectScreen(screen);
        preferred_size_ = base::Size();
    }
    else if (extension.name() == common::kPreferredSizeExtension)
    {
        proto::PreferredSize preferred_size;

        if (!preferred_size.ParseFromString(extension.data()))
        {
            LOG(LS_ERROR) << "Unable to parse preferred size extension data";
            return;
        }

        static const int kMaxScreenSize = std::numeric_limits<int16_t>::max();

        if (preferred_size.width() < 0 || preferred_size.width() > kMaxScreenSize ||
            preferred_size.height() < 0 || preferred_size.height() > kMaxScreenSize)
        {
            LOG(LS_ERROR) << "Invalid preferred size: "
                          << preferred_size.width() << "x" << preferred_size.height();
            return;
        }

        LOG(LS_INFO) << "Preferred size changed: "
                     << preferred_size.width() << "x" << preferred_size.height();

        preferred_size_.set(preferred_size.width(), preferred_size.height());
        desktop_session_proxy_->captureScreen();
    }
    else if (extension.name() == common::kPowerControlExtension)
    {
        if (sessionType() != proto::SESSION_TYPE_DESKTOP_MANAGE)
        {
            LOG(LS_WARNING) << "Power management is only accessible from a desktop manage session";
            return;
        }

        proto::PowerControl power_control;

        if (!power_control.ParseFromString(extension.data()))
        {
            LOG(LS_ERROR) << "Unable to parse power control extension data";
            return;
        }

        switch (power_control.action())
        {
            case proto::PowerControl::ACTION_SHUTDOWN:
                base::PowerController::shutdown();
                break;

            case proto::PowerControl::ACTION_REBOOT:
                base::PowerController::reboot();
                break;

            case proto::PowerControl::ACTION_LOGOFF:
                desktop_session_proxy_->control(proto::internal::Control::LOGOFF);
                break;

            case proto::PowerControl::ACTION_LOCK:
                desktop_session_proxy_->control(proto::internal::Control::LOCK);
                break;

            default:
                LOG(LS_WARNING) << "Unhandled power control action: " << power_control.action();
                break;
        }
    }
    else if (extension.name() == common::kRemoteUpdateExtension)
    {
        if (sessionType() == proto::SESSION_TYPE_DESKTOP_MANAGE)
        {
            launchUpdater(sessionId());
        }
        else
        {
            LOG(LS_WARNING) << "Update can only be launched from a desktop manage session";
        }
    }
    else if (extension.name() == common::kSystemInfoExtension)
    {
        proto::SystemInfo system_info;
        createSystemInfo(&system_info);

        outgoing_message_.Clear();

        proto::DesktopExtension* desktop_extension = outgoing_message_.mutable_extension();
        desktop_extension->set_name(common::kSystemInfoExtension);
        desktop_extension->set_data(system_info.SerializeAsString());

        sendMessage(base::serialize(outgoing_message_));
    }
    else
    {
        LOG(LS_WARNING) << "Unknown extension: " << extension.name();
    }
}

void ClientSessionDesktop::readConfig(const proto::DesktopConfig& config)
{
    switch (config.video_encoding())
    {
        case proto::VIDEO_ENCODING_VP8:
            video_encoder_ = base::VideoEncoderVPX::createVP8();
            break;

        case proto::VIDEO_ENCODING_VP9:
            video_encoder_ = base::VideoEncoderVPX::createVP9();
            break;

        case proto::VIDEO_ENCODING_ZSTD:
            video_encoder_ = base::VideoEncoderZstd::create(
                base::parsePixelFormat(config.pixel_format()), config.compress_ratio());
            break;

        default:
        {
            // No supported video encoding.
            LOG(LS_WARNING) << "Unsupported video encoding: " << config.video_encoding();
        }
        break;
    }

    if (!video_encoder_)
    {
        LOG(LS_ERROR) << "Video encoder not initialized!";
        return;
    }

    cursor_encoder_.reset();
    if (config.flags() & proto::ENABLE_CURSOR_SHAPE)
        cursor_encoder_ = std::make_unique<base::CursorEncoder>();

    scale_reducer_ = std::make_unique<base::ScaleReducer>();

    desktop_session_config_.disable_font_smoothing =
        (config.flags() & proto::DISABLE_FONT_SMOOTHING);
    desktop_session_config_.disable_effects =
        (config.flags() & proto::DISABLE_DESKTOP_EFFECTS);
    desktop_session_config_.disable_wallpaper =
        (config.flags() & proto::DISABLE_DESKTOP_WALLPAPER);
    desktop_session_config_.block_input =
        (config.flags() & proto::BLOCK_REMOTE_INPUT);
    desktop_session_config_.lock_at_disconnect =
        (config.flags() & proto::LOCK_AT_DISCONNECT);

    LOG(LS_INFO) << "NEW CLIENT CONFIGURATION";
    LOG(LS_INFO) << "Video encoding: " << config.video_encoding();
    LOG(LS_INFO) << "Enable cursor shape: " << (cursor_encoder_ != nullptr);
    LOG(LS_INFO) << "Disable font smoothing: " << desktop_session_config_.disable_font_smoothing;
    LOG(LS_INFO) << "Disable desktop effects: " << desktop_session_config_.disable_effects;
    LOG(LS_INFO) << "Disable desktop wallpaper: " << desktop_session_config_.disable_wallpaper;
    LOG(LS_INFO) << "Block input: " << desktop_session_config_.block_input;
    LOG(LS_INFO) << "Lock at disconnect: " << desktop_session_config_.lock_at_disconnect;

    delegate_->onClientSessionConfigured();
}

} // namespace host
<commit_msg>Don't change the current preferred size.<commit_after>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "host/client_session_desktop.h"

#include "base/logging.h"
#include "base/power_controller.h"
#include "base/codec/cursor_encoder.h"
#include "base/codec/scale_reducer.h"
#include "base/codec/video_encoder_vpx.h"
#include "base/codec/video_encoder_zstd.h"
#include "base/codec/video_util.h"
#include "base/desktop/frame.h"
#include "common/desktop_session_constants.h"
#include "host/desktop_session_proxy.h"
#include "host/system_info.h"
#include "host/win/updater_launcher.h"
#include "proto/desktop_internal.pb.h"

namespace host {

ClientSessionDesktop::ClientSessionDesktop(
    proto::SessionType session_type, std::unique_ptr<base::NetworkChannel> channel)
    : ClientSession(session_type, std::move(channel))
{
    // Nothing
}

ClientSessionDesktop::~ClientSessionDesktop() = default;

void ClientSessionDesktop::setDesktopSessionProxy(
    std::shared_ptr<DesktopSessionProxy> desktop_session_proxy)
{
    desktop_session_proxy_ = std::move(desktop_session_proxy);
    DCHECK(desktop_session_proxy_);
}

void ClientSessionDesktop::onMessageReceived(const base::ByteArray& buffer)
{
    incoming_message_.Clear();

    if (!base::parse(buffer, &incoming_message_))
    {
        LOG(LS_ERROR) << "Invalid message from client";
        return;
    }

    if (incoming_message_.has_mouse_event())
    {
        if (sessionType() != proto::SESSION_TYPE_DESKTOP_MANAGE)
            return;

        if (!scale_reducer_)
            return;

        const proto::MouseEvent& mouse_event = incoming_message_.mouse_event();

        int pos_x = static_cast<int>(
            static_cast<double>(mouse_event.x() * 100) / scale_reducer_->scaleFactorX());
        int pos_y = static_cast<int>(
            static_cast<double>(mouse_event.y() * 100) / scale_reducer_->scaleFactorY());

        proto::MouseEvent out_mouse_event;
        out_mouse_event.set_mask(mouse_event.mask());
        out_mouse_event.set_x(pos_x);
        out_mouse_event.set_y(pos_y);

        desktop_session_proxy_->injectMouseEvent(out_mouse_event);
    }
    else if (incoming_message_.has_key_event())
    {
        if (sessionType() == proto::SESSION_TYPE_DESKTOP_MANAGE)
            desktop_session_proxy_->injectKeyEvent(incoming_message_.key_event());
    }
    else if (incoming_message_.has_clipboard_event())
    {
        if (sessionType() == proto::SESSION_TYPE_DESKTOP_MANAGE)
            desktop_session_proxy_->injectClipboardEvent(incoming_message_.clipboard_event());
    }
    else if (incoming_message_.has_extension())
    {
        readExtension(incoming_message_.extension());
    }
    else if (incoming_message_.has_config())
    {
        readConfig(incoming_message_.config());
    }
    else
    {
        LOG(LS_WARNING) << "Unhandled message from client";
        return;
    }
}

void ClientSessionDesktop::onMessageWritten(size_t /* pending */)
{
    // Nothing
}

void ClientSessionDesktop::onStarted()
{
    const char* extensions;

    // Supported extensions are different for managing and viewing the desktop.
    if (sessionType() == proto::SESSION_TYPE_DESKTOP_MANAGE)
    {
        extensions = common::kSupportedExtensionsForManage;
    }
    else
    {
        DCHECK_EQ(sessionType(), proto::SESSION_TYPE_DESKTOP_VIEW);
        extensions = common::kSupportedExtensionsForView;
    }

    // Create a configuration request.
    proto::DesktopConfigRequest* request = outgoing_message_.mutable_config_request();

    // Add supported extensions and video encodings.
    request->set_extensions(extensions);
    request->set_video_encodings(common::kSupportedVideoEncodings);

    LOG(LS_INFO) << "Sending config request";
    LOG(LS_INFO) << "Supported extensions: " << request->extensions();
    LOG(LS_INFO) << "Supported video encodings: " << request->video_encodings();

    // Send the request.
    sendMessage(base::serialize(outgoing_message_));
}

void ClientSessionDesktop::encode(const base::Frame* frame, const base::MouseCursor* cursor)
{
    outgoing_message_.Clear();

    if (frame && video_encoder_ && scale_reducer_)
    {
        const base::Size& source_size = frame->size();
        base::Size current_size = preferred_size_;

        if (current_size.width() > source_size.width() ||
            current_size.height() > source_size.height())
        {
            LOG(LS_INFO) << "Preferred size is larger than the original. "
                            "Original frame size will be used";
            current_size = source_size;
        }

        if (current_size.isEmpty())
        {
            LOG(LS_INFO) << "Preferred size has not been set. Original frame size will be used";
            current_size = source_size;
        }

        const base::Frame* scaled_frame = scale_reducer_->scaleFrame(frame, current_size);
        if (!scaled_frame)
        {
            LOG(LS_ERROR) << "No scaled frame";
            return;
        }

        proto::VideoPacket* packet = outgoing_message_.mutable_video_packet();

        // Encode the frame into a video packet.
        video_encoder_->encode(scaled_frame, packet);

        if (packet->has_format())
        {
            proto::Size* screen_size = packet->mutable_format()->mutable_screen_size();
            screen_size->set_width(frame->size().width());
            screen_size->set_height(frame->size().height());

            LOG(LS_INFO) << "Video packet has format";
            LOG(LS_INFO) << "Screen size: " << screen_size->width() << "x" << screen_size->height();
            LOG(LS_INFO) << "Video size: " << packet->format().video_rect().width() << "x"
                         << packet->format().video_rect().height();
        }
    }

    if (cursor && cursor_encoder_)
    {
        if (!cursor_encoder_->encode(*cursor, outgoing_message_.mutable_cursor_shape()))
            outgoing_message_.clear_cursor_shape();
    }

    if (outgoing_message_.has_video_packet() || outgoing_message_.has_cursor_shape())
        sendMessage(base::serialize(outgoing_message_));
}

void ClientSessionDesktop::setScreenList(const proto::ScreenList& list)
{
    outgoing_message_.Clear();

    proto::DesktopExtension* extension = outgoing_message_.mutable_extension();
    extension->set_name(common::kSelectScreenExtension);
    extension->set_data(list.SerializeAsString());

    sendMessage(base::serialize(outgoing_message_));
}

void ClientSessionDesktop::injectClipboardEvent(const proto::ClipboardEvent& event)
{
    if (sessionType() == proto::SESSION_TYPE_DESKTOP_MANAGE)
    {
        outgoing_message_.Clear();

        outgoing_message_.mutable_clipboard_event()->CopyFrom(event);
        sendMessage(base::serialize(outgoing_message_));
    }
}

void ClientSessionDesktop::readExtension(const proto::DesktopExtension& extension)
{
    if (extension.name() == common::kSelectScreenExtension)
    {
        proto::Screen screen;

        if (!screen.ParseFromString(extension.data()))
        {
            LOG(LS_ERROR) << "Unable to parse select screen extension data";
            return;
        }

        desktop_session_proxy_->selectScreen(screen);
        preferred_size_ = base::Size();
    }
    else if (extension.name() == common::kPreferredSizeExtension)
    {
        proto::PreferredSize preferred_size;

        if (!preferred_size.ParseFromString(extension.data()))
        {
            LOG(LS_ERROR) << "Unable to parse preferred size extension data";
            return;
        }

        static const int kMaxScreenSize = std::numeric_limits<int16_t>::max();

        if (preferred_size.width() < 0 || preferred_size.width() > kMaxScreenSize ||
            preferred_size.height() < 0 || preferred_size.height() > kMaxScreenSize)
        {
            LOG(LS_ERROR) << "Invalid preferred size: "
                          << preferred_size.width() << "x" << preferred_size.height();
            return;
        }

        LOG(LS_INFO) << "Preferred size changed: "
                     << preferred_size.width() << "x" << preferred_size.height();

        preferred_size_.set(preferred_size.width(), preferred_size.height());
        desktop_session_proxy_->captureScreen();
    }
    else if (extension.name() == common::kPowerControlExtension)
    {
        if (sessionType() != proto::SESSION_TYPE_DESKTOP_MANAGE)
        {
            LOG(LS_WARNING) << "Power management is only accessible from a desktop manage session";
            return;
        }

        proto::PowerControl power_control;

        if (!power_control.ParseFromString(extension.data()))
        {
            LOG(LS_ERROR) << "Unable to parse power control extension data";
            return;
        }

        switch (power_control.action())
        {
            case proto::PowerControl::ACTION_SHUTDOWN:
                base::PowerController::shutdown();
                break;

            case proto::PowerControl::ACTION_REBOOT:
                base::PowerController::reboot();
                break;

            case proto::PowerControl::ACTION_LOGOFF:
                desktop_session_proxy_->control(proto::internal::Control::LOGOFF);
                break;

            case proto::PowerControl::ACTION_LOCK:
                desktop_session_proxy_->control(proto::internal::Control::LOCK);
                break;

            default:
                LOG(LS_WARNING) << "Unhandled power control action: " << power_control.action();
                break;
        }
    }
    else if (extension.name() == common::kRemoteUpdateExtension)
    {
        if (sessionType() == proto::SESSION_TYPE_DESKTOP_MANAGE)
        {
            launchUpdater(sessionId());
        }
        else
        {
            LOG(LS_WARNING) << "Update can only be launched from a desktop manage session";
        }
    }
    else if (extension.name() == common::kSystemInfoExtension)
    {
        proto::SystemInfo system_info;
        createSystemInfo(&system_info);

        outgoing_message_.Clear();

        proto::DesktopExtension* desktop_extension = outgoing_message_.mutable_extension();
        desktop_extension->set_name(common::kSystemInfoExtension);
        desktop_extension->set_data(system_info.SerializeAsString());

        sendMessage(base::serialize(outgoing_message_));
    }
    else
    {
        LOG(LS_WARNING) << "Unknown extension: " << extension.name();
    }
}

void ClientSessionDesktop::readConfig(const proto::DesktopConfig& config)
{
    switch (config.video_encoding())
    {
        case proto::VIDEO_ENCODING_VP8:
            video_encoder_ = base::VideoEncoderVPX::createVP8();
            break;

        case proto::VIDEO_ENCODING_VP9:
            video_encoder_ = base::VideoEncoderVPX::createVP9();
            break;

        case proto::VIDEO_ENCODING_ZSTD:
            video_encoder_ = base::VideoEncoderZstd::create(
                base::parsePixelFormat(config.pixel_format()), config.compress_ratio());
            break;

        default:
        {
            // No supported video encoding.
            LOG(LS_WARNING) << "Unsupported video encoding: " << config.video_encoding();
        }
        break;
    }

    if (!video_encoder_)
    {
        LOG(LS_ERROR) << "Video encoder not initialized!";
        return;
    }

    cursor_encoder_.reset();
    if (config.flags() & proto::ENABLE_CURSOR_SHAPE)
        cursor_encoder_ = std::make_unique<base::CursorEncoder>();

    scale_reducer_ = std::make_unique<base::ScaleReducer>();

    desktop_session_config_.disable_font_smoothing =
        (config.flags() & proto::DISABLE_FONT_SMOOTHING);
    desktop_session_config_.disable_effects =
        (config.flags() & proto::DISABLE_DESKTOP_EFFECTS);
    desktop_session_config_.disable_wallpaper =
        (config.flags() & proto::DISABLE_DESKTOP_WALLPAPER);
    desktop_session_config_.block_input =
        (config.flags() & proto::BLOCK_REMOTE_INPUT);
    desktop_session_config_.lock_at_disconnect =
        (config.flags() & proto::LOCK_AT_DISCONNECT);

    LOG(LS_INFO) << "NEW CLIENT CONFIGURATION";
    LOG(LS_INFO) << "Video encoding: " << config.video_encoding();
    LOG(LS_INFO) << "Enable cursor shape: " << (cursor_encoder_ != nullptr);
    LOG(LS_INFO) << "Disable font smoothing: " << desktop_session_config_.disable_font_smoothing;
    LOG(LS_INFO) << "Disable desktop effects: " << desktop_session_config_.disable_effects;
    LOG(LS_INFO) << "Disable desktop wallpaper: " << desktop_session_config_.disable_wallpaper;
    LOG(LS_INFO) << "Block input: " << desktop_session_config_.block_input;
    LOG(LS_INFO) << "Lock at disconnect: " << desktop_session_config_.lock_at_disconnect;

    delegate_->onClientSessionConfigured();
}

} // namespace host
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: wizard.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-03-29 15:02:11 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _WIZARD_HXX_
#define _WIZARD_HXX_

#include <rtl/ustring.hxx>
#include <svtools/roadmapwizard.hxx>
#include <vcl/window.hxx>
#include <tools/resid.hxx>

namespace desktop
{

class WizardResId : public ResId
{
public:
    WizardResId( USHORT nId );
};

class FirstStartWizard : public svt::RoadmapWizard
{

public:
    static const WizardState STATE_WELCOME;
    static const WizardState STATE_LICENSE;
    static const WizardState STATE_MIGRATION;
    static const WizardState STATE_USER;
    static const WizardState STATE_REGISTRATION;

    static ResMgr* pResMgr;
    static ResMgr* GetResManager();

    FirstStartWizard(Window* pParent);

    virtual short Execute();
    virtual long PreNotify( NotifyEvent& rNEvt );

    static rtl::OUString getLicensePath();

    void overrideCheck(sal_Bool bOverride);

private:
    sal_Bool m_bOverride;
    WizardState _currentState;
    PathId m_aDefaultPath;
    PathId m_aMigrationPath;
    String m_sNext;
    String m_sCancel;
    sal_Bool m_bDone;
    sal_Bool m_bAccepted;
    Link m_lnkCancel;

    void storeAcceptDate();
    void disableWizard();
    void enableQuickstart();

    DECL_LINK(DeclineHdl, PushButton*);

public:
    static sal_Bool isFirstStart();
    static sal_Bool isLicenseAccepted();

protected:
    // from svt::WizardMachine
    virtual TabPage* createPage(WizardState _nState);
    virtual sal_Bool prepareLeaveCurrentState( CommitPageReason _eReason );
    virtual sal_Bool leaveState(WizardState _nState );
    virtual sal_Bool onFinish(sal_Int32 _nResult);
    virtual void     enterState(WizardState _nState);

    // from svt::RoadmapWizard
    virtual String       getStateDisplayName( WizardState _nState );

};
}
#endif
<commit_msg>INTEGRATION: CWS winregclean1 (1.4.26); FILE MERGED 2005/04/22 13:56:33 mav 1.4.26.1: #i47658# cleaning if required<commit_after>/*************************************************************************
 *
 *  $RCSfile: wizard.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2005-04-29 08:55:52 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _WIZARD_HXX_
#define _WIZARD_HXX_

#include <rtl/ustring.hxx>
#include <svtools/roadmapwizard.hxx>
#include <vcl/window.hxx>
#include <tools/resid.hxx>

namespace desktop
{

class WizardResId : public ResId
{
public:
    WizardResId( USHORT nId );
};

class FirstStartWizard : public svt::RoadmapWizard
{

public:
    static const WizardState STATE_WELCOME;
    static const WizardState STATE_LICENSE;
    static const WizardState STATE_MIGRATION;
    static const WizardState STATE_USER;
    static const WizardState STATE_REGISTRATION;

    static ResMgr* pResMgr;
    static ResMgr* GetResManager();

    FirstStartWizard(Window* pParent);

    virtual short Execute();
    virtual long PreNotify( NotifyEvent& rNEvt );

    static rtl::OUString getLicensePath();

    void overrideCheck(sal_Bool bOverride);

private:
    sal_Bool m_bOverride;
    WizardState _currentState;
    PathId m_aDefaultPath;
    PathId m_aMigrationPath;
    String m_sNext;
    String m_sCancel;
    sal_Bool m_bDone;
    sal_Bool m_bAccepted;
    Link m_lnkCancel;

    void storeAcceptDate();
    void disableWizard();
    void enableQuickstart();

    DECL_LINK(DeclineHdl, PushButton*);

    void cleanOldOfficeRegKeys();

public:
    static sal_Bool isFirstStart();
    static sal_Bool isLicenseAccepted();

protected:
    // from svt::WizardMachine
    virtual TabPage* createPage(WizardState _nState);
    virtual sal_Bool prepareLeaveCurrentState( CommitPageReason _eReason );
    virtual sal_Bool leaveState(WizardState _nState );
    virtual sal_Bool onFinish(sal_Int32 _nResult);
    virtual void     enterState(WizardState _nState);

    // from svt::RoadmapWizard
    virtual String       getStateDisplayName( WizardState _nState );
};
}
#endif
<|endoftext|>


<commit_before>#include "Collection.hpp"

#include "options/Options.hpp"

Collection::Collection():
    currentIdx_ { 0 } {
    // Build map
    for (const auto & itemName: Options::items)
        addItem(itemName);

    // Build vector
    for (auto & itemPair: itemMap_)
        flatten(itemPair.second);
}

const Collection::Items & Collection::items() const {
    return items_;
}

Collection::Items::size_type Collection::currentIndex() const {
    return currentIdx_;
}

void Collection::prev() {
    do {
        if (currentIdx_ == 0)
            currentIdx_ = items_.size() - 1;
        else
            --currentIdx_;
    } while (!current().visible);
}

void Collection::next() {
    do {
        currentIdx_ = (currentIdx_ + 1) % items_.size();
    } while (!current().visible);
}

void Collection::select() {
    current().selected = !current().selected;
}

void Collection::expand() {
    current().expanded = !current().expanded;
    for (auto & childPair: current().childMap)
        setVisible(childPair.second, current().expanded);
}

void Collection::expandRecursive() {
    expandFromNode(current(), !current().expanded);
    for (auto & childPair: current().childMap)
        setVisible(childPair.second, current().expanded);
}

void Collection::expandFromNode(Item & item, bool expanded) {
    item.expanded = expanded;
    for (auto & childPair: item.childMap)
        expandFromNode(childPair.second, expanded);
}

void Collection::show() {
    for (const auto & item: items_)
        if (item.get().selected)
            std::cout << item << std::endl;
}

void Collection::execute() {
    for (const auto & item: items_)
        if (item.get().selected) {
            auto pid = fork();
            if (pid == -1)
                perror(nullptr);
            else if (pid == 0) {
                std::ostringstream oss;
                oss << item;
                char * const args[3] = {
                    (char *)Options::command.c_str(),
                    (char *)oss.str().c_str(),
                    nullptr
                };
                execvp(Options::command.c_str(), args);
                std::cerr << "Error executing " << Options::command << "\n";
                perror(nullptr);
            }
            else
                waitpid(pid, nullptr, 0);
        }
}

Item & Collection::current() {
    return items_.at(currentIdx_);
}

void Collection::addItem(const std::string & name) {
    auto first = name.begin();
    auto last = name.end();

    auto onParsed = [this](const auto & components) {
        auto inserted = itemMap_.emplace(
            components.front(),
            components.front()
        );

        auto item = std::ref(inserted.first->second);
        auto it = std::next(components.begin());
        for (; it != components.end(); ++it)
            item = item.get()[*it];
    };

    bool parseOK = qi::parse(
        first,
        last,
        (qi::as_string[*(qi::char_ - '/')] % '/')[onParsed]
    );
    (void)parseOK;
}

void Collection::flatten(Item & item) {
    items_.emplace_back(item);

    for (auto & childPair: item.childMap)
        flatten(childPair.second);
}

void Collection::setVisible(Item & item, bool visible) {
    item.visible = visible;
    for (auto & childPair: item.childMap)
        setVisible(childPair.second, item.expanded && visible);
}
<commit_msg>[:lipstick:] http://stackoverflow.com/questions/190184/execv-and-const-ness<commit_after>#include "Collection.hpp"

#include "options/Options.hpp"

Collection::Collection():
    currentIdx_ { 0 } {
    // Build map
    for (const auto & itemName: Options::items)
        addItem(itemName);

    // Build vector
    for (auto & itemPair: itemMap_)
        flatten(itemPair.second);
}

const Collection::Items & Collection::items() const {
    return items_;
}

Collection::Items::size_type Collection::currentIndex() const {
    return currentIdx_;
}

void Collection::prev() {
    do {
        if (currentIdx_ == 0)
            currentIdx_ = items_.size() - 1;
        else
            --currentIdx_;
    } while (!current().visible);
}

void Collection::next() {
    do {
        currentIdx_ = (currentIdx_ + 1) % items_.size();
    } while (!current().visible);
}

void Collection::select() {
    current().selected = !current().selected;
}

void Collection::expand() {
    current().expanded = !current().expanded;
    for (auto & childPair: current().childMap)
        setVisible(childPair.second, current().expanded);
}

void Collection::expandRecursive() {
    expandFromNode(current(), !current().expanded);
    for (auto & childPair: current().childMap)
        setVisible(childPair.second, current().expanded);
}

void Collection::expandFromNode(Item & item, bool expanded) {
    item.expanded = expanded;
    for (auto & childPair: item.childMap)
        expandFromNode(childPair.second, expanded);
}

void Collection::show() {
    for (const auto & item: items_)
        if (item.get().selected)
            std::cout << item << std::endl;
}

void Collection::execute() {
    for (const auto & item: items_)
        if (item.get().selected) {
            auto pid = fork();
            if (pid == -1)
                perror(nullptr);
            else if (pid == 0) {
                std::ostringstream oss;
                oss << item;
                const char * const args[3] = {
                    Options::command.c_str(),
                    oss.str().c_str(),
                    nullptr
                };
                execvp(Options::command.c_str(), const_cast<char **>(args));
                std::cerr << "Error executing " << Options::command << "\n";
                perror(nullptr);
            }
            else
                waitpid(pid, nullptr, 0);
        }
}

Item & Collection::current() {
    return items_.at(currentIdx_);
}

void Collection::addItem(const std::string & name) {
    auto first = name.begin();
    auto last = name.end();

    auto onParsed = [this](const auto & components) {
        auto inserted = itemMap_.emplace(
            components.front(),
            components.front()
        );

        auto item = std::ref(inserted.first->second);
        auto it = std::next(components.begin());
        for (; it != components.end(); ++it)
            item = item.get()[*it];
    };

    bool parseOK = qi::parse(
        first,
        last,
        (qi::as_string[*(qi::char_ - '/')] % '/')[onParsed]
    );
    (void)parseOK;
}

void Collection::flatten(Item & item) {
    items_.emplace_back(item);

    for (auto & childPair: item.childMap)
        flatten(childPair.second);
}

void Collection::setVisible(Item & item, bool visible) {
    item.visible = visible;
    for (auto & childPair: item.childMap)
        setVisible(childPair.second, item.expanded && visible);
}
<|endoftext|>


<commit_before>/*
 * ReportRank.cc
 *
 * Implements the PageRank graph centrality algorithm for word-senses.
 *
 * Copyright (c) 2008 Linas Vepstas <linas@linas.org>
 */
#include <stdio.h>

#include "FollowLink.h"
#include "ForeachWord.h"
#include "ReportRank.h"
#include "Node.h"
#include "SimpleTruthValue.h"
#include "TruthValue.h"

using namespace opencog;

#define DEBUG

ReportRank::ReportRank(void)
{
}

ReportRank::~ReportRank()
{
}

/**
 * For each parse of the sentence, make a report.
 */
void ReportRank::report_rank(Handle h)
{
	parse_cnt = 0;
	foreach_parse(h, &ReportRank::report_parse, this);
}

/**
 * For each parse, walk over each word.
 */
bool ReportRank::report_parse(Handle h)
{
	printf ("Parse %d:\n", parse_cnt);
	foreach_word_instance(h, &ReportRank::report_word, this);
	parse_cnt ++;
	return false;
}

/**
 * Report the parse rank for this word.
 */
bool ReportRank::report_word(Handle h)
{
	// Only noun-senses and verb-senses get ranked.
	std::string pos = get_pos_of_word_instance(h);
	if (pos.compare("#noun") && pos.compare("#verb")) return false;

	hi_score = 0.0;
	foreach_word_sense_of_inst(h, &ReportRank::choose_sense, this);

	Node *word = dynamic_cast<Node *>(TLB::getAtom(h));
	Node *sense = dynamic_cast<Node *>(TLB::getAtom(hi_scorer));
	printf ("%s sense %s score=%g\n",
	        word->getName().c_str(), sense->getName().c_str(), hi_score);

	return false;
}

bool ReportRank::choose_sense(Handle word_sense_h,
                              Handle sense_link_h)
{
	Link *l = dynamic_cast<Link *>(TLB::getAtom(sense_link_h));
	double score = l->getTruthValue().getMean();
printf ("word sense=%s score=%f hi=%f\n", n->getName().c_str(), score, hi_score);
	if (hi_score < score)
	{
		hi_score = score;
		hi_scorer = word_sense_h;
	}
	return false;
}

/* ============================== END OF FILE ====================== */
<commit_msg>whoops, fix a build break<commit_after>/*
 * ReportRank.cc
 *
 * Implements the PageRank graph centrality algorithm for word-senses.
 *
 * Copyright (c) 2008 Linas Vepstas <linas@linas.org>
 */
#include <stdio.h>

#include "FollowLink.h"
#include "ForeachWord.h"
#include "ReportRank.h"
#include "Node.h"
#include "SimpleTruthValue.h"
#include "TruthValue.h"

using namespace opencog;

#define DEBUG

ReportRank::ReportRank(void)
{
}

ReportRank::~ReportRank()
{
}

/**
 * For each parse of the sentence, make a report.
 */
void ReportRank::report_rank(Handle h)
{
	parse_cnt = 0;
	foreach_parse(h, &ReportRank::report_parse, this);
}

/**
 * For each parse, walk over each word.
 */
bool ReportRank::report_parse(Handle h)
{
	printf ("Parse %d:\n", parse_cnt);
	foreach_word_instance(h, &ReportRank::report_word, this);
	parse_cnt ++;
	return false;
}

/**
 * Report the parse rank for this word.
 */
bool ReportRank::report_word(Handle h)
{
	// Only noun-senses and verb-senses get ranked.
	std::string pos = get_pos_of_word_instance(h);
	if (pos.compare("#noun") && pos.compare("#verb")) return false;

	hi_score = 0.0;
	foreach_word_sense_of_inst(h, &ReportRank::choose_sense, this);

	Node *word = dynamic_cast<Node *>(TLB::getAtom(h));
	Node *sense = dynamic_cast<Node *>(TLB::getAtom(hi_scorer));
	printf ("%s sense %s score=%g\n",
	        word->getName().c_str(), sense->getName().c_str(), hi_score);

	return false;
}

bool ReportRank::choose_sense(Handle word_sense_h,
                              Handle sense_link_h)
{
	Link *l = dynamic_cast<Link *>(TLB::getAtom(sense_link_h));
	double score = l->getTruthValue().getMean();
Node *n = dynamic_cast<Node *>(TLB::getAtom(word_sense_h));
printf ("word sense=%s score=%f hi=%f\n", n->getName().c_str(), score, hi_score);
	if (hi_score < score)
	{
		hi_score = score;
		hi_scorer = word_sense_h;
	}
	return false;
}

/* ============================== END OF FILE ====================== */
<|endoftext|>


<commit_before>/**
 * Daniel Sebastian Iliescu, http://dansil.net
 * MIT License (MIT), http://opensource.org/licenses/MIT
 *
 * A doubly-linked implementation of a list combining both LIFO and FIFO operations.
 *
 * C++ Standard Library compliant iterators for the list are provided. Custom allocators are also supported.
 *
 * All modifier functions operate in constant time (amortized for custom allocators) since no traversal occurs.
 */

#pragma once

#include <memory>

namespace dsa
{
	template <
		typename T,
		typename Allocator = std::allocator< T > >
	class doubly_linked_list
	{
	public:
		struct doubly_linked_node
		{
			doubly_linked_node() noexcept = default;
			doubly_linked_node( T input_item ) noexcept :
				item( input_item )
			{
			}
			~doubly_linked_node() noexcept = default;

			doubly_linked_node( doubly_linked_node const & ) = default;
			doubly_linked_node( doubly_linked_node && ) noexcept = default;

			doubly_linked_node& operator=( doubly_linked_node const & ) = default;
			doubly_linked_node& operator=( doubly_linked_node && ) noexcept = default;

			bool
			operator==( doubly_linked_node const & rhs ) const noexcept
			{
				return ( this->item == rhs.item );
			}

			bool
			operator!=( doubly_linked_node const & rhs ) const noexcept
			{
				return !( *this == rhs );
			}

			T item = T();

			doubly_linked_node* previous = nullptr;
			doubly_linked_node* next = nullptr;
		};

		// Iterator class for both mutable and const iterators.
		template< bool IsConstIterator >
		class iterator_impl
		{
		public:
			using iterator_category = std::bidirectional_iterator_tag;
			using value_type = T;
			using difference_type = std::ptrdiff_t;
			using pointer =
				typename std::conditional<
					IsConstIterator,
					const T* const,
					T* >::type;
			using reference =
				typename std::conditional<
					IsConstIterator,
					const T&,
					T& >::type;

			iterator_impl( doubly_linked_node* const input_node ) noexcept :
				node( input_node )
			{
			}

			iterator_impl( const iterator_impl< false >& it ) noexcept :
				node( it.node )
			{
			}

			 // Copy construction for const iterators is handled by the default
			 // generated implementation. The copy constructor specialization for
			 // mutable iterators allows for the conversion from mutable to const.
			iterator_impl& operator=( const iterator_impl< false >& it ) noexcept
			{
				this->node = it.node;

				return *this;
			}

			void
			swap( iterator_impl& it ) noexcept
			{
				std::swap( this->node, it.node );
			}

			iterator_impl&
			operator++() noexcept
			{
				this->node = this->node->next;

				return *this;
			}

			iterator_impl
			operator++( int ) noexcept
			{
				const iterator_impl iterator( *this );
				++( *this );

				return iterator;
			}

			iterator_impl&
			operator--() noexcept
			{
				this->node = this->node->previous;

				return *this;
			}

			iterator_impl
			operator--( int ) noexcept
			{
				const iterator_impl iterator ( *this );
				--( *this );

				return iterator;
			}

			reference
			operator*() const noexcept
			{
				return this->node->item;
			}

			pointer
			operator->() const noexcept
			{
				return this->node;
			}

			bool
			operator==( const iterator_impl& it ) const noexcept
			{
				return
					( this->node == it.node ) ||
					( ( this->node && it.node ) &&
						( *this->node == *it.node ) );
			}

			bool
			operator!=( const iterator_impl& it ) const noexcept
			{
				return !( *this == it );
			}

		private:
			doubly_linked_node* node;
		};

		using iterator = iterator_impl< false >;
		using const_iterator = iterator_impl< true >;
		using reverse_iterator = std::reverse_iterator< iterator >;
		using const_reverse_iterator = std::reverse_iterator< const_iterator >;

		using value_type = T;
		using allocator_type = typename std::allocator_traits< Allocator >::template rebind_alloc< doubly_linked_node >;
		using size_type = std::size_t;
		using difference_type = typename std::iterator_traits< iterator >::difference_type;
		using reference = value_type&;
		using const_reference = const value_type&;
		using pointer = typename std::allocator_traits< allocator_type >::pointer;
		using const_pointer = typename std::allocator_traits< allocator_type >::const_pointer;

		doubly_linked_list() noexcept = default;

		~doubly_linked_list() noexcept
		{
			this->clear();
		}

		doubly_linked_list( const doubly_linked_list& other )
		{
			auto node = other.front_node;

			while ( this->valid_node( node ) )
			{
				this->push_back( node->item );
				node = node->next;
			}
		}

		doubly_linked_list( doubly_linked_list&& other ) noexcept :
			front_node( other.front_node ),
			back_node( other.back_node ),
			sentinel( std::move( other.sentinel ) ),
			nodes( other.nodes )
		{
			other.front_node = nullptr;
			other.back_node = nullptr;
			other.nodes = 0;
		}

		doubly_linked_list&
		operator=( const doubly_linked_list& rhs )
		{
			this->swap( *this, doubly_linked_list( rhs ) );

			return *this;
		}

		doubly_linked_list&
		operator=( doubly_linked_list&& rhs ) noexcept
		{
			this->swap( *this, rhs );

			return *this;
		}

		bool
		operator==( const doubly_linked_list& rhs ) const noexcept
		{
			return equals( this->front_node, rhs.front_node );
		}

		bool
		operator!=( const doubly_linked_list& rhs ) const noexcept
		{
			return !( *this == rhs );
		}

		friend void
		swap( doubly_linked_list& first, doubly_linked_list& second ) noexcept
		{
			using std::swap;

			swap( first.front_node, second.front_node );
			swap( first.back_node, second.back_node );
			swap( first.sentinel, second.sentinel );
			swap( first.nodes, second.nodes );
		}

		allocator_type
		get_allocator() const
		{
			return this->allocator;
		}

		/**
		 * Element access
		 */

		T
		front() const noexcept
		{
			return this->empty() ? T() : this->front_node->item;
		}

		T
		back() const noexcept
		{
			return this->empty() ? T() : this->back_node->item;
		}

		/**
		 * Iterators
		 */

		iterator
		begin() noexcept
		{
			return this->first();
		}

		const_iterator
		begin() const noexcept
		{
			return this->first();
		}

		const_iterator
		cbegin() const noexcept
		{
			return this->begin();
		}

		iterator
		end() noexcept
		{
			return this->last();
		}

		const_iterator
		end() const noexcept
		{
			return this->last();
		}

		const_iterator
		cend() const noexcept
		{
			return this->end();
		}

		reverse_iterator
		rbegin() noexcept
		{
			return reverse_iterator( this->end() );
		}

		const_reverse_iterator
		rbegin() const noexcept
		{
			return const_reverse_iterator( this->end() );
		}

		const_reverse_iterator
		crbegin() const noexcept
		{
			return this->rbegin();
		}

		reverse_iterator
		rend() noexcept
		{
			return reverse_iterator( this->begin() );
		}

		const_reverse_iterator
		rend() const noexcept
		{
			return const_reverse_iterator( this->begin() );
		}

		const_reverse_iterator
		crend() const noexcept
		{
			return this->rend();
		}

		/**
		 * Modifiers
		 */

		void
		push_front( T item )
		{
			auto new_node = this->create_node( item );

			if ( this->empty() )
			{
				this->front_node = new_node;
				this->back_node = new_node;

				this->update_sentinel();
			}
			else
			{
				new_node->next = this->front_node;

				this->front_node->previous = new_node;
				this->front_node = new_node;
			}

			++( this->nodes );
		}

		void
		push_back( T item )
		{
			auto new_node = this->create_node( item );

			if ( this->empty() )
			{
				this->front_node = new_node;
				this->back_node = new_node;
			}
			else
			{
				new_node->previous = this->back_node;

				this->back_node->next = new_node;
				this->back_node = new_node;
			}

			this->update_sentinel();

			++( this->nodes );
		}

		T
		pop_front() noexcept
		{
			if ( this->empty() )
			{
				return T();
			}

			const auto item = this->front_node->item;
			auto next_node = this->front_node->next;

			this->destroy_node( this->front_node );

			if ( this->valid_node( next_node ) )
			{
				next_node->previous = nullptr;
				this->front_node = next_node;
			}
			else
			{
				this->front_node = nullptr;
				this->back_node = nullptr;
			}

			--( this->nodes );

			return item;
		}

		T
		pop_back() noexcept
		{
			if ( this->empty() )
			{
				return T();
			}

			const auto item = this->back_node->item;
			auto previous_node = this->back_node->previous;

			this->destroy_node( this->back_node );

			if ( previous_node )
			{
				previous_node->next = nullptr;
				this->back_node = previous_node;

				this->update_sentinel();
			}
			else
			{
				this->front_node = nullptr;
				this->back_node = nullptr;
			}

			--( this->nodes );

			return item;
		}

		void
		clear() noexcept
		{
			this->clear( *this );
		}

		bool
		empty() const noexcept
		{
			return ( ( !this->front_node ) &&
					 ( !this->back_node ) &&
					 ( this->nodes == 0 ) );
		}

		size_type
		size() const noexcept
		{
			return this->nodes;
		}

		size_type
		max_size() const noexcept
		{
			return std::allocator_traits< allocator_type >::max_size();
		}

	private:
		typename std::allocator_traits< allocator_type >::pointer
		create_node( T item )
		{
			auto node = std::allocator_traits< allocator_type >::allocate( this->allocator, 1 );
			std::allocator_traits< allocator_type >::construct( this->allocator, node, item );

			return node;
		}

		void destroy_node( typename std::allocator_traits< allocator_type >::pointer node ) noexcept
		{
			std::allocator_traits< allocator_type >::deallocate( this->allocator, node, 1 );
		}

		static void
		clear( doubly_linked_list& instance ) noexcept
		{
			while ( !instance.empty() )
			{
				instance.pop_back();
			}
		}

		void
		update_sentinel()
		{
			this->sentinel.previous = this->back_node;
			this->back_node->next = &this->sentinel;
		}

		pointer
		first() const noexcept
		{
			return this->front_node;
		}

		pointer
		last() const noexcept
		{
			return this->back_node->next;
		}

		bool
		valid_node( pointer node ) const
		{
			return node && ( node != &this->sentinel );
		}

		static bool
		equals(
			pointer node1,
			pointer node2 ) noexcept
		{
			return
				( node1 == node2 ) ||
				( ( node1 && node2 ) &&
					( *node1 == *node2 ) &&
					equals( node1->next, node2->next ) );
		}

		allocator_type allocator;

		pointer front_node = nullptr;
		pointer back_node = nullptr;

		// Sentinel used to point to the past-the-end sequence for iteration.
		typename std::allocator_traits< allocator_type >::value_type sentinel;

		size_type nodes = 0;
	};
}<commit_msg>Fixed doubly_linked_list tests.<commit_after>/**
 * Daniel Sebastian Iliescu, http://dansil.net
 * MIT License (MIT), http://opensource.org/licenses/MIT
 *
 * A doubly-linked implementation of a list combining both LIFO and FIFO operations.
 *
 * C++ Standard Library compliant iterators for the list are provided. Custom allocators are also supported.
 *
 * All modifier functions operate in constant time (amortized for custom allocators) since no traversal occurs.
 */

#pragma once

#include <memory>

namespace dsa
{
	template <
		typename T,
		typename Allocator = std::allocator< T > >
	class doubly_linked_list
	{
	public:
		struct doubly_linked_node
		{
			doubly_linked_node() noexcept = default;
			doubly_linked_node( T input_item ) noexcept :
				item( input_item )
			{
			}
			~doubly_linked_node() noexcept = default;

			doubly_linked_node( doubly_linked_node const & ) = default;
			doubly_linked_node( doubly_linked_node && ) noexcept = default;

			doubly_linked_node& operator=( doubly_linked_node const & ) = default;
			doubly_linked_node& operator=( doubly_linked_node && ) noexcept = default;

			bool
			operator==( doubly_linked_node const & rhs ) const noexcept
			{
				return ( this->item == rhs.item );
			}

			bool
			operator!=( doubly_linked_node const & rhs ) const noexcept
			{
				return !( *this == rhs );
			}

			T item = T();

			doubly_linked_node* previous = nullptr;
			doubly_linked_node* next = nullptr;
		};

		// Iterator class for both mutable and const iterators.
		template< bool IsConstIterator >
		class iterator_impl
		{
		public:
			using iterator_category = std::bidirectional_iterator_tag;
			using value_type = T;
			using difference_type = std::ptrdiff_t;
			using pointer =
				typename std::conditional<
					IsConstIterator,
					const T* const,
					T* >::type;
			using reference =
				typename std::conditional<
					IsConstIterator,
					const T&,
					T& >::type;

			iterator_impl( doubly_linked_node* const input_node ) noexcept :
				node( input_node )
			{
			}

			iterator_impl( const iterator_impl< false >& it ) noexcept :
				node( it.node )
			{
			}

			 // Copy construction for const iterators is handled by the default
			 // generated implementation. The copy constructor specialization for
			 // mutable iterators allows for the conversion from mutable to const.
			iterator_impl& operator=( const iterator_impl< false >& it ) noexcept
			{
				this->node = it.node;

				return *this;
			}

			void
			swap( iterator_impl& it ) noexcept
			{
				std::swap( this->node, it.node );
			}

			iterator_impl&
			operator++() noexcept
			{
				this->node = this->node->next;

				return *this;
			}

			iterator_impl
			operator++( int ) noexcept
			{
				const iterator_impl iterator( *this );
				++( *this );

				return iterator;
			}

			iterator_impl&
			operator--() noexcept
			{
				this->node = this->node->previous;

				return *this;
			}

			iterator_impl
			operator--( int ) noexcept
			{
				const iterator_impl iterator ( *this );
				--( *this );

				return iterator;
			}

			reference
			operator*() const noexcept
			{
				return this->node->item;
			}

			pointer
			operator->() const noexcept
			{
				return this->node;
			}

			bool
			operator==( const iterator_impl& it ) const noexcept
			{
				return
					( this->node == it.node ) ||
					( ( this->node && it.node ) &&
						( *this->node == *it.node ) );
			}

			bool
			operator!=( const iterator_impl& it ) const noexcept
			{
				return !( *this == it );
			}

		private:
			doubly_linked_node* node;
		};

		using iterator = iterator_impl< false >;
		using const_iterator = iterator_impl< true >;
		using reverse_iterator = std::reverse_iterator< iterator >;
		using const_reverse_iterator = std::reverse_iterator< const_iterator >;

		using value_type = T;
		using allocator_type = typename std::allocator_traits< Allocator >::template rebind_alloc< doubly_linked_node >;
		using size_type = std::size_t;
		using difference_type = typename std::iterator_traits< iterator >::difference_type;
		using reference = value_type&;
		using const_reference = const value_type&;
		using pointer = typename std::allocator_traits< allocator_type >::pointer;
		using const_pointer = typename std::allocator_traits< allocator_type >::const_pointer;

		doubly_linked_list() noexcept = default;

		~doubly_linked_list() noexcept
		{
			this->clear();
		}

		doubly_linked_list( const doubly_linked_list& other )
		{
			auto node = other.front_node;

			while ( other.valid_node( node ) )
			{
				this->push_back( node->item );
				node = node->next;
			}
		}

		doubly_linked_list( doubly_linked_list&& other ) noexcept :
			allocator( other.allocator ),
			front_node( other.front_node ),
			back_node( other.back_node ),
			sentinel( std::move( other.sentinel ) ),
			nodes( other.nodes )
		{
			other.front_node = nullptr;
			other.back_node = nullptr;
			other.nodes = 0;
		}

		doubly_linked_list&
		operator=( const doubly_linked_list& rhs )
		{
			this->swap( *this, doubly_linked_list( rhs ) );

			return *this;
		}

		doubly_linked_list&
		operator=( doubly_linked_list&& rhs ) noexcept
		{
			this->swap( *this, rhs );

			return *this;
		}

		bool
		operator==( const doubly_linked_list& rhs ) const noexcept
		{
			return equals( this->front_node, rhs.front_node );
		}

		bool
		operator!=( const doubly_linked_list& rhs ) const noexcept
		{
			return !( *this == rhs );
		}

		friend void
		swap( doubly_linked_list& first, doubly_linked_list& second ) noexcept
		{
			using std::swap;

			swap( first.front_node, second.front_node );
			swap( first.back_node, second.back_node );
			swap( first.sentinel, second.sentinel );
			swap( first.nodes, second.nodes );
		}

		allocator_type
		get_allocator() const
		{
			return this->allocator;
		}

		/**
		 * Element access
		 */

		T
		front() const noexcept
		{
			return this->empty() ? T() : this->front_node->item;
		}

		T
		back() const noexcept
		{
			return this->empty() ? T() : this->back_node->item;
		}

		/**
		 * Iterators
		 */

		iterator
		begin() noexcept
		{
			return this->first();
		}

		const_iterator
		begin() const noexcept
		{
			return this->first();
		}

		const_iterator
		cbegin() const noexcept
		{
			return this->begin();
		}

		iterator
		end() noexcept
		{
			return this->last();
		}

		const_iterator
		end() const noexcept
		{
			return this->last();
		}

		const_iterator
		cend() const noexcept
		{
			return this->end();
		}

		reverse_iterator
		rbegin() noexcept
		{
			return reverse_iterator( this->end() );
		}

		const_reverse_iterator
		rbegin() const noexcept
		{
			return const_reverse_iterator( this->end() );
		}

		const_reverse_iterator
		crbegin() const noexcept
		{
			return this->rbegin();
		}

		reverse_iterator
		rend() noexcept
		{
			return reverse_iterator( this->begin() );
		}

		const_reverse_iterator
		rend() const noexcept
		{
			return const_reverse_iterator( this->begin() );
		}

		const_reverse_iterator
		crend() const noexcept
		{
			return this->rend();
		}

		/**
		 * Modifiers
		 */

		void
		push_front( T item )
		{
			auto new_node = this->create_node( item );

			if ( this->empty() )
			{
				this->front_node = new_node;
				this->back_node = new_node;

				this->update_sentinel();
			}
			else
			{
				new_node->next = this->front_node;

				this->front_node->previous = new_node;
				this->front_node = new_node;
			}

			++( this->nodes );
		}

		void
		push_back( T item )
		{
			auto new_node = this->create_node( item );

			if ( this->empty() )
			{
				this->front_node = new_node;
				this->back_node = new_node;
			}
			else
			{
				new_node->previous = this->back_node;

				this->back_node->next = new_node;
				this->back_node = new_node;
			}

			this->update_sentinel();

			++( this->nodes );
		}

		T
		pop_front() noexcept
		{
			if ( this->empty() )
			{
				return T();
			}

			const auto item = this->front_node->item;
			auto next_node = this->front_node->next;

			this->destroy_node( this->front_node );

			if ( this->valid_node( next_node ) )
			{
				next_node->previous = nullptr;
				this->front_node = next_node;
			}
			else
			{
				this->front_node = nullptr;
				this->back_node = nullptr;
			}

			--( this->nodes );

			return item;
		}

		T
		pop_back() noexcept
		{
			if ( this->empty() )
			{
				return T();
			}

			const auto item = this->back_node->item;
			auto previous_node = this->back_node->previous;

			this->destroy_node( this->back_node );

			if ( previous_node )
			{
				previous_node->next = nullptr;
				this->back_node = previous_node;

				this->update_sentinel();
			}
			else
			{
				this->front_node = nullptr;
				this->back_node = nullptr;
			}

			--( this->nodes );

			return item;
		}

		void
		clear() noexcept
		{
			this->clear( *this );
		}

		bool
		empty() const noexcept
		{
			return ( ( !this->front_node ) &&
					 ( !this->back_node ) &&
					 ( this->nodes == 0 ) );
		}

		size_type
		size() const noexcept
		{
			return this->nodes;
		}

		size_type
		max_size() const noexcept
		{
			return std::allocator_traits< allocator_type >::max_size();
		}

	private:
		typename std::allocator_traits< allocator_type >::pointer
		create_node( T item )
		{
			auto node = std::allocator_traits< allocator_type >::allocate( this->allocator, 1 );
			std::allocator_traits< allocator_type >::construct( this->allocator, node, item );

			return node;
		}

		void destroy_node( typename std::allocator_traits< allocator_type >::pointer node ) noexcept
		{
			std::allocator_traits< allocator_type >::deallocate( this->allocator, node, 1 );
		}

		static void
		clear( doubly_linked_list& instance ) noexcept
		{
			while ( !instance.empty() )
			{
				instance.pop_back();
			}
		}

		void
		update_sentinel()
		{
			this->sentinel.previous = this->back_node;
			this->back_node->next = &this->sentinel;
		}

		pointer
		first() const noexcept
		{
			return this->front_node;
		}

		pointer
		last() const noexcept
		{
			return this->back_node->next;
		}

		bool
		valid_node( pointer node ) const
		{
			return node && ( node != &this->sentinel );
		}

		static bool
		equals(
			pointer node1,
			pointer node2 ) noexcept
		{
			return
				( node1 == node2 ) ||
				( ( node1 && node2 ) &&
					( *node1 == *node2 ) &&
					equals( node1->next, node2->next ) );
		}

		allocator_type allocator;

		pointer front_node = nullptr;
		pointer back_node = nullptr;

		// Sentinel used to point to the past-the-end sequence for iteration.
		typename std::allocator_traits< allocator_type >::value_type sentinel;

		size_type nodes = 0;
	};
}<|endoftext|>


<commit_before>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Radu Serban, Justin Madsen
// =============================================================================
//
// Front and Rear HMMWV suspension subsystems (reduced double A-arm)
//
// =============================================================================

#include "assets/ChBoxShape.h"
#include "assets/ChColorAsset.h"

#include "HMMWV9_DoubleWishbone.h"

using namespace chrono;

namespace hmmwv9 {

// -----------------------------------------------------------------------------
// Static variables
// -----------------------------------------------------------------------------

static const double in2m = 0.0254;

const double     HMMWV9_DoubleWishboneFront::m_spindleMass = 1;
const double     HMMWV9_DoubleWishboneFront::m_uprightMass = 1;

const ChVector<> HMMWV9_DoubleWishboneFront::m_spindleInertia(1, 1, 1);
const ChVector<> HMMWV9_DoubleWishboneFront::m_uprightInertia(1, 1, 1);

const double     HMMWV9_DoubleWishboneFront::m_axleInertia = 0.4;

const ChVector<> HMMWV9_DoubleWishboneFront::m_uprightDims(0.1, 0.05, 0.1);

const double     HMMWV9_DoubleWishboneFront::m_springCoefficient  = 167062.0;
const double     HMMWV9_DoubleWishboneFront::m_dampingCoefficient = 22459.0;
const double     HMMWV9_DoubleWishboneFront::m_springRestLength   = 0.4562;

// -----------------------------------------------------------------------------

const double     HMMWV9_DoubleWishboneRear::m_spindleMass = 1;
const double     HMMWV9_DoubleWishboneRear::m_uprightMass = 1;

const ChVector<> HMMWV9_DoubleWishboneRear::m_spindleInertia(1, 1, 1);
const ChVector<> HMMWV9_DoubleWishboneRear::m_uprightInertia(1, 1, 1);

const double     HMMWV9_DoubleWishboneRear::m_axleInertia = 0.4;

const ChVector<> HMMWV9_DoubleWishboneRear::m_uprightDims(0.1, 0.05, 0.1);

const double     HMMWV9_DoubleWishboneRear::m_springCoefficient = 369149.0;
const double     HMMWV9_DoubleWishboneRear::m_dampingCoefficient = 35024.0;
const double     HMMWV9_DoubleWishboneRear::m_springRestLength = 0.4562;

// -----------------------------------------------------------------------------
// Constructors
// -----------------------------------------------------------------------------
HMMWV9_DoubleWishboneFront::HMMWV9_DoubleWishboneFront(const std::string& name,
                                                       ChSuspension::Side side,
                                                       bool               driven)
: ChDoubleWishboneReduced(name, side, driven)
{
}

HMMWV9_DoubleWishboneRear::HMMWV9_DoubleWishboneRear(const std::string& name,
                                                     ChSuspension::Side side,
                                                     bool               driven)
: ChDoubleWishboneReduced(name, side, driven)
{
}

// -----------------------------------------------------------------------------
// Implementations of the getLocation() virtual methods.
// -----------------------------------------------------------------------------

const ChVector<> HMMWV9_DoubleWishboneFront::getLocation(PointId which)
{
  switch (which) {
  case SPINDLE:  return in2m * ChVector<>(0, 0, 0);
  case UPRIGHT:  return in2m * ChVector<>(0, -4.0000, 0);
  case UCA_F:    return in2m * ChVector<>(0.3000, -18.2600, 10.6650);
  case UCA_B:    return in2m * ChVector<>(8.9700, -18.2600, 8.7250);
  case UCA_U:    return in2m * ChVector<>(0.5000, -7.6500, 9.5150);
  case LCA_F:    return in2m * ChVector<>(-10.3800, -23.7200, 1.0350);
  case LCA_B:    return in2m * ChVector<>(7.2000, -23.7200, 1.0350);
  case LCA_U:    return in2m * ChVector<>(-0.1900, -4.8500, -3.6150);
  case SHOCK_C:  return in2m * ChVector<>(-5.6900, -7.9500, 13.7550);
  case SHOCK_U:  return in2m * ChVector<>(-5.4200, -4.8500, -0.4850);
  case TIEROD_C: return in2m * ChVector<>(11.8000, -26.0100, 0);
  case TIEROD_U: return in2m * ChVector<>(5.3300, -3.5000, 0);
  default:       return ChVector<>(0, 0, 0);
  }
}

const ChVector<> HMMWV9_DoubleWishboneRear::getLocation(PointId which)
{
  switch (which) {
  case SPINDLE:  return in2m * ChVector<>(0, 0, 0);
  case UPRIGHT:  return in2m * ChVector<>(0, -4.0000, 0);
  case UCA_F:    return in2m * ChVector<>(-1.6700, -17.620, 9.9150);
  case UCA_B:    return in2m * ChVector<>(-12.3800, -17.6200, 9.9150);
  case UCA_U:    return in2m * ChVector<>(0, -7.6500, 10.3150);
  case LCA_F:    return in2m * ChVector<>(10.1900, -23.7200, 1.0350);
  case LCA_B:    return in2m * ChVector<>(-7.3900, -23.7200, 1.0350);
  case LCA_U:    return in2m * ChVector<>(0, -4.8500, -3.6150);
  case SHOCK_C:  return in2m * ChVector<>(5.4900, -7.6200, 13.7550);
  case SHOCK_U:  return in2m * ChVector<>(5.4900, -4.8500, -0.4750);
  case TIEROD_C: return in2m * ChVector<>(-11.3000, -19.4400, 0.6650);
  case TIEROD_U: return in2m * ChVector<>(-5.3000, -3.4900, 0.6650);
  default:       return ChVector<>(0, 0, 0);
  }
}

// -----------------------------------------------------------------------------
// Implementations of the OnInitializeUpright() virtual methods.
// Add simple visualization for the upright body.
// -----------------------------------------------------------------------------

void HMMWV9_DoubleWishboneFront::OnInitializeUpright()
{
  ChSharedPtr<ChBoxShape> box(new ChBoxShape);
  box->GetBoxGeometry().SetLenghts(m_uprightDims);
  m_upright->AddAsset(box);

  ChSharedPtr<ChColorAsset> col(new ChColorAsset);
  switch (m_side) {
  case RIGHT: col->SetColor(ChColor(0.6f, 0.2f, 0.2f)); break;
  case LEFT:  col->SetColor(ChColor(0.2f, 0.6f, 0.2f)); break;
  }
  m_upright->AddAsset(col);
}

void HMMWV9_DoubleWishboneRear::OnInitializeUpright()
{
  ChSharedPtr<ChBoxShape> box(new ChBoxShape);
  box->GetBoxGeometry().SetLenghts(m_uprightDims);
  m_upright->AddAsset(box);

  ChSharedPtr<ChColorAsset> col(new ChColorAsset);
  switch (m_side) {
  case RIGHT: col->SetColor(ChColor(0.6f, 0.4f, 0.4f)); break;
  case LEFT:  col->SetColor(ChColor(0.4f, 0.6f, 0.6f)); break;
  }
  m_upright->AddAsset(col);
}

} // end namespace hmmwv9
<commit_msg>Adjust parameters of the HMMWV9 suspension.<commit_after>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Radu Serban, Justin Madsen
// =============================================================================
//
// Front and Rear HMMWV suspension subsystems (reduced double A-arm)
//
// =============================================================================

#include "assets/ChBoxShape.h"
#include "assets/ChColorAsset.h"

#include "HMMWV9_DoubleWishbone.h"

using namespace chrono;

namespace hmmwv9 {

// -----------------------------------------------------------------------------
// Static variables
// -----------------------------------------------------------------------------

static const double in2m = 0.0254;

const double     HMMWV9_DoubleWishboneFront::m_spindleMass = 1;
const double     HMMWV9_DoubleWishboneFront::m_uprightMass = 1;

const ChVector<> HMMWV9_DoubleWishboneFront::m_spindleInertia(1, 1, 1);
const ChVector<> HMMWV9_DoubleWishboneFront::m_uprightInertia(5, 5, 5);

const double     HMMWV9_DoubleWishboneFront::m_axleInertia = 0.4;

const ChVector<> HMMWV9_DoubleWishboneFront::m_uprightDims(0.1, 0.05, 0.1);

const double     HMMWV9_DoubleWishboneFront::m_springCoefficient  = 167062.0;
const double     HMMWV9_DoubleWishboneFront::m_dampingCoefficient = 22459.0;
const double     HMMWV9_DoubleWishboneFront::m_springRestLength   = 0.4062;

// -----------------------------------------------------------------------------

const double     HMMWV9_DoubleWishboneRear::m_spindleMass = 1;
const double     HMMWV9_DoubleWishboneRear::m_uprightMass = 1;

const ChVector<> HMMWV9_DoubleWishboneRear::m_spindleInertia(1, 1, 1);
const ChVector<> HMMWV9_DoubleWishboneRear::m_uprightInertia(5, 5, 5);

const double     HMMWV9_DoubleWishboneRear::m_axleInertia = 0.4;

const ChVector<> HMMWV9_DoubleWishboneRear::m_uprightDims(0.1, 0.05, 0.1);

const double     HMMWV9_DoubleWishboneRear::m_springCoefficient = 369149.0;
const double     HMMWV9_DoubleWishboneRear::m_dampingCoefficient = 35024.0;
const double     HMMWV9_DoubleWishboneRear::m_springRestLength = 0.4162;

// -----------------------------------------------------------------------------
// Constructors
// -----------------------------------------------------------------------------
HMMWV9_DoubleWishboneFront::HMMWV9_DoubleWishboneFront(const std::string& name,
                                                       ChSuspension::Side side,
                                                       bool               driven)
: ChDoubleWishboneReduced(name, side, driven)
{
}

HMMWV9_DoubleWishboneRear::HMMWV9_DoubleWishboneRear(const std::string& name,
                                                     ChSuspension::Side side,
                                                     bool               driven)
: ChDoubleWishboneReduced(name, side, driven)
{
}

// -----------------------------------------------------------------------------
// Implementations of the getLocation() virtual methods.
// -----------------------------------------------------------------------------

const ChVector<> HMMWV9_DoubleWishboneFront::getLocation(PointId which)
{
  switch (which) {
  case SPINDLE:  return in2m * ChVector<>(0, 0, 0);
  case UPRIGHT:  return in2m * ChVector<>(0, -4.0000, 0);
  case UCA_F:    return in2m * ChVector<>(0.3000, -18.2600, 10.6650);
  case UCA_B:    return in2m * ChVector<>(8.9700, -18.2600, 8.7250);
  case UCA_U:    return in2m * ChVector<>(0.5000, -7.6500, 9.5150);
  case LCA_F:    return in2m * ChVector<>(-10.3800, -23.7200, 1.0350);
  case LCA_B:    return in2m * ChVector<>(7.2000, -23.7200, 1.0350);
  case LCA_U:    return in2m * ChVector<>(-0.1900, -4.8500, -3.6150);
  case SHOCK_C:  return in2m * ChVector<>(-5.6900, -7.9500, 13.7550);
  case SHOCK_U:  return in2m * ChVector<>(-5.4200, -4.8500, -0.4850);
  case TIEROD_C: return in2m * ChVector<>(11.8000, -26.0100, 0);
  case TIEROD_U: return in2m * ChVector<>(5.3300, -3.5000, 0);
  default:       return ChVector<>(0, 0, 0);
  }
}

const ChVector<> HMMWV9_DoubleWishboneRear::getLocation(PointId which)
{
  switch (which) {
  case SPINDLE:  return in2m * ChVector<>(0, 0, 0);
  case UPRIGHT:  return in2m * ChVector<>(0, -4.0000, 0);
  case UCA_F:    return in2m * ChVector<>(-1.6700, -17.620, 9.9150);
  case UCA_B:    return in2m * ChVector<>(-12.3800, -17.6200, 9.9150);
  case UCA_U:    return in2m * ChVector<>(0, -7.6500, 10.3150);
  case LCA_F:    return in2m * ChVector<>(10.1900, -23.7200, 1.0350);
  case LCA_B:    return in2m * ChVector<>(-7.3900, -23.7200, 1.0350);
  case LCA_U:    return in2m * ChVector<>(0, -4.8500, -3.6150);
  case SHOCK_C:  return in2m * ChVector<>(5.4900, -7.6200, 13.7550);
  case SHOCK_U:  return in2m * ChVector<>(5.4900, -4.8500, -0.4750);
  case TIEROD_C: return in2m * ChVector<>(-11.3000, -19.4400, 0.6650);
  case TIEROD_U: return in2m * ChVector<>(-5.3000, -3.4900, 0.6650);
  default:       return ChVector<>(0, 0, 0);
  }
}

// -----------------------------------------------------------------------------
// Implementations of the OnInitializeUpright() virtual methods.
// Add simple visualization for the upright body.
// -----------------------------------------------------------------------------

void HMMWV9_DoubleWishboneFront::OnInitializeUpright()
{
  ChSharedPtr<ChBoxShape> box(new ChBoxShape);
  box->GetBoxGeometry().SetLenghts(m_uprightDims);
  m_upright->AddAsset(box);

  ChSharedPtr<ChColorAsset> col(new ChColorAsset);
  switch (m_side) {
  case RIGHT: col->SetColor(ChColor(0.6f, 0.2f, 0.2f)); break;
  case LEFT:  col->SetColor(ChColor(0.2f, 0.6f, 0.2f)); break;
  }
  m_upright->AddAsset(col);
}

void HMMWV9_DoubleWishboneRear::OnInitializeUpright()
{
  ChSharedPtr<ChBoxShape> box(new ChBoxShape);
  box->GetBoxGeometry().SetLenghts(m_uprightDims);
  m_upright->AddAsset(box);

  ChSharedPtr<ChColorAsset> col(new ChColorAsset);
  switch (m_side) {
  case RIGHT: col->SetColor(ChColor(0.6f, 0.4f, 0.4f)); break;
  case LEFT:  col->SetColor(ChColor(0.4f, 0.6f, 0.6f)); break;
  }
  m_upright->AddAsset(col);
}

} // end namespace hmmwv9
<|endoftext|>