<commit_before>

#include "engine/engine.h"
#include "server/zone/objects/tangible/tool/antidecay/AntiDecayKit.h"
#include "server/zone/Zone.h"
#include "server/zone/objects/tangible/Container.h"
#include "server/zone/objects/tangible/TangibleObject.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/packets/object/ObjectMenuResponse.h"

void AntiDecayKitImplementation::initializeTransientMembers() {

	ContainerImplementation::initializeTransientMembers();

	setLoggingName("AntiDecayKit");
}

void AntiDecayKitImplementation::fillObjectMenuResponse(ObjectMenuResponse* menuResponse, CreatureObject* player) {
	if(isASubChildOf(player) && getContainerObjectsSize() > 0) {
		menuResponse->addRadialMenuItem(68, 3, "@ui_radial:apply_anti_decay");
		menuResponse->addRadialMenuItem(69, 3, "@ui_radial:retrieve_items_from_anti_decay_kit");
	}
	TangibleObjectImplementation::fillObjectMenuResponse(menuResponse, player);
}

int AntiDecayKitImplementation::handleObjectMenuSelect(CreatureObject* player, byte selectedID) {
	if(isASubChildOf(player)) {
		switch(selectedID){
		case 68:
			doApplyAntiDecay(player);
			break;
		case 69:
			doRetrieveItem(player);
			break;
		}
	}

	return TangibleObjectImplementation::handleObjectMenuSelect(player, selectedID);
}

void AntiDecayKitImplementation::doApplyAntiDecay(CreatureObject* player)
{
	ManagedReference<SceneObject*> inventory = player->getSlottedObject("inventory");

	if(inventory == NULL || getContainerObjectsSize() < 1)
		return;

	if(getContainerObjectsSize() > 1){
		player->sendSystemMessage("@veteran_new:error_kit_has_too_many_items"); // This Anti Decay Kit can only function with one item inside. There are currently more than one item inside. Please remove the items from the Anti Decay Kit first by selecting the "Retrieve Item" menu option before continuing to use this Anti Decay Kit.
		return;
	}

	ManagedReference<TangibleObject*> tano = getContainerObject(0).castTo<TangibleObject*>();
	if(tano == NULL){
		player->sendSystemMessage("@veteran_new:failed_item_not_made_anti_decay"); // The Anti Decay Kit failed to apply Anti Decay to this item.
		return;
	}

	if(inventory->getContainerVolumeLimit() < (inventory->getCountableObjectsRecursive() + 1)){
		player->sendSystemMessage("@veteran_new:failed_item_cannot_be_placed_in_inventory"); // The Anti Decay Kit failed to place an item back into your inventory. Please make sure that your inventory has room for this item and try again.
		return;
	}

	tano->applyAntiDecayKit(player, _this.get());

	inventory->transferObject(tano, -1, false);
	tano->sendTo(player, true);

	player->sendSystemMessage("@veteran_new:successfully_used_anti_decay_kit"); // You have successfully used the Anti Decay Kit. The item you used this Anti Decay Kit on will no longer require insurance nor will decay from use.
}

void AntiDecayKitImplementation::doRetrieveItem(CreatureObject* player)
{
	ManagedReference<SceneObject*> inventory = player->getSlottedObject("inventory");

	if(inventory == NULL || getContainerObjectsSize() < 1)
		return;

	if(inventory->getContainerVolumeLimit() < (inventory->getCountableObjectsRecursive() + getCountableObjectsRecursive())){
		player->sendSystemMessage("@veteran_new:failed_item_cannot_be_placed_in_inventory"); // The Anti Decay Kit failed to place an item back into your inventory. Please make sure that your inventory has room for this item and try again.
		return;
	}

	for (int i = 0; i < getContainerObjectsSize(); ++i) {
		ManagedReference<SceneObject*> object = getContainerObject(i);
		if(object != NULL){
			inventory->transferObject(object, -1, false);
			object->sendTo(player, true);
		}
	}
}

int AntiDecayKitImplementation::canAddObject(SceneObject* object, int containmentType, String& errorDescription) {
	ManagedReference<SceneObject*> parent = getParentRecursively(SceneObjectType::PLAYERCREATURE).get();

	if (parent == NULL){
		errorDescription = "@veteran_new:error_kit_not_in_player_inventory"; // This Anti Decay Kit can only be used when it is in your inventory.
		return TransferErrorCode::MUSTBEINPLAYERINVENTORY;
	}

	if(getContainerObjectsSize() > 0){
		errorDescription = "@veteran_new:error_kit_already_has_item"; // This Anti Decay Kit already has an item inside. Please use the Anti Decay Kit or retrieve the item from the Anti Decay Kit by using the radial menu options on the Anti Decay Kit.
		return TransferErrorCode::CONTAINERFULL;
	}

	if (parent != object->getParentRecursively(SceneObjectType::PLAYERCREATURE).get()){
		errorDescription = "@veteran_new:error_item_not_in_player_inventory"; // You can only use the Anti Decay Kit on an item that is in your inventory.
		return TransferErrorCode::MUSTBEINPLAYERINVENTORY;
	}

	if(!(object->isWeaponObject() || object->isWearableObject())){
		errorDescription = "@veteran_new:error_item_not_valid_for_anti_decay"; // This item is not valid to be used by the Anti Decay Kit. Valid items are items that can be insured and weapons.
		return TransferErrorCode::INVALIDTYPE;
	}

	ManagedReference<TangibleObject*> tano = cast<TangibleObject*>(object);
	if(tano->hasAntiDecayKit()){
		errorDescription = "@veteran_new:error_item_is_already_anti_decay"; // The item you attempted to place in the Anti Decay Kit already has Anti Decay applied to it. Please use another item.
		return TransferErrorCode::INVALIDTYPE;
	}

	int containerObjects = parent->getSlottedObject("inventory")->getCountableObjectsRecursive();

	if (containerObjects >= parent->getSlottedObject("inventory")->getContainerVolumeLimit()) {
		errorDescription = "@error_message:inv_full"; // Your inventory is full.
		return TransferErrorCode::CONTAINERFULL;
	}

	return ContainerImplementation::canAddObject(object, containmentType, errorDescription);
}
<commit_msg>[fixed] prevented broken items being placed into anti-decay kits [fixed] anti-decay kits should now restore the item condition when applied - mantis #5698<commit_after>

#include "engine/engine.h"
#include "server/zone/objects/tangible/tool/antidecay/AntiDecayKit.h"
#include "server/zone/Zone.h"
#include "server/zone/objects/tangible/Container.h"
#include "server/zone/objects/tangible/TangibleObject.h"
#include "server/zone/objects/creature/CreatureObject.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/packets/object/ObjectMenuResponse.h"

void AntiDecayKitImplementation::initializeTransientMembers() {

	ContainerImplementation::initializeTransientMembers();

	setLoggingName("AntiDecayKit");
}

void AntiDecayKitImplementation::fillObjectMenuResponse(ObjectMenuResponse* menuResponse, CreatureObject* player) {
	if(isASubChildOf(player) && getContainerObjectsSize() > 0) {
		menuResponse->addRadialMenuItem(68, 3, "@ui_radial:apply_anti_decay");
		menuResponse->addRadialMenuItem(69, 3, "@ui_radial:retrieve_items_from_anti_decay_kit");
	}
	TangibleObjectImplementation::fillObjectMenuResponse(menuResponse, player);
}

int AntiDecayKitImplementation::handleObjectMenuSelect(CreatureObject* player, byte selectedID) {
	if(isASubChildOf(player)) {
		switch(selectedID){
		case 68:
			doApplyAntiDecay(player);
			break;
		case 69:
			doRetrieveItem(player);
			break;
		}
	}

	return TangibleObjectImplementation::handleObjectMenuSelect(player, selectedID);
}

void AntiDecayKitImplementation::doApplyAntiDecay(CreatureObject* player)
{
	ManagedReference<SceneObject*> inventory = player->getSlottedObject("inventory");

	if(inventory == NULL || getContainerObjectsSize() < 1)
		return;

	if(getContainerObjectsSize() > 1){
		player->sendSystemMessage("@veteran_new:error_kit_has_too_many_items"); // This Anti Decay Kit can only function with one item inside. There are currently more than one item inside. Please remove the items from the Anti Decay Kit first by selecting the "Retrieve Item" menu option before continuing to use this Anti Decay Kit.
		return;
	}

	ManagedReference<TangibleObject*> tano = getContainerObject(0).castTo<TangibleObject*>();
	if(tano == NULL){
		player->sendSystemMessage("@veteran_new:failed_item_not_made_anti_decay"); // The Anti Decay Kit failed to apply Anti Decay to this item.
		return;
	}

	if(inventory->getContainerVolumeLimit() < (inventory->getCountableObjectsRecursive() + 1)){
		player->sendSystemMessage("@veteran_new:failed_item_cannot_be_placed_in_inventory"); // The Anti Decay Kit failed to place an item back into your inventory. Please make sure that your inventory has room for this item and try again.
		return;
	}

	tano->setConditionDamage(0);
	tano->applyAntiDecayKit(player, _this.get());

	inventory->transferObject(tano, -1, false);
	tano->sendTo(player, true);

	player->sendSystemMessage("@veteran_new:successfully_used_anti_decay_kit"); // You have successfully used the Anti Decay Kit. The item you used this Anti Decay Kit on will no longer require insurance nor will decay from use.
}

void AntiDecayKitImplementation::doRetrieveItem(CreatureObject* player)
{
	ManagedReference<SceneObject*> inventory = player->getSlottedObject("inventory");

	if(inventory == NULL || getContainerObjectsSize() < 1)
		return;

	if(inventory->getContainerVolumeLimit() < (inventory->getCountableObjectsRecursive() + getCountableObjectsRecursive())){
		player->sendSystemMessage("@veteran_new:failed_item_cannot_be_placed_in_inventory"); // The Anti Decay Kit failed to place an item back into your inventory. Please make sure that your inventory has room for this item and try again.
		return;
	}

	for (int i = 0; i < getContainerObjectsSize(); ++i) {
		ManagedReference<SceneObject*> object = getContainerObject(i);
		if(object != NULL){
			inventory->transferObject(object, -1, false);
			object->sendTo(player, true);
		}
	}
}

int AntiDecayKitImplementation::canAddObject(SceneObject* object, int containmentType, String& errorDescription) {
	ManagedReference<SceneObject*> parent = getParentRecursively(SceneObjectType::PLAYERCREATURE).get();

	if (parent == NULL){
		errorDescription = "@veteran_new:error_kit_not_in_player_inventory"; // This Anti Decay Kit can only be used when it is in your inventory.
		return TransferErrorCode::MUSTBEINPLAYERINVENTORY;
	}

	if(getContainerObjectsSize() > 0){
		errorDescription = "@veteran_new:error_kit_already_has_item"; // This Anti Decay Kit already has an item inside. Please use the Anti Decay Kit or retrieve the item from the Anti Decay Kit by using the radial menu options on the Anti Decay Kit.
		return TransferErrorCode::CONTAINERFULL;
	}

	if (parent != object->getParentRecursively(SceneObjectType::PLAYERCREATURE).get()){
		errorDescription = "@veteran_new:error_item_not_in_player_inventory"; // You can only use the Anti Decay Kit on an item that is in your inventory.
		return TransferErrorCode::MUSTBEINPLAYERINVENTORY;
	}

	ManagedReference<TangibleObject*> tano = cast<TangibleObject*>(object);

	if(!(object->isWeaponObject() || object->isWearableObject()) || tano->isBroken()){
		errorDescription = "@veteran_new:error_item_not_valid_for_anti_decay"; // This item is not valid to be used by the Anti Decay Kit. Valid items are items that can be insured and weapons.
		return TransferErrorCode::INVALIDTYPE;
	}

	if(tano->hasAntiDecayKit()){
		errorDescription = "@veteran_new:error_item_is_already_anti_decay"; // The item you attempted to place in the Anti Decay Kit already has Anti Decay applied to it. Please use another item.
		return TransferErrorCode::INVALIDTYPE;
	}

	int containerObjects = parent->getSlottedObject("inventory")->getCountableObjectsRecursive();

	if (containerObjects >= parent->getSlottedObject("inventory")->getContainerVolumeLimit()) {
		errorDescription = "@error_message:inv_full"; // Your inventory is full.
		return TransferErrorCode::CONTAINERFULL;
	}

	return ContainerImplementation::canAddObject(object, containmentType, errorDescription);
}
<|endoftext|>


<commit_before>//===========================================
//  Lumina-Desktop source code
//  Copyright (c) 2016, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "imgDialog.h"
#include "ui_imgDialog.h"

#include <QMessageBox>

#include <LuminaOS.h>
#include <LuminaXDG.h>

#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

imgDialog::imgDialog(QWidget *parent) : QDialog(parent), ui(new Ui::imgDialog()){
  ui->setupUi(this); //load the designer form
  QString title = tr("Burn IMG to Device");
  if( getuid()==0){ title.append(" ("+tr("Admin Mode")+")"); }
  this->setWindowTitle(title);
  ui->frame_running->setVisible(false);
  ui->frame_setup->setVisible(true);
  ddProc = 0;
  unitdiv = 1;
  //Setup the signals/slots
  ui->tool_refresh->setIcon( LXDG::findIcon("view-refresh","drive-removable-media-usb-pendrive") );
  connect(ui->push_cancel, SIGNAL(clicked()), this, SLOT(cancel()) );
  connect(ui->push_start, SIGNAL(clicked()), this, SLOT(start_process()) );
  connect(ui->tool_refresh, SIGNAL(clicked()), this, SLOT(loadDeviceList()) );
  loadDeviceList(); //do the initial load of the available devices
  //Setup the possible transfer rate units
  ui->combo_rate_units->clear();
  ui->combo_rate_units->addItem(tr("Kilobyte(s)"), "k");
  ui->combo_rate_units->addItem(tr("Megabyte(s)"), "m");
  ui->combo_rate_units->addItem(tr("Gigabyte(s)"), "g");
  ui->combo_rate_units->setCurrentIndex(1); //MB
  //Setup the Process Timer
  procTimer = new QTimer(this);
    procTimer->setInterval(1000); //1 second updates
  connect(procTimer, SIGNAL(timeout()), this, SLOT(getProcStatus()) );
  //Determine which type of system this is for the process status signal
  BSD_signal = LOS::OSName().contains("BSD"); //assume everything else is Linux-like
}

imgDialog::~imgDialog(){

}

void imgDialog::loadIMG(QString filepath){
  ui->label_iso->setText(filepath.section("/",-1)); //only show the filename
  ui->label_iso->setWhatsThis(filepath); //save the full path for later
}

//============================
//  PRIVATE SLOTS
//============================
void imgDialog::start_process(){
  //Sanity Checks
  if( !QFile::exists(ui->combo_devices->currentData().toString()) ){ loadDeviceList(); return; } //USB device no longer available
  if(!QFile::exists(ui->label_iso->whatsThis()) ){ return; } //IMG file no longer available
  qDebug() << "Start Process...";
  //Read the size of the img file
  QString units = ui->combo_rate_units->currentData().toString();
  if(units=="k"){ unitdiv = 1024; }
  else if(units=="m"){ unitdiv = 1024*1024; }
  else if(units=="g"){ unitdiv = 1024*1024*1024; }
  qint64 bytes = QFileInfo(ui->label_iso->whatsThis()).size();
  //qDebug() << "IMG File size:" << bytes;
  //Set the progressBar maximum
  ui->progressBar->setRange(0, qRound(bytes/unitdiv) );
  ui->progressBar->setValue(0);
  ui->label_dev->setText( ui->combo_devices->currentText() );
  ui->label_time->setText("0:00");
  ui->frame_running->setVisible(true);
  ui->frame_setup->setVisible(false);
  //qDebug() << "Blocks:" << ui->progressBar->maximum();
  //Initialize the process
  if(ddProc==0){
    ddProc = new QProcess(this);
    connect(ddProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(procFinished()) );
    connect(ddProc, SIGNAL(readyRead()), this, SLOT(procInfoAvailable()) );
    ddProc->setProcessChannelMode(QProcess::MergedChannels);
  }
  //Generate the command
  QString prog; QStringList args;
  //if( ::getuid()!=0){ prog = "qsudo";  args<<"dd"; }
  //else{
    prog = "dd";
  //}
   args << "if="+ui->label_iso->whatsThis();
   args << "of="+ui->combo_devices->currentData().toString();
   args << "bs="+QString::number(ui->spin_rate_num->value())+units;
   if(ui->check_sync->isChecked()){ args << "conv=sync"; }
  //Start the process
  startTime = QDateTime::currentDateTime();
  ddProc->start(prog, args);
  //Start the timer to watch for updates
  procTimer->start();
  ui->push_start->setEnabled(false);
}

void imgDialog::cancel(){
  if(ddProc==0 || ddProc->state()==QProcess::NotRunning){
    this->close();
  }else{
    //Prompt if the transfer should be cancelled
    if(QMessageBox::Yes == QMessageBox::question(this, tr("Cancel Image Burn?"), tr("Do you wish to stop the current IMG burn process?")+"\n\n"+tr("Warning: This will leave the USB device in an inconsistent state")) ){
      ddProc->kill();
    }
  }
}

void imgDialog::loadDeviceList(){
  ui->combo_devices->clear();
  //Probe the system for USB devices
  QDir devDir("/dev");
  QString filter = (BSD_signal) ? "da*" : "sd*";
  QStringList usb = devDir.entryList(QStringList() << filter, QDir::System, QDir::Name);
  //Filter out any devices which are currently mounted/used

  //Create the list
  for(int i=0; i<usb.length(); i++){
    ui->combo_devices->addItem(usb[i], devDir.absoluteFilePath(usb[i]));
  }
}

void imgDialog::getProcStatus(){
  if(ddProc==0 || ddProc->state()!=QProcess::Running ){ return; }
  QStringList pidlist = LUtils::getCmdOutput("pgrep -S -f \"dd if="+ui->label_iso->whatsThis()+"\"");
  if(pidlist.isEmpty()){ return; }
  int pid = pidlist.first().simplified().toInt(); //just use the first pid - the pgrep should be detailed enough to only match one
  //qDebug() << "Sending signal to show status on PID:" << pid;
#ifndef __Linux__
  ::kill(pid, SIGINFO); //On BSD systems, the INFO signal is used to poke dd for status updates
#else
  //LINUX systems do not even have a SIGINFO defined - need to block this off with defines...
  ::kill(pid, SIGUSR1);  //On linux systems, the USR1 signal is used to poke dd for status updates
#endif
  //Now update the elapsed time on the UI
    int elapsed = startTime.secsTo( QDateTime::currentDateTime() );
    int min = elapsed/60;
    int secs = elapsed%60;
    ui->label_time->setText( QString::number(min)+":"+ (secs < 10 ? "0" : "")+QString::number(secs) );
}

void imgDialog::procInfoAvailable(){
  lastmsg = ddProc->readAll();
  if(lastmsg.endsWith("\n")){ lastmsg.chop(1); }
  //qDebug() << "Got Process Info:" << lastmsg;
  //Now look for the " bytes transferred" line
  QStringList records = lastmsg.split("\n").filter(" bytes transferred ");
  if(!records.isEmpty()){
    //Update the progress bar
    //qDebug() << "Got status update:" << records.last();
    ui->progressBar->setValue( qRound(records.last().section(" bytes",0,0).toDouble()/unitdiv) );
  }
}

void imgDialog::procFinished(){
  qDebug() << "Process Finished:" << ddProc->exitCode();
  procTimer->stop();
  ui->frame_running->setVisible(false);
  ui->frame_setup->setVisible(true);
  if(ddProc->exitStatus()==QProcess::NormalExit){
    if(ddProc->exitCode() !=0 ){
      if(lastmsg.contains("permission denied", Qt::CaseInsensitive) && LUtils::isValidBinary("qsudo") ){
        if(QMessageBox::Yes == QMessageBox::question(this, tr("Administrator Permissions Needed"), tr("This operation requires administrator priviledges.")+"\n\n"+tr("Would you like to enable these priviledges?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) ){
          QProcess::startDetached("qsudo", QStringList() << "lumina-archiver" << "--burn-img" << ui->label_iso->whatsThis());
          exit(0);
        }
      }else{
        QMessageBox::warning(this, tr("ERROR"), tr("The process could not be completed:")+"\n\n"+lastmsg);
      }
    }else{
      QMessageBox::information(this, tr("SUCCESS"), tr("The image was successfully burned to the USB device") );
      this->close();
    }
  }
}
<commit_msg>Fix the __linux__ ifdef. Needed to be all lowercase.<commit_after>//===========================================
//  Lumina-Desktop source code
//  Copyright (c) 2016, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "imgDialog.h"
#include "ui_imgDialog.h"

#include <QMessageBox>

#include <LuminaOS.h>
#include <LuminaXDG.h>

#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

imgDialog::imgDialog(QWidget *parent) : QDialog(parent), ui(new Ui::imgDialog()){
  ui->setupUi(this); //load the designer form
  QString title = tr("Burn IMG to Device");
  if( getuid()==0){ title.append(" ("+tr("Admin Mode")+")"); }
  this->setWindowTitle(title);
  ui->frame_running->setVisible(false);
  ui->frame_setup->setVisible(true);
  ddProc = 0;
  unitdiv = 1;
  //Setup the signals/slots
  ui->tool_refresh->setIcon( LXDG::findIcon("view-refresh","drive-removable-media-usb-pendrive") );
  connect(ui->push_cancel, SIGNAL(clicked()), this, SLOT(cancel()) );
  connect(ui->push_start, SIGNAL(clicked()), this, SLOT(start_process()) );
  connect(ui->tool_refresh, SIGNAL(clicked()), this, SLOT(loadDeviceList()) );
  loadDeviceList(); //do the initial load of the available devices
  //Setup the possible transfer rate units
  ui->combo_rate_units->clear();
  ui->combo_rate_units->addItem(tr("Kilobyte(s)"), "k");
  ui->combo_rate_units->addItem(tr("Megabyte(s)"), "m");
  ui->combo_rate_units->addItem(tr("Gigabyte(s)"), "g");
  ui->combo_rate_units->setCurrentIndex(1); //MB
  //Setup the Process Timer
  procTimer = new QTimer(this);
    procTimer->setInterval(1000); //1 second updates
  connect(procTimer, SIGNAL(timeout()), this, SLOT(getProcStatus()) );
  //Determine which type of system this is for the process status signal
  BSD_signal = LOS::OSName().contains("BSD"); //assume everything else is Linux-like
}

imgDialog::~imgDialog(){

}

void imgDialog::loadIMG(QString filepath){
  ui->label_iso->setText(filepath.section("/",-1)); //only show the filename
  ui->label_iso->setWhatsThis(filepath); //save the full path for later
}

//============================
//  PRIVATE SLOTS
//============================
void imgDialog::start_process(){
  //Sanity Checks
  if( !QFile::exists(ui->combo_devices->currentData().toString()) ){ loadDeviceList(); return; } //USB device no longer available
  if(!QFile::exists(ui->label_iso->whatsThis()) ){ return; } //IMG file no longer available
  qDebug() << "Start Process...";
  //Read the size of the img file
  QString units = ui->combo_rate_units->currentData().toString();
  if(units=="k"){ unitdiv = 1024; }
  else if(units=="m"){ unitdiv = 1024*1024; }
  else if(units=="g"){ unitdiv = 1024*1024*1024; }
  qint64 bytes = QFileInfo(ui->label_iso->whatsThis()).size();
  //qDebug() << "IMG File size:" << bytes;
  //Set the progressBar maximum
  ui->progressBar->setRange(0, qRound(bytes/unitdiv) );
  ui->progressBar->setValue(0);
  ui->label_dev->setText( ui->combo_devices->currentText() );
  ui->label_time->setText("0:00");
  ui->frame_running->setVisible(true);
  ui->frame_setup->setVisible(false);
  //qDebug() << "Blocks:" << ui->progressBar->maximum();
  //Initialize the process
  if(ddProc==0){
    ddProc = new QProcess(this);
    connect(ddProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(procFinished()) );
    connect(ddProc, SIGNAL(readyRead()), this, SLOT(procInfoAvailable()) );
    ddProc->setProcessChannelMode(QProcess::MergedChannels);
  }
  //Generate the command
  QString prog; QStringList args;
  //if( ::getuid()!=0){ prog = "qsudo";  args<<"dd"; }
  //else{
    prog = "dd";
  //}
   args << "if="+ui->label_iso->whatsThis();
   args << "of="+ui->combo_devices->currentData().toString();
   args << "bs="+QString::number(ui->spin_rate_num->value())+units;
   if(ui->check_sync->isChecked()){ args << "conv=sync"; }
  //Start the process
  startTime = QDateTime::currentDateTime();
  ddProc->start(prog, args);
  //Start the timer to watch for updates
  procTimer->start();
  ui->push_start->setEnabled(false);
}

void imgDialog::cancel(){
  if(ddProc==0 || ddProc->state()==QProcess::NotRunning){
    this->close();
  }else{
    //Prompt if the transfer should be cancelled
    if(QMessageBox::Yes == QMessageBox::question(this, tr("Cancel Image Burn?"), tr("Do you wish to stop the current IMG burn process?")+"\n\n"+tr("Warning: This will leave the USB device in an inconsistent state")) ){
      ddProc->kill();
    }
  }
}

void imgDialog::loadDeviceList(){
  ui->combo_devices->clear();
  //Probe the system for USB devices
  QDir devDir("/dev");
  QString filter = (BSD_signal) ? "da*" : "sd*";
  QStringList usb = devDir.entryList(QStringList() << filter, QDir::System, QDir::Name);
  //Filter out any devices which are currently mounted/used

  //Create the list
  for(int i=0; i<usb.length(); i++){
    ui->combo_devices->addItem(usb[i], devDir.absoluteFilePath(usb[i]));
  }
}

void imgDialog::getProcStatus(){
  if(ddProc==0 || ddProc->state()!=QProcess::Running ){ return; }
  QStringList pidlist = LUtils::getCmdOutput("pgrep -S -f \"dd if="+ui->label_iso->whatsThis()+"\"");
  if(pidlist.isEmpty()){ return; }
  int pid = pidlist.first().simplified().toInt(); //just use the first pid - the pgrep should be detailed enough to only match one
  //qDebug() << "Sending signal to show status on PID:" << pid;
#ifndef __linux__
  ::kill(pid, SIGINFO); //On BSD systems, the INFO signal is used to poke dd for status updates
#else
  //LINUX systems do not even have a SIGINFO defined - need to block this off with defines...
  ::kill(pid, SIGUSR1);  //On linux systems, the USR1 signal is used to poke dd for status updates
#endif
  //Now update the elapsed time on the UI
    int elapsed = startTime.secsTo( QDateTime::currentDateTime() );
    int min = elapsed/60;
    int secs = elapsed%60;
    ui->label_time->setText( QString::number(min)+":"+ (secs < 10 ? "0" : "")+QString::number(secs) );
}

void imgDialog::procInfoAvailable(){
  lastmsg = ddProc->readAll();
  if(lastmsg.endsWith("\n")){ lastmsg.chop(1); }
  //qDebug() << "Got Process Info:" << lastmsg;
  //Now look for the " bytes transferred" line
  QStringList records = lastmsg.split("\n").filter(" bytes transferred ");
  if(!records.isEmpty()){
    //Update the progress bar
    //qDebug() << "Got status update:" << records.last();
    ui->progressBar->setValue( qRound(records.last().section(" bytes",0,0).toDouble()/unitdiv) );
  }
}

void imgDialog::procFinished(){
  qDebug() << "Process Finished:" << ddProc->exitCode();
  procTimer->stop();
  ui->frame_running->setVisible(false);
  ui->frame_setup->setVisible(true);
  if(ddProc->exitStatus()==QProcess::NormalExit){
    if(ddProc->exitCode() !=0 ){
      if(lastmsg.contains("permission denied", Qt::CaseInsensitive) && LUtils::isValidBinary("qsudo") ){
        if(QMessageBox::Yes == QMessageBox::question(this, tr("Administrator Permissions Needed"), tr("This operation requires administrator priviledges.")+"\n\n"+tr("Would you like to enable these priviledges?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) ){
          QProcess::startDetached("qsudo", QStringList() << "lumina-archiver" << "--burn-img" << ui->label_iso->whatsThis());
          exit(0);
        }
      }else{
        QMessageBox::warning(this, tr("ERROR"), tr("The process could not be completed:")+"\n\n"+lastmsg);
      }
    }else{
      QMessageBox::information(this, tr("SUCCESS"), tr("The image was successfully burned to the USB device") );
      this->close();
    }
  }
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>

#define N 10	//切り分けパターンの数
#define L 10	//もともとの金属棒の長さ
void setArrays(void);
void freeArrays(void);
void solve(void);
void backtrack(int,int,int);
void print_result(void);

struct InputSet{
	int length;
	int price;
};

struct InputSet s[N+1] =
	 {{0,0},{1,1},{2,5},{3,8},{4,9},{5,10},{6,17},{7,17},{8,20},{9,24},{10,30}};
struct InputSet *ms = NULL;		//個数制限無しのナップサック問題用に，修正した入力をここに保存
int **c = NULL;					//c[i][l]は長さlの金属棒についてi番目の切り分けパターンまで考慮したときの価格の最大値
int result[N+1] = {0};
int length = L;
int newsize;

int main(int argc,char *argv[])
{
	if(argc == 2)length = atoi(argv[1]);
	while(length > 0){
		for(int i = 0;i <= length+1;i++)printf("____ ");
		printf("\nL = %2d : result \n",length);
		setArrays();
		solve();
		print_result();
		freeArrays();
		length--;
	}
	return 0;
}

void setArrays()
{
	newsize = 0;
	for(int i = 1;i <= N;i++)newsize += (int)(length/s[i].length);
	ms = (struct InputSet *)malloc(sizeof(struct InputSet) * (newsize + 1));
	printf("NEWSIZE = %3d\n",newsize);
	ms[0] = {0,0};

	int currentIndex = 1;
	for(int i = 1;i <= N;i++){
		int count = (int)(length / s[i].length);
		for(int x = 0;x < count;x++)ms[x+currentIndex] = {s[i].length,s[i].price};
		currentIndex += count;
	}
	printf("MODIFIED INPUT IS \n[ ");
	for(int i = 0;i <= newsize;i++){
		printf("{%2d,%2d} ",ms[i].length,ms[i].price);
		if(i % length == 0)printf("\n");
	}
	printf("]\n\n");

	c = (int **)malloc(sizeof(int *) * (newsize + 1));
	for(int i = 0;i <= newsize;i++){
		c[i] = (int *)malloc(sizeof(int) * (length + 1));
	}
}

void freeArrays()
{
	free(ms);
	for(int i = 0;i <= newsize;i++){
		free(c[i]);
	}
	free(c);
}

void solve()
{
	for(int i = 0;i <= newsize;i++)c[i][0] = 0;
	for(int l = 0;l <= length;l++)c[0][l] = 0;
	for(int x=0;x<=length+1;x++)printf("**** ");printf("\n");

	for(int i = 1;i <= newsize;i++){
		for(int l = 1;l <= length;l++){
			if(ms[i].length <= l){
				if(ms[i].price + c[i-1][l-ms[i].length] > c[i-1][l]){
					c[i][l] = ms[i].price + c[i-1][l-ms[i].length];
				}else{
					c[i][l] = c[i-1][l];
				}
			}else{
				c[i][l] = c[i-1][l];
			}
		}
	}
}

void backtrack(int i, int j, int index)
{
	if(j < 1 || i < 1)return;
	while(c[i--][j] == c[i][j]);
	result[index++] = ms[++i].length;
	backtrack(i,j-ms[i].length,index);
}

void print_result()
{
	for(int i = -1;i <= newsize;i++){
		for(int l = -1;l <= length;l++){
			if(i < 0 && l < 0){
				printf("     ");
				continue;
			}else if(l < 0 ){
				printf("[%2d]  ",i);
				continue;
			}else if(i < 0){
				printf("[%2d] ",l);
				continue;
			}
			printf("%2d   ",c[i][l]);
		}
		printf("\n");
	}
	printf("\n");

	printf("MAXIMUM PRICE IS [ %2d ]\n\n",c[newsize][length]);

	backtrack(newsize,length,0);
	printf("Cutting List = [ ");
	for(int i = 0;i <= N;i++){
		if(result[i]) printf("%2d,",result[i]);
	}
	printf("]\n\n");
	for(int i = 0;i <= N;i++){
		result[i] = 0;
	}
}<commit_msg>few changes<commit_after>#include <stdio.h>
#include <stdlib.h>

#define N 10	//切り分けパターンの数
#define L 10	//もともとの金属棒の長さ

void setArrays(void);
void freeArrays(void);
void solve(void);
void backtrack(int,int,int);
void print_result(void);

struct InputSet{
	int length;
	int price;
};

struct InputSet s[N+1] =
	 {{0,0},{1,1},{2,5},{3,8},{4,9},{5,10},{6,17},{7,17},{8,20},{9,24},{10,30}};
struct InputSet *ms = NULL;	//個数制限無しのナップサック問題用に，修正した入力をここに保存
int **c = NULL;	//c[i][l]は長さlの金属棒についてi番目の切り分けパターンまで考慮したときの価格の最大値
int result[N+1] = {0};
int length = L;
int newsize;

int main(int argc,char *argv[])
{
	if(argc == 2)length = atoi(argv[1]);
	while(length > 0){
		for(int i = 0;i <= length+1;i++)printf("____ ");
		printf("\nL = %2d : result \n",length);
		setArrays();
		solve();
		print_result();
		freeArrays();
		length--;
	}
	return 0;
}

void setArrays()
{
	newsize = 0;
	for(int i = 1;i <= N;i++)newsize += (int)(length/s[i].length);
	ms = (struct InputSet *)malloc(sizeof(struct InputSet) * (newsize + 1));
	printf("NEWSIZE = %3d\n",newsize);
	ms[0] = {0,0};

	int currentIndex = 1;
	for(int i = 1;i <= N;i++){
		int count = (int)(length / s[i].length);
		for(int x = 0;x < count;x++)ms[x+currentIndex] = {s[i].length,s[i].price};
		currentIndex += count;
	}
	printf("MODIFIED INPUT IS \n[ ");
	for(int i = 0;i <= newsize;i++){
		printf("{%2d,%2d} ",ms[i].length,ms[i].price);
		if(i % length == 0)printf("\n");
	}
	printf("]\n\n");

	c = (int **)malloc(sizeof(int *) * (newsize + 1));
	for(int i = 0;i <= newsize;i++){
		c[i] = (int *)malloc(sizeof(int) * (length + 1));
	}
}

void freeArrays()
{
	free(ms);
	for(int i = 0;i <= newsize;i++){
		free(c[i]);
	}
	free(c);
}

void solve()
{
	for(int i = 0;i <= newsize;i++)c[i][0] = 0;
	for(int l = 0;l <= length;l++)c[0][l] = 0;
	for(int x=0;x<=length+1;x++)printf("**** ");printf("\n");

	for(int i = 1;i <= newsize;i++){
		for(int l = 1;l <= length;l++){
			if(ms[i].length <= l){
				if(ms[i].price + c[i-1][l-ms[i].length] > c[i-1][l]){
					c[i][l] = ms[i].price + c[i-1][l-ms[i].length];
				}else{
					c[i][l] = c[i-1][l];
				}
			}else{
				c[i][l] = c[i-1][l];
			}
		}
	}
}

void backtrack(int i, int j, int index)
{
	if(j < 1 || i < 1)return;
	while(c[i--][j] == c[i][j]);
	result[index++] = ms[++i].length;
	backtrack(i,j-ms[i].length,index);
}

void print_result()
{
	for(int i = -1;i <= newsize;i++){
		for(int l = -1;l <= length;l++){
			if(i < 0 && l < 0){
				printf("     ");
				continue;
			}else if(l < 0 ){
				printf("[%2d]  ",i);
				continue;
			}else if(i < 0){
				printf("[%2d] ",l);
				continue;
			}
			printf("%2d   ",c[i][l]);
		}
		printf("\n");
	}
	printf("\n");

	printf("MAXIMUM PRICE IS [ %2d ]\n\n",c[newsize][length]);

	backtrack(newsize,length,0);
	printf("Cutting List = [ ");
	for(int i = 0;i <= N;i++){
		if(result[i]) printf("%2d,",result[i]);
	}
	printf("]\n\n");
	for(int i = 0;i <= N;i++){
		result[i] = 0;
	}
}<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.2  1999/12/07 23:11:01  roddey
 * Add in some new tests for transcoders and update the URL tests
 * a bit.
 *
 * Revision 1.1.1.1  1999/11/09 01:02:03  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:42:28  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include "CoreTests.hpp"
#include <util/Janitor.hpp>
#include <util/PlatformUtils.hpp>
#include <util/TransService.hpp>

// ---------------------------------------------------------------------------
//  Local, static data
// ---------------------------------------------------------------------------
static const char* const   testStr1 = "The test string";
static const XMLCh         testStr2[] =
{
        chLatin_T, chLatin_h, chLatin_e, chSpace, chLatin_t, chLatin_e
    ,   chLatin_s, chLatin_t, chSpace, chLatin_s, chLatin_t, chLatin_r
    ,   chLatin_i, chLatin_n, chLatin_g, chNull
};
static const XMLCh         testStr3[] =
{
        chLatin_T, chLatin_H, chLatin_E, chSpace, chLatin_T, chLatin_E
    ,   chLatin_S, chLatin_T, chSpace, chLatin_S, chLatin_T, chLatin_R
    ,   chLatin_I, chLatin_N, chLatin_G, chNull
};

// ---------------------------------------------------------------------------
//  Local test methods
// ---------------------------------------------------------------------------
static bool basicTransServiceTests()
{
    const XMLCh* pszTmp;

    // Test the case insensitive comparison
    if (XMLPlatformUtils::fgTransService->compareIString(testStr2, testStr3))
    {
        outStrm << "Case sensitive compare failed" << EndLn;
        return false;
    }

    //
    //  Test the case sensitive leading substring compare. Loop through and
    //  test it for each length possible. This will probe boundary conditions
    //  hopefully.
    //
    const unsigned int testLen = XMLString::stringLen(testStr2);
    for (unsigned int testInd = 0; testInd < testLen; testInd++)
    {
        if (XMLPlatformUtils::fgTransService->compareNIString(testStr2, testStr3, testInd))
        {
            outStrm << "Case sensitive leading compare failed" << EndLn;
            return false;
        }
    }

    //
    //  Check the isSpace API. This is the only generalized character type
    //  check that we need (all others are XML specific and done via XML's
    //  character type tables.)
    //
    static const XMLCh testWS[] = { chSpace, chHTab, chLF, chCR, chNull };
    pszTmp = testWS;
    while (*pszTmp)
    {
        if (!XMLPlatformUtils::fgTransService->isSpace(*pszTmp))
        {
            outStrm << "isSpace() failed on code point: "
                    << (unsigned int)*pszTmp << EndLn;
            return false;
        }
        pszTmp++;
    }

    static const XMLCh testNWS[] = { chDigit_0, chLatin_A, chPound, chNull };
    pszTmp = testNWS;
    while (*pszTmp)
    {
        if (XMLPlatformUtils::fgTransService->isSpace(*pszTmp))
        {
            outStrm << "isSpace() failed on code point: "
                    << (unsigned int)*pszTmp << EndLn;
            return false;
        }
        pszTmp++;
    }

    return true;
}

static bool basicTranscoderTests()
{
    //
    //  Ok, lets test out the very basic semantics of transcoders. This
    //  will test the particular transcoder system installed. First of all
    //  lets get a default transcoder.
    //
    XMLTranscoder* testX = XMLPlatformUtils::fgTransService->makeNewDefTranscoder();
    Janitor<XMLTranscoder> janXCoder(testX);

    // Ask it to do a basic transcoding of a string round trip
    {
        // Do the first pass and compare against the expected result
        XMLCh* firstPass = testX->transcode(testStr1);
        if (XMLString::compareString(firstPass, testStr2))
        {
            outStrm << "Xcode from native to Unicode failed"
                    << EndLn;
            return false;
        }

        // Now transcode that back to native again
        char* secondPass = testX->transcode(firstPass);
        if (XMLString::compareString(secondPass, testStr1))
        {
            outStrm << "Xcode from Unicode to native failed"
                    << EndLn;
            return false;
        }
    }

    // Check the methods that calculate required storage
    {
        if (testX->calcRequiredSize(testStr1) != XMLString::stringLen(testStr2))
        {
            outStrm << "Calculated size to xcode char string was wrong"
                    << EndLn;
            return false;
        }

        if (testX->calcRequiredSize(testStr2) != XMLString::stringLen(testStr1))
        {
            outStrm << "Calculated size to xcode Unicode string was wrong"
                    << EndLn;
            return false;
        }
    }

    return true;
}

// ---------------------------------------------------------------------------
//  Test entry point
// ---------------------------------------------------------------------------
bool testTranscoders()
{
    outStrm << "----------------------------------\n"
            << "Testing transcoder classes\n"
            << "----------------------------------" << EndLn;

    bool retVal = true;

    try
    {
        // Call other local methods to do specific tests
        outStrm << "Testing basic trans service functions" << EndLn;
        if (!basicTransServiceTests())
        {
            outStrm << "TransService basic tests failed" << EndLn;
            retVal = false;
        }
         else
        {
            outStrm << "TransService basic tests passed" << EndLn;
        }
        outStrm << EndLn;

        outStrm << "Testing basic transcoder functions" << EndLn;
        if (!basicTranscoderTests())
        {
            outStrm << "Transcoder basic tests failed" << EndLn;
            retVal = false;
        }
         else
        {
            outStrm << "Transcoder basic tests passed" << EndLn;
        }
        outStrm << EndLn;
    }

    catch(const XMLException& toCatch)
    {
        outStrm << "  ERROR: Unexpected exception!\n   Msg: "
                << toCatch.getMessage() << EndLn;
        return false;
    }
    return retVal;
}
<commit_msg>Added new tests and updated tests for new split transcoder architecture.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.3  1999/12/15 19:59:12  roddey
 * Added new tests and updated tests for new split transcoder architecture.
 *
 * Revision 1.2  1999/12/07 23:11:01  roddey
 * Add in some new tests for transcoders and update the URL tests
 * a bit.
 *
 * Revision 1.1.1.1  1999/11/09 01:02:03  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:42:28  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include "CoreTests.hpp"
#include <util/XMLASCIITranscoder.hpp>
#include <util/Janitor.hpp>
#include <util/PlatformUtils.hpp>
#include <util/TransService.hpp>

// ---------------------------------------------------------------------------
//  Local test methods
// ---------------------------------------------------------------------------
static bool testOneTranscoder(          XMLTranscoder&  toTest
                                , const char* const     nativeStr
                                , const unsigned int    nativeBytes
                                , const XMLCh* const    unicodeStr
                                , const unsigned int    unicodeBytes)
{
    // Ask it to do a basic transcoding of a string round trip
    {
        // Do the first pass and compare against the expected result
        XMLCh* firstPass = toTest.transcode(nativeStr);
        if (XMLString::compareString(firstPass, unicodeStr))
        {
            outStrm << "Xcode from native to Unicode failed"
                    << EndLn;
            return false;
        }

        // Now transcode that back to native again
        char* secondPass = toTest.transcode(firstPass);
        if (XMLString::compareString(secondPass, nativeStr))
        {
            outStrm << "Xcode from Unicode to native failed"
                    << EndLn;
            return false;
        }
    }

    // Check the methods that calculate required storage
    {
        if (toTest.calcRequiredSize(nativeStr) != unicodeBytes)
        {
            outStrm << "Calculated size to xcode char string was wrong"
                    << EndLn;
            return false;
        }

        if (toTest.calcRequiredSize(unicodeStr) != nativeBytes)
        {
            outStrm << "Calculated size to xcode Unicode string was wrong"
                    << EndLn;
            return false;
        }
    }

    return true;
}

//
//  This method tests the basic services of the currently loaded transcoding
//  service. This is the stuff that is independent of the source XML
//  encoding, i.e. it just works mostly on XMLCh content.
//
static bool basicTransServiceTests()
{
    static const char* const   testStr1 = "The test string";
    static const XMLCh         testStr2[] =
    {
            chLatin_T, chLatin_h, chLatin_e, chSpace, chLatin_t, chLatin_e
        ,   chLatin_s, chLatin_t, chSpace, chLatin_s, chLatin_t, chLatin_r
        ,   chLatin_i, chLatin_n, chLatin_g, chNull
    };
    static const XMLCh         testStr3[] =
    {
            chLatin_T, chLatin_H, chLatin_E, chSpace, chLatin_T, chLatin_E
        ,   chLatin_S, chLatin_T, chSpace, chLatin_S, chLatin_T, chLatin_R
        ,   chLatin_I, chLatin_N, chLatin_G, chNull
    };
    static const XMLCh testWS[] = { chSpace, chHTab, chLF, chCR, chNull };
    static const XMLCh testNWS[] = { chDigit_0, chLatin_A, chPound, chNull };

    const XMLCh* pszTmp;

    // Test the case insensitive comparison
    if (XMLPlatformUtils::fgTransService->compareIString(testStr2, testStr3))
    {
        outStrm << "Case sensitive compare failed" << EndLn;
        return false;
    }

    //
    //  Test the case sensitive leading substring compare. Loop through and
    //  test it for each length possible. This will probe boundary conditions
    //  hopefully.
    //
    const unsigned int testLen = XMLString::stringLen(testStr2);
    for (unsigned int testInd = 0; testInd < testLen; testInd++)
    {
        if (XMLPlatformUtils::fgTransService->compareNIString(testStr2, testStr3, testInd))
        {
            outStrm << "Case sensitive leading compare failed" << EndLn;
            return false;
        }
    }

    //  Check the isSpace API. This is the only generalized character type
    //  check that we need (all others are XML specific and done via XML's
    //  character type tables.)
    //
    pszTmp = testWS;
    while (*pszTmp)
    {
        if (!XMLPlatformUtils::fgTransService->isSpace(*pszTmp))
        {
            outStrm << "isSpace() failed on code point: "
                    << (unsigned int)*pszTmp << EndLn;
            return false;
        }
        pszTmp++;
    }

    pszTmp = testNWS;
    while (*pszTmp)
    {
        if (XMLPlatformUtils::fgTransService->isSpace(*pszTmp))
        {
            outStrm << "isSpace() failed on code point: "
                    << (unsigned int)*pszTmp << EndLn;
            return false;
        }
        pszTmp++;
    }

    return true;
}

//
//  This tests some of the individual transcoders. These transcode between
//  some native encoding and the internal Unicode format.
//
//  We test the transcoders for the intrinsic transcoders here, the ones
//  that are implemented directly in the parser system. We can't test any
//  others because there is no guarantee that any others are supported by
//  any particular plugged in transcoding service.
//
static bool basicTranscoderTests()
{
    static const XMLCh         testStr2[] =
    {
            chLatin_T, chLatin_h, chLatin_e, chSpace, chLatin_t, chLatin_e
        ,   chLatin_s, chLatin_t, chSpace, chLatin_s, chLatin_t, chLatin_r
        ,   chLatin_i, chLatin_n, chLatin_g, chNull
    };
    bool result;

    // Test the intrinsic ASCII transcoder
    {
        const char* const testStr1 = "The test string";
        XMLASCIITranscoder toTest;
        result = testOneTranscoder
        (
            toTest
            , testStr1
            , XMLString::stringLen(testStr1)
            , testStr2
            , XMLString::stringLen(testStr2)
        );

        if (!result)
            return false;
    }

    // Test the intrinsic UTF-16 transcoder, in little endian
    {
    }

    // Test the intrinsic UTF-16 transcoder, in big endian
    {
    }

    return true;
}

// ---------------------------------------------------------------------------
//  Test entry point
// ---------------------------------------------------------------------------
bool testTranscoders()
{
    outStrm << "----------------------------------\n"
            << "Testing transcoder classes\n"
            << "----------------------------------" << EndLn;

    bool retVal = true;

    try
    {
        // Call other local methods to do specific tests
        outStrm << "Testing basic trans service functions" << EndLn;
        if (!basicTransServiceTests())
        {
            outStrm << "TransService basic tests failed" << EndLn;
            retVal = false;
        }
         else
        {
            outStrm << "TransService basic tests passed" << EndLn;
        }
        outStrm << EndLn;

        outStrm << "Testing basic transcoder functions" << EndLn;
        if (!basicTranscoderTests())
        {
            outStrm << "Transcoder basic tests failed" << EndLn;
            retVal = false;
        }
         else
        {
            outStrm << "Transcoder basic tests passed" << EndLn;
        }
        outStrm << EndLn;
    }

    catch(const XMLException& toCatch)
    {
        outStrm << "  ERROR: Unexpected exception!\n   Msg: "
                << toCatch.getMessage() << EndLn;
        return false;
    }
    return retVal;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#include "coordinate_calculation.hpp"

#include "../util/mercator.hpp"
#include "../util/string_util.hpp"

#include <boost/assert.hpp>

#include <osrm/coordinate.hpp>

#include <cmath>

#include <limits>

namespace
{
constexpr static const float RAD = 0.017453292519943295769236907684886f;
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
constexpr static const float earth_radius = 6372797.560856f;
}

double coordinate_calculation::great_circle_distance(const int lat1,
                                                     const int lon1,
                                                     const int lat2,
                                                     const int lon2)
{
    BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
    const double lt1 = lat1 / COORDINATE_PRECISION;
    const double ln1 = lon1 / COORDINATE_PRECISION;
    const double lt2 = lat2 / COORDINATE_PRECISION;
    const double ln2 = lon2 / COORDINATE_PRECISION;
    const double dlat1 = lt1 * (RAD);

    const double dlong1 = ln1 * (RAD);
    const double dlat2 = lt2 * (RAD);
    const double dlong2 = ln2 * (RAD);

    const double dLong = dlong1 - dlong2;
    const double dLat = dlat1 - dlat2;

    const double aHarv = std::pow(std::sin(dLat / 2.0), 2.0) +
                         std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dLong / 2.), 2);
    const double cHarv = 2. * std::atan2(std::sqrt(aHarv), std::sqrt(1.0 - aHarv));
    return earth_radius * cHarv;
}

double coordinate_calculation::great_circle_distance(const FixedPointCoordinate &coordinate_1,
                                                     const FixedPointCoordinate &coordinate_2)
{
    return great_circle_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
                                 coordinate_2.lon);
}

float coordinate_calculation::euclidean_distance(const FixedPointCoordinate &coordinate_1,
                                                 const FixedPointCoordinate &coordinate_2)
{
    return euclidean_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
                              coordinate_2.lon);
}

float coordinate_calculation::euclidean_distance(const int lat1,
                                                 const int lon1,
                                                 const int lat2,
                                                 const int lon2)
{
    BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());

    const float float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
    const float float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
    const float float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
    const float float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;

    const float x_value = (float_lon2 - float_lon1) * cos((float_lat1 + float_lat2) / 2.f);
    const float y_value = float_lat2 - float_lat1;
    return std::hypot(x_value, y_value) * earth_radius;
}

float coordinate_calculation::perpendicular_distance(const FixedPointCoordinate &source_coordinate,
                                                     const FixedPointCoordinate &target_coordinate,
                                                     const FixedPointCoordinate &query_location)
{
    float ratio;
    FixedPointCoordinate nearest_location;

    return perpendicular_distance(source_coordinate, target_coordinate, query_location,
                                  nearest_location, ratio);
}

float coordinate_calculation::perpendicular_distance(const FixedPointCoordinate &segment_source,
                                                     const FixedPointCoordinate &segment_target,
                                                     const FixedPointCoordinate &query_location,
                                                     FixedPointCoordinate &nearest_location,
                                                     float &ratio)
{
    return perpendicular_distance_from_projected_coordinate(
        segment_source, segment_target, query_location,
        {mercator::lat2y(query_location.lat / COORDINATE_PRECISION),
         query_location.lon / COORDINATE_PRECISION},
        nearest_location, ratio);
}

float coordinate_calculation::perpendicular_distance_from_projected_coordinate(
    const FixedPointCoordinate &source_coordinate,
    const FixedPointCoordinate &target_coordinate,
    const FixedPointCoordinate &query_location,
    const std::pair<double, double> &projected_coordinate)
{
    float ratio;
    FixedPointCoordinate nearest_location;

    return perpendicular_distance_from_projected_coordinate(source_coordinate, target_coordinate,
                                                            query_location, projected_coordinate,
                                                            nearest_location, ratio);
}

float coordinate_calculation::perpendicular_distance_from_projected_coordinate(
    const FixedPointCoordinate &segment_source,
    const FixedPointCoordinate &segment_target,
    const FixedPointCoordinate &query_location,
    const std::pair<double, double> &projected_coordinate,
    FixedPointCoordinate &nearest_location,
    float &ratio)
{
    BOOST_ASSERT(query_location.is_valid());

    // initialize values
    const double x = projected_coordinate.first;
    const double y = projected_coordinate.second;
    const double a = mercator::lat2y(segment_source.lat / COORDINATE_PRECISION);
    const double b = segment_source.lon / COORDINATE_PRECISION;
    const double c = mercator::lat2y(segment_target.lat / COORDINATE_PRECISION);
    const double d = segment_target.lon / COORDINATE_PRECISION;
    double p, q /*,mX*/, nY;
    if (std::abs(a - c) > std::numeric_limits<double>::epsilon())
    {
        const double m = (d - b) / (c - a); // slope
        // Projection of (x,y) on line joining (a,b) and (c,d)
        p = ((x + (m * y)) + (m * m * a - m * b)) / (1.f + m * m);
        q = b + m * (p - a);
    }
    else
    {
        p = c;
        q = y;
    }
    nY = (d * p - c * q) / (a * d - b * c);

    // discretize the result to coordinate precision. it's a hack!
    if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
    {
        nY = 0.f;
    }

    // compute ratio
    ratio =
        static_cast<float>((p - nY * a) / c); // These values are actually n/m+n and m/m+n , we need
    // not calculate the explicit values of m an n as we
    // are just interested in the ratio
    if (std::isnan(ratio))
    {
        ratio = (segment_target == query_location ? 1.f : 0.f);
    }
    else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
    {
        ratio = 0.f;
    }
    else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
    {
        ratio = 1.f;
    }

    // compute nearest location
    BOOST_ASSERT(!std::isnan(ratio));
    if (ratio <= 0.f)
    {
        nearest_location = segment_source;
    }
    else if (ratio >= 1.f)
    {
        nearest_location = segment_target;
    }
    else
    {
        // point lies in between
        nearest_location.lat = static_cast<int>(mercator::y2lat(p) * COORDINATE_PRECISION);
        nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
    }
    BOOST_ASSERT(nearest_location.is_valid());

    const float approximate_distance =
        coordinate_calculation::euclidean_distance(query_location, nearest_location);
    BOOST_ASSERT(0.f <= approximate_distance);
    return approximate_distance;
}

void coordinate_calculation::lat_or_lon_to_string(const int value, std::string &output)
{
    char buffer[12];
    buffer[11] = 0; // zero termination
    output = printInt<11, 6>(buffer, value);
}

float coordinate_calculation::deg_to_rad(const float degree)
{
    return degree * (static_cast<float>(M_PI) / 180.f);
}

float coordinate_calculation::rad_to_deg(const float radian)
{
    return radian * (180.f * static_cast<float>(M_1_PI));
}

float coordinate_calculation::bearing(const FixedPointCoordinate &first_coordinate,
                                      const FixedPointCoordinate &second_coordinate)
{
    const float lon_diff =
        second_coordinate.lon / COORDINATE_PRECISION - first_coordinate.lon / COORDINATE_PRECISION;
    const float lon_delta = deg_to_rad(lon_diff);
    const float lat1 = deg_to_rad(first_coordinate.lat / COORDINATE_PRECISION);
    const float lat2 = deg_to_rad(second_coordinate.lat / COORDINATE_PRECISION);
    const float y = std::sin(lon_delta) * std::cos(lat2);
    const float x =
        std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
    float result = rad_to_deg(std::atan2(y, x));
    while (result < 0.f)
    {
        result += 360.f;
    }

    while (result >= 360.f)
    {
        result -= 360.f;
    }
    return result;
}
<commit_msg>fix warning: implicit float/double cast<commit_after>/*

Copyright (c) 2015, Project OSRM, Dennis Luxen, others
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#include "coordinate_calculation.hpp"

#include "../util/mercator.hpp"
#include "../util/string_util.hpp"

#include <boost/assert.hpp>

#include <osrm/coordinate.hpp>

#include <cmath>

#include <limits>

namespace
{
constexpr static const float RAD = 0.017453292519943295769236907684886f;
// earth radius varies between 6,356.750-6,378.135 km (3,949.901-3,963.189mi)
// The IUGG value for the equatorial radius is 6378.137 km (3963.19 miles)
constexpr static const float earth_radius = 6372797.560856f;
}

double coordinate_calculation::great_circle_distance(const int lat1,
                                                     const int lon1,
                                                     const int lat2,
                                                     const int lon2)
{
    BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());
    const double lt1 = lat1 / COORDINATE_PRECISION;
    const double ln1 = lon1 / COORDINATE_PRECISION;
    const double lt2 = lat2 / COORDINATE_PRECISION;
    const double ln2 = lon2 / COORDINATE_PRECISION;
    const double dlat1 = lt1 * (RAD);

    const double dlong1 = ln1 * (RAD);
    const double dlat2 = lt2 * (RAD);
    const double dlong2 = ln2 * (RAD);

    const double dLong = dlong1 - dlong2;
    const double dLat = dlat1 - dlat2;

    const double aHarv = std::pow(std::sin(dLat / 2.0), 2.0) +
                         std::cos(dlat1) * std::cos(dlat2) * std::pow(std::sin(dLong / 2.), 2);
    const double cHarv = 2. * std::atan2(std::sqrt(aHarv), std::sqrt(1.0 - aHarv));
    return earth_radius * cHarv;
}

double coordinate_calculation::great_circle_distance(const FixedPointCoordinate &coordinate_1,
                                                     const FixedPointCoordinate &coordinate_2)
{
    return great_circle_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
                                 coordinate_2.lon);
}

float coordinate_calculation::euclidean_distance(const FixedPointCoordinate &coordinate_1,
                                                 const FixedPointCoordinate &coordinate_2)
{
    return euclidean_distance(coordinate_1.lat, coordinate_1.lon, coordinate_2.lat,
                              coordinate_2.lon);
}

float coordinate_calculation::euclidean_distance(const int lat1,
                                                 const int lon1,
                                                 const int lat2,
                                                 const int lon2)
{
    BOOST_ASSERT(lat1 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lon1 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lat2 != std::numeric_limits<int>::min());
    BOOST_ASSERT(lon2 != std::numeric_limits<int>::min());

    const float float_lat1 = (lat1 / COORDINATE_PRECISION) * RAD;
    const float float_lon1 = (lon1 / COORDINATE_PRECISION) * RAD;
    const float float_lat2 = (lat2 / COORDINATE_PRECISION) * RAD;
    const float float_lon2 = (lon2 / COORDINATE_PRECISION) * RAD;

    const float x_value = (float_lon2 - float_lon1) * std::cos((float_lat1 + float_lat2) / 2.f);
    const float y_value = float_lat2 - float_lat1;
    return std::hypot(x_value, y_value) * earth_radius;
}

float coordinate_calculation::perpendicular_distance(const FixedPointCoordinate &source_coordinate,
                                                     const FixedPointCoordinate &target_coordinate,
                                                     const FixedPointCoordinate &query_location)
{
    float ratio;
    FixedPointCoordinate nearest_location;

    return perpendicular_distance(source_coordinate, target_coordinate, query_location,
                                  nearest_location, ratio);
}

float coordinate_calculation::perpendicular_distance(const FixedPointCoordinate &segment_source,
                                                     const FixedPointCoordinate &segment_target,
                                                     const FixedPointCoordinate &query_location,
                                                     FixedPointCoordinate &nearest_location,
                                                     float &ratio)
{
    return perpendicular_distance_from_projected_coordinate(
        segment_source, segment_target, query_location,
        {mercator::lat2y(query_location.lat / COORDINATE_PRECISION),
         query_location.lon / COORDINATE_PRECISION},
        nearest_location, ratio);
}

float coordinate_calculation::perpendicular_distance_from_projected_coordinate(
    const FixedPointCoordinate &source_coordinate,
    const FixedPointCoordinate &target_coordinate,
    const FixedPointCoordinate &query_location,
    const std::pair<double, double> &projected_coordinate)
{
    float ratio;
    FixedPointCoordinate nearest_location;

    return perpendicular_distance_from_projected_coordinate(source_coordinate, target_coordinate,
                                                            query_location, projected_coordinate,
                                                            nearest_location, ratio);
}

float coordinate_calculation::perpendicular_distance_from_projected_coordinate(
    const FixedPointCoordinate &segment_source,
    const FixedPointCoordinate &segment_target,
    const FixedPointCoordinate &query_location,
    const std::pair<double, double> &projected_coordinate,
    FixedPointCoordinate &nearest_location,
    float &ratio)
{
    BOOST_ASSERT(query_location.is_valid());

    // initialize values
    const double x = projected_coordinate.first;
    const double y = projected_coordinate.second;
    const double a = mercator::lat2y(segment_source.lat / COORDINATE_PRECISION);
    const double b = segment_source.lon / COORDINATE_PRECISION;
    const double c = mercator::lat2y(segment_target.lat / COORDINATE_PRECISION);
    const double d = segment_target.lon / COORDINATE_PRECISION;
    double p, q /*,mX*/, nY;
    if (std::abs(a - c) > std::numeric_limits<double>::epsilon())
    {
        const double m = (d - b) / (c - a); // slope
        // Projection of (x,y) on line joining (a,b) and (c,d)
        p = ((x + (m * y)) + (m * m * a - m * b)) / (1.f + m * m);
        q = b + m * (p - a);
    }
    else
    {
        p = c;
        q = y;
    }
    nY = (d * p - c * q) / (a * d - b * c);

    // discretize the result to coordinate precision. it's a hack!
    if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
    {
        nY = 0.f;
    }

    // compute ratio
    ratio =
        static_cast<float>((p - nY * a) / c); // These values are actually n/m+n and m/m+n , we need
    // not calculate the explicit values of m an n as we
    // are just interested in the ratio
    if (std::isnan(ratio))
    {
        ratio = (segment_target == query_location ? 1.f : 0.f);
    }
    else if (std::abs(ratio) <= std::numeric_limits<float>::epsilon())
    {
        ratio = 0.f;
    }
    else if (std::abs(ratio - 1.f) <= std::numeric_limits<float>::epsilon())
    {
        ratio = 1.f;
    }

    // compute nearest location
    BOOST_ASSERT(!std::isnan(ratio));
    if (ratio <= 0.f)
    {
        nearest_location = segment_source;
    }
    else if (ratio >= 1.f)
    {
        nearest_location = segment_target;
    }
    else
    {
        // point lies in between
        nearest_location.lat = static_cast<int>(mercator::y2lat(p) * COORDINATE_PRECISION);
        nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
    }
    BOOST_ASSERT(nearest_location.is_valid());

    const float approximate_distance =
        coordinate_calculation::euclidean_distance(query_location, nearest_location);
    BOOST_ASSERT(0.f <= approximate_distance);
    return approximate_distance;
}

void coordinate_calculation::lat_or_lon_to_string(const int value, std::string &output)
{
    char buffer[12];
    buffer[11] = 0; // zero termination
    output = printInt<11, 6>(buffer, value);
}

float coordinate_calculation::deg_to_rad(const float degree)
{
    return degree * (static_cast<float>(M_PI) / 180.f);
}

float coordinate_calculation::rad_to_deg(const float radian)
{
    return radian * (180.f * static_cast<float>(M_1_PI));
}

float coordinate_calculation::bearing(const FixedPointCoordinate &first_coordinate,
                                      const FixedPointCoordinate &second_coordinate)
{
    const float lon_diff =
        second_coordinate.lon / COORDINATE_PRECISION - first_coordinate.lon / COORDINATE_PRECISION;
    const float lon_delta = deg_to_rad(lon_diff);
    const float lat1 = deg_to_rad(first_coordinate.lat / COORDINATE_PRECISION);
    const float lat2 = deg_to_rad(second_coordinate.lat / COORDINATE_PRECISION);
    const float y = std::sin(lon_delta) * std::cos(lat2);
    const float x =
        std::cos(lat1) * std::sin(lat2) - std::sin(lat1) * std::cos(lat2) * std::cos(lon_delta);
    float result = rad_to_deg(std::atan2(y, x));
    while (result < 0.f)
    {
        result += 360.f;
    }

    while (result >= 360.f)
    {
        result -= 360.f;
    }
    return result;
}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "../include/spica.h"
using namespace spica;

#include <string>

namespace {
    const int width = 320;
    const int height = 240;
    Random rng = Random();
    const std::string filepath = DATA_DIR + "test_image.bmp";
}

TEST(ImageTest, InstanceTest) {
    Image image;
    EXPECT_EQ(0, image.width());
    EXPECT_EQ(0, image.height());
    ASSERT_DEATH(image(0, 0), "");
    ASSERT_DEATH(Image(-1, -1), "");

    image = Image(width, height);
    EXPECT_EQ(320, image.width());
    EXPECT_EQ(240, image.height());
    for (int y = 0; y < image.height(); y++) {
        for (int x = 0; x < image.width(); x++) {
            EXPECT_EQ(0.0, image(x, y).red());
            EXPECT_EQ(0.0, image(x, y).green());
            EXPECT_EQ(0.0, image(x, y).blue());
        }
    }

    Image rand(160, 120);
    for (int y = 0; y < rand.height(); y++) {
        for (int x = 0; x < rand.width(); x++) {
            rand.pixel(x, y) = Color(rng.nextReal(), rng.nextReal(), rng.nextReal());
        }
    }

    image = rand;
    EXPECT_EQ(rand.width(), image.width());
    EXPECT_EQ(rand.height(), image.height());
    for (int y = 0; y < image.height(); y++) {
        for (int x = 0; x < image.width(); x++) {
            EXPECT_EQ(rand(x, y).red(), image(x, y).red());
            EXPECT_EQ(rand(x, y).green(), image(x, y).green());
            EXPECT_EQ(rand(x, y).blue(), image(x, y).blue());
        }
    }
}

TEST(ImageTest, SaveLoadTest) {
    Image image(width, height);
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            image.pixel(x, y) = Color(rng.nextReal(), rng.nextReal(), rng.nextReal());
        }
    }

    image.saveBMP(filepath);

    Image loaded;
    ASSERT_DEATH(loaded.loadBMP("dammy_path.bmp"), "");

    /*
    loaded.loadBMP(filepath);
    EXPECT_EQ(image.width(), loaded.width());
    EXPECT_EQ(image.height(), loaded.height());
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            EXPECT_NEAR(image(x, y).red(),   loaded(x, y).red(),   0.01) << "Red is different";
            EXPECT_NEAR(image(x, y).green(), loaded(x, y).green(), 0.01) << "Green is different";
            EXPECT_NEAR(image(x, y).blue(),  loaded(x, y).blue(),  0.01) << "Blue is different";
        }
    }
    */
}
<commit_msg>Revising unit test for Image object.<commit_after>#include "gtest/gtest.h"
#include "../include/spica.h"
using namespace spica;

#include <string>

namespace {
    const int width = 320;
    const int height = 240;
    Random rng = Random();
    const std::string filepath = DATA_DIR + "test_image.bmp";
}

TEST(ImageTest, InstanceTest) {
    Image image;
    EXPECT_EQ(0, image.width());
    EXPECT_EQ(0, image.height());
    ASSERT_DEATH(image(0, 0), "");
    ASSERT_DEATH(Image(-1, -1), "");

    image = Image(width, height);
    EXPECT_EQ(320, image.width());
    EXPECT_EQ(240, image.height());
    for (int y = 0; y < image.height(); y++) {
        for (int x = 0; x < image.width(); x++) {
            EXPECT_EQ(0.0, image(x, y).red());
            EXPECT_EQ(0.0, image(x, y).green());
            EXPECT_EQ(0.0, image(x, y).blue());
        }
    }

    Image rand(160, 120);
    for (int y = 0; y < rand.height(); y++) {
        for (int x = 0; x < rand.width(); x++) {
            rand.pixel(x, y) = Color(rng.nextReal(), rng.nextReal(), rng.nextReal());
        }
    }

    image = rand;
    EXPECT_EQ(rand.width(), image.width());
    EXPECT_EQ(rand.height(), image.height());
    for (int y = 0; y < image.height(); y++) {
        for (int x = 0; x < image.width(); x++) {
            EXPECT_EQ(rand(x, y).red(), image(x, y).red());
            EXPECT_EQ(rand(x, y).green(), image(x, y).green());
            EXPECT_EQ(rand(x, y).blue(), image(x, y).blue());
        }
    }
}

TEST(ImageTest, InvalidPathToLoad) {
    Image image;
    ASSERT_DEATH(image.loadBMP("dammy_path.bmp"), "");
}

TEST(ImageTest, SaveLoadTest) {
    Image image(width, height);
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            image.pixel(x, y) = Color(rng.nextReal(), rng.nextReal(), rng.nextReal());
        }
    }
    image.saveBMP(filepath);

    std::cout << filepath << std::endl;
    std::cerr << filepath << std::endl;

    Image loaded;
    loaded.loadBMP(filepath);
    EXPECT_EQ(image.width(), loaded.width());
    EXPECT_EQ(image.height(), loaded.height());
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            EXPECT_NEAR(image(x, y).red(),   loaded(x, y).red(),   0.01) << "Red is different";
            EXPECT_NEAR(image(x, y).green(), loaded(x, y).green(), 0.01) << "Green is different";
            EXPECT_NEAR(image(x, y).blue(),  loaded(x, y).blue(),  0.01) << "Blue is different";
        }
    }
}
<|endoftext|>


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

#include "grid_soa.h"

namespace embree
{
  namespace isa
  {
    GridSOA::GridSOA(const SubdivPatch1Base& patch,
                     const size_t x0, const size_t x1, const size_t y0, const size_t y1, const size_t swidth, const size_t sheight,
                     const SubdivMesh* const geom, const size_t bvhBytes, BBox3fa* bounds_o)
      : root(BVH4::emptyNode), width(x1-x0+1), height(y1-y0+1), dim_offset(0), geomID(patch.geom), primID(patch.prim), bvhBytes(bvhBytes)
    {
      dim_offset = calculate_grid_size(width,height);

      dynamic_large_stack_array(float,local_grid_u,dim_offset+VSIZEX,64*64);
      dynamic_large_stack_array(float,local_grid_v,dim_offset+VSIZEX,64*64);
      dynamic_large_stack_array(float,local_grid_x,dim_offset+VSIZEX,64*64);
      dynamic_large_stack_array(float,local_grid_y,dim_offset+VSIZEX,64*64);
      dynamic_large_stack_array(float,local_grid_z,dim_offset+VSIZEX,64*64);

      /* compute vertex grid (+displacement) */
      evalGrid(patch,x0,x1,y0,y1,swidth,sheight,
               local_grid_x,local_grid_y,local_grid_z,local_grid_u,local_grid_v,geom);

      /* copy temporary data to tessellation cache */
      float* const grid_x  = (float*)(gridData() + 0*dim_offset);
      float* const grid_y  = (float*)(gridData() + 1*dim_offset);
      float* const grid_z  = (float*)(gridData() + 2*dim_offset);
      int  * const grid_uv = (int*  )(gridData() + 3*dim_offset);

      /* copy points */
      memcpy(grid_x, local_grid_x, dim_offset*sizeof(float));
      memcpy(grid_y, local_grid_y, dim_offset*sizeof(float));
      memcpy(grid_z, local_grid_z, dim_offset*sizeof(float));

      /* encode UVs */
      for (size_t i=0; i<dim_offset; i+=VSIZEX) {
        const vintx iu = (vintx) clamp(vfloatx::load(&local_grid_u[i])*0xFFFF, vfloatx(0.0f), vfloatx(0xFFFF));
        const vintx iv = (vintx) clamp(vfloatx::load(&local_grid_v[i])*0xFFFF, vfloatx(0.0f), vfloatx(0xFFFF));
        vintx::storeu(&grid_uv[i], (iv << 16) | iu);
      }

      /* create BVH */
      root = buildBVH(bvhData(),gridData(),bvhBytes,bounds_o);
    }

    size_t GridSOA::getBVHBytes(const GridRange& range, const unsigned int leafBytes)
    {
      if (range.hasLeafSize())
        return leafBytes;

      __aligned(64) GridRange r[4];
      const unsigned int children = range.splitIntoSubRanges(r);

      size_t bytes = sizeof(BVH4::Node);
      for (unsigned int i=0;i<children;i++)
        bytes += getBVHBytes(r[i],leafBytes);
      return bytes;
    }

    BVH4::NodeRef GridSOA::buildBVH(char* node_array, float* grid_array, const size_t bvhBytes, BBox3fa* bounds_o)
    {
      BVH4::NodeRef root = 0; size_t allocator = 0;
      GridRange range(0,width-1,0,height-1);
      BBox3fa bounds = buildBVH(root,node_array,grid_array,range,allocator);
      if (bounds_o) *bounds_o = bounds;
      assert(allocator == bvhBytes);
      return root;
    }

    BBox3fa GridSOA::buildBVH(BVH4::NodeRef& curNode, char* node_array, float* grid_array, const GridRange& range, size_t& allocator)
    {
      /*! create leaf node */
      if (unlikely(range.hasLeafSize()))
      {
        const float* const grid_x_array = grid_array + 0 * dim_offset;
        const float* const grid_y_array = grid_array + 1 * dim_offset;
        const float* const grid_z_array = grid_array + 2 * dim_offset;

        /* compute the bounds just for the range! */
        BBox3fa bounds( empty );
        for (size_t v = range.v_start; v<=range.v_end; v++)
        {
          for (size_t u = range.u_start; u<=range.u_end; u++)
          {
            const float x = grid_x_array[ v * width + u];
            const float y = grid_y_array[ v * width + u];
            const float z = grid_z_array[ v * width + u];
            bounds.extend( Vec3fa(x,y,z) );
          }
        }
        assert(is_finite(bounds));

        /* shift 2x2 quads that wrap around to the left */ // FIXME: causes intersection filter to be called multiple times for some triangles
        unsigned int u_start = range.u_start, u_end = range.u_end;
        unsigned int v_start = range.v_start, v_end = range.v_end;
        unsigned int u_size = u_end-u_start; assert(u_size > 0);
        unsigned int v_size = v_end-v_start; assert(v_size > 0);
        if (unlikely(u_size < 2 && u_start > 0)) u_start--;
        if (unlikely(v_size < 2 && v_start > 0)) v_start--;

        /* we store pointer to first subgrid vertex as leaf node */
        const size_t value = 16*(v_start * width + u_start + 1); // +1 to not create empty leaf
        curNode = BVH4::encodeTypedLeaf((void*)value,0);
        return bounds;
      }

      /* create internal node */
      else
      {
        /* allocate new bvh4 node */
        BVH4::Node* node = (BVH4::Node *)&node_array[allocator];
        allocator += sizeof(BVH4::Node);
        node->clear();

        /* split range */
        GridRange r[4];
        const size_t children = range.splitIntoSubRanges(r);

        /* recurse into subtrees */
        BBox3fa bounds( empty );
        for (size_t i=0; i<children; i++)
        {
          BBox3fa box = buildBVH( node->child(i), node_array, grid_array, r[i], allocator);
          node->set(i,box);
          bounds.extend(box);
        }

        curNode = BVH4::encodeNode(node);
        assert(is_finite(bounds));
        return bounds;
      }
    }
  }
}
<commit_msg>compressing UV for subdiv first into temprary array<commit_after>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "grid_soa.h"

namespace embree
{
  namespace isa
  {
    GridSOA::GridSOA(const SubdivPatch1Base& patch,
                     const size_t x0, const size_t x1, const size_t y0, const size_t y1, const size_t swidth, const size_t sheight,
                     const SubdivMesh* const geom, const size_t bvhBytes, BBox3fa* bounds_o)
      : root(BVH4::emptyNode), width(x1-x0+1), height(y1-y0+1), dim_offset(0), geomID(patch.geom), primID(patch.prim), bvhBytes(bvhBytes)
    {
      /* the generate loops need padded arrays, thus first store into these temporary arrays */
      dim_offset = calculate_grid_size(width,height);
      dynamic_large_stack_array(float,local_grid_u,dim_offset+VSIZEX,64*64);
      dynamic_large_stack_array(float,local_grid_v,dim_offset+VSIZEX,64*64);
      dynamic_large_stack_array(float,local_grid_x,dim_offset+VSIZEX,64*64);
      dynamic_large_stack_array(float,local_grid_y,dim_offset+VSIZEX,64*64);
      dynamic_large_stack_array(float,local_grid_z,dim_offset+VSIZEX,64*64);
      dynamic_large_stack_array(float,local_grid_uv,dim_offset+VSIZEX,64*64);

      /* compute vertex grid (+displacement) */
      evalGrid(patch,x0,x1,y0,y1,swidth,sheight,
               local_grid_x,local_grid_y,local_grid_z,local_grid_u,local_grid_v,geom);

      /* encode UVs */
      for (size_t i=0; i<dim_offset; i+=VSIZEX) {
        const vintx iu = (vintx) clamp(vfloatx::load(&local_grid_u[i])*0xFFFF, vfloatx(0.0f), vfloatx(0xFFFF));
        const vintx iv = (vintx) clamp(vfloatx::load(&local_grid_v[i])*0xFFFF, vfloatx(0.0f), vfloatx(0xFFFF));
        vintx::storeu(&local_grid_uv[i], (iv << 16) | iu);
      }

      /* copy temporary data to compact grid */
      float* const grid_x  = (float*)(gridData() + 0*dim_offset);
      float* const grid_y  = (float*)(gridData() + 1*dim_offset);
      float* const grid_z  = (float*)(gridData() + 2*dim_offset);
      int  * const grid_uv = (int*  )(gridData() + 3*dim_offset);
      memcpy(grid_x, local_grid_x, dim_offset*sizeof(float));
      memcpy(grid_y, local_grid_y, dim_offset*sizeof(float));
      memcpy(grid_z, local_grid_z, dim_offset*sizeof(float));
      memcpy(grid_uv,local_grid_uv,dim_offset*sizeof(int));

      /* create BVH */
      root = buildBVH(bvhData(),gridData(),bvhBytes,bounds_o);
    }

    size_t GridSOA::getBVHBytes(const GridRange& range, const unsigned int leafBytes)
    {
      if (range.hasLeafSize())
        return leafBytes;

      __aligned(64) GridRange r[4];
      const unsigned int children = range.splitIntoSubRanges(r);

      size_t bytes = sizeof(BVH4::Node);
      for (unsigned int i=0;i<children;i++)
        bytes += getBVHBytes(r[i],leafBytes);
      return bytes;
    }

    BVH4::NodeRef GridSOA::buildBVH(char* node_array, float* grid_array, const size_t bvhBytes, BBox3fa* bounds_o)
    {
      BVH4::NodeRef root = 0; size_t allocator = 0;
      GridRange range(0,width-1,0,height-1);
      BBox3fa bounds = buildBVH(root,node_array,grid_array,range,allocator);
      if (bounds_o) *bounds_o = bounds;
      assert(allocator == bvhBytes);
      return root;
    }

    BBox3fa GridSOA::buildBVH(BVH4::NodeRef& curNode, char* node_array, float* grid_array, const GridRange& range, size_t& allocator)
    {
      /*! create leaf node */
      if (unlikely(range.hasLeafSize()))
      {
        const float* const grid_x_array = grid_array + 0 * dim_offset;
        const float* const grid_y_array = grid_array + 1 * dim_offset;
        const float* const grid_z_array = grid_array + 2 * dim_offset;

        /* compute the bounds just for the range! */
        BBox3fa bounds( empty );
        for (size_t v = range.v_start; v<=range.v_end; v++)
        {
          for (size_t u = range.u_start; u<=range.u_end; u++)
          {
            const float x = grid_x_array[ v * width + u];
            const float y = grid_y_array[ v * width + u];
            const float z = grid_z_array[ v * width + u];
            bounds.extend( Vec3fa(x,y,z) );
          }
        }
        assert(is_finite(bounds));

        /* shift 2x2 quads that wrap around to the left */ // FIXME: causes intersection filter to be called multiple times for some triangles
        unsigned int u_start = range.u_start, u_end = range.u_end;
        unsigned int v_start = range.v_start, v_end = range.v_end;
        unsigned int u_size = u_end-u_start; assert(u_size > 0);
        unsigned int v_size = v_end-v_start; assert(v_size > 0);
        if (unlikely(u_size < 2 && u_start > 0)) u_start--;
        if (unlikely(v_size < 2 && v_start > 0)) v_start--;

        /* we store pointer to first subgrid vertex as leaf node */
        const size_t value = 16*(v_start * width + u_start + 1); // +1 to not create empty leaf
        curNode = BVH4::encodeTypedLeaf((void*)value,0);
        return bounds;
      }

      /* create internal node */
      else
      {
        /* allocate new bvh4 node */
        BVH4::Node* node = (BVH4::Node *)&node_array[allocator];
        allocator += sizeof(BVH4::Node);
        node->clear();

        /* split range */
        GridRange r[4];
        const size_t children = range.splitIntoSubRanges(r);

        /* recurse into subtrees */
        BBox3fa bounds( empty );
        for (size_t i=0; i<children; i++)
        {
          BBox3fa box = buildBVH( node->child(i), node_array, grid_array, r[i], allocator);
          node->set(i,box);
          bounds.extend(box);
        }

        curNode = BVH4::encodeNode(node);
        assert(is_finite(bounds));
        return bounds;
      }
    }
  }
}
<|endoftext|>