Go back to Richel Bilderbeek's homepage.

Go back to Richel Bilderbeek's C++ page.

 

 

 

 

 

(C++) PerfectElasticCollision

 

PerfectElasticCollision is a tool to investigate the impulses of a perfect elastic collision.

 

PerfectElasticCollision is programmed using the Qt Creator IDE, using the Boost, QT and STL libraries.

 

 

 

 

 

Downloads

 

 

The Windows executable of version 1.0 is created following how to cross-compile a Qt Creator project from Ubuntu to a windows executable: example 15: MinGW cross-compiling environment.

Technical facts

 

Operating system(s) or programming environment(s)

IDE(s):

Project type:

C++ standard:

Compiler(s):

Libraries used:

 

 

 

 

 

Qt project file: ./ToolPerfectElasticCollision/ToolPerfectElasticCollisionConsole.pro

 

include(../../ConsoleApplication.pri)
include(../../Libraries/Apfloat.pri)
include(../../Libraries/Boost.pri)
include(../../Libraries/GeneralConsole.pri)

include(../../Classes/CppContainer/CppContainer.pri)
include(../../Classes/CppGeometry/CppGeometry.pri)
include(../../Classes/CppPlane/CppPlane.pri)
include(../../Classes/CppRibiRegex/CppRibiRegex.pri)

include(ToolPerfectElasticCollisionConsole.pri)

SOURCES += main.cpp

 

 

 

 

 

Qt project file: ./ToolPerfectElasticCollision/ToolPerfectElasticCollisionDesktop.pro

 

include(../../DesktopApplication.pri)
include(../../Libraries/Apfloat.pri)
include(../../Libraries/Boost.pri)
include(../../Libraries/GeneralConsole.pri)
include(../../Libraries/GeneralDesktop.pri)

include(../../Classes/CppContainer/CppContainer.pri)
include(../../Classes/CppGeometry/CppGeometry.pri)
include(../../Classes/CppPlane/CppPlane.pri)
include(../../Classes/CppRibiRegex/CppRibiRegex.pri)
include(ToolPerfectElasticCollisionDesktop.pri)

SOURCES += qtmain.cpp

 

 

 

 

 

./ToolPerfectElasticCollision/ToolPerfectElasticCollisionConsole.pri

 

INCLUDEPATH += \
    ../../Tools/ToolPerfectElasticCollision

SOURCES += \
    ../../Tools/ToolPerfectElasticCollision/perfectelasticcollisionmenudialog.cpp

HEADERS += \
    ../../Tools/ToolPerfectElasticCollision/perfectelasticcollisionmenudialog.h

OTHER_FILES += \
    ../../Tools/ToolPerfectElasticCollision/Licence.txt

 

 

 

 

 

./ToolPerfectElasticCollision/ToolPerfectElasticCollisionDesktop.pri

 

include(../../Tools/ToolPerfectElasticCollision/ToolPerfectElasticCollisionConsole.pri)

SOURCES += \
    ../../Tools/ToolPerfectElasticCollision/qtperfectelasticcollisionmaindialog.cpp \
    ../../Tools/ToolPerfectElasticCollision/qtperfectelasticcollisionmenudialog.cpp

HEADERS  += \
    ../../Tools/ToolPerfectElasticCollision/qtperfectelasticcollisionmaindialog.h \
    ../../Tools/ToolPerfectElasticCollision/qtperfectelasticcollisionmenudialog.h

FORMS    += \
    ../../Tools/ToolPerfectElasticCollision/qtperfectelasticcollisionmaindialog.ui \
    ../../Tools/ToolPerfectElasticCollision/qtperfectelasticcollisionmenudialog.ui

RESOURCES += \
    ../../Tools/ToolPerfectElasticCollision/ToolPerfectElasticCollision.qrc

 

 

 

 

 

./ToolPerfectElasticCollision/ToolPerfectElasticCollisionWebsite.pri

 

include(../../Tools/ToolPerfectElasticCollision/ToolPerfectElasticCollisionConsole.pri)
SOURCES +=
HEADERS +=

 

 

 

 

 

./ToolPerfectElasticCollision/main.cpp

 

//---------------------------------------------------------------------------
/*
PerfectElasticCollision, tool to investigate a perfect elastic collision
Copyright (C) 2010-2013 Richel Bilderbeek

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 <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From hhtp://www.richelbilderbeek.nl/ToolPerfectElasticCollision.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include "perfectelasticcollisionmenudialog.h"
#pragma GCC diagnostic pop

int main(int argc, char *argv[])
{
  const std::vector<std::string> args { ribi::MenuDialog::ConvertArguments(argc,argv) };
  ribi::PerfectElasticCollisionMenuDialog d;
  return d.Execute(args);
}

 

 

 

 

 

./ToolPerfectElasticCollision/perfectelasticcollisionmenudialog.h

 

//---------------------------------------------------------------------------
/*
PerfectElasticCollision, tool to investigate a perfect elastic collision
Copyright (C) 2010-2015 Richel Bilderbeek

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 <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From hhtp://www.richelbilderbeek.nl/ToolPerfectElasticCollision.htm
//---------------------------------------------------------------------------
#ifndef PERFECTELASTICCOLLISIONMENUDIALOG_H
#define PERFECTELASTICCOLLISIONMENUDIALOG_H

#include "menudialog.h"

namespace ribi {

///PerfectElasticCollisionMenuDialog contains the PerfectElasticCollision menu dialog
struct  PerfectElasticCollisionMenuDialog final : public MenuDialog
{
  About GetAbout() const noexcept override;
  Help GetHelp() const noexcept override;
  boost::shared_ptr<const Program> GetProgram() const noexcept override;
  std::string GetVersion() const noexcept override;
  std::vector<std::string> GetVersionHistory() const noexcept override;

  private:
  int ExecuteSpecific(const std::vector<std::string>& argv) noexcept override;

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace ribi

#endif // PERFECTELASTICCOLLISIONMENUDIALOG_H

 

 

 

 

 

./ToolPerfectElasticCollision/perfectelasticcollisionmenudialog.cpp

 

//---------------------------------------------------------------------------
/*
PerfectElasticCollision, tool to investigate a perfect elastic collision
Copyright (C) 2010-2015 Richel Bilderbeek

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 <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From hhtp://www.richelbilderbeek.nl/ToolPerfectElasticCollision.htm
//---------------------------------------------------------------------------
#include "perfectelasticcollisionmenudialog.h"

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <stdexcept>

#include "richelbilderbeekprogram.h"
#include "testtimer.h"
#include "trace.h"

int ribi::PerfectElasticCollisionMenuDialog::ExecuteSpecific(const std::vector<std::string>& argv) noexcept
{
  #ifndef NDEBUG
  Test();
  #endif
  const int argc = static_cast<int>(argv.size());
  if (argc == 1)
  {
    std::cout << this->GetHelp() << '\n';
    return 1;
  }
  assert(!"TODO");
  return 1;
}

ribi::About ribi::PerfectElasticCollisionMenuDialog::GetAbout() const noexcept
{
  About a(
    "Richel Bilderbeek",
    "PerfectElasticCollision",
    "tool to investigate a perfect elastic collision",
    "the 7th of March 2012",
    "2010-2015",
    "http://www.richelbilderbeek.nl/ToolPerfectElasticCollision.htm",
    GetVersion(),
    GetVersionHistory()
  );
  a.AddLibrary("TestTimer version: " + TestTimer::GetVersion());
  a.AddLibrary("Trace version: " + Trace::GetVersion());
  return a;
}

ribi::Help ribi::PerfectElasticCollisionMenuDialog::GetHelp() const noexcept
{
  return Help(
    this->GetAbout().GetFileTitle(),
    this->GetAbout().GetFileDescription(),
    {

    },
    {

    }
  );
}

boost::shared_ptr<const ribi::Program> ribi::PerfectElasticCollisionMenuDialog::GetProgram() const noexcept
{
  const boost::shared_ptr<const ribi::Program> p {
    new ProgramPerfectElasticCollision
  };
  assert(p);
  return p;
}

std::string ribi::PerfectElasticCollisionMenuDialog::GetVersion() const noexcept
{
  return "1.2";
}

std::vector<std::string> ribi::PerfectElasticCollisionMenuDialog::GetVersionHistory() const noexcept
{
  return {
    "2010-08-14: version 1.0: initial version",
    "2012-03-07: version 1.1: added versioning. Added menu screen",
    "2013-11-04: version 1.2: conformized to ProjectRichelBilderbeekConsole",
  };
}


#ifndef NDEBUG
void ribi::PerfectElasticCollisionMenuDialog::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  const TestTimer test_timer(__func__,__FILE__,1.0);
}
#endif

 

 

 

 

 

./ToolPerfectElasticCollision/qtmain.cpp

 

//---------------------------------------------------------------------------
/*
PerfectElasticCollision, tool to investigate a perfect elastic collision
Copyright (C) 2010 Richel Bilderbeek

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 <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From hhtp://www.richelbilderbeek.nl/ToolPerfectElasticCollision.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <QApplication>
#include "qtperfectelasticcollisionmenudialog.h"
#pragma GCC diagnostic pop

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  ribi::QtPerfectElasticCollisionMenuDialog w;
  w.show();
  return a.exec();
}

 

 

 

 

 

./ToolPerfectElasticCollision/qtperfectelasticcollisionmaindialog.h

 

//---------------------------------------------------------------------------
/*
PerfectElasticCollision, tool to investigate a perfect elastic collision
Copyright (C) 2010-2015 Richel Bilderbeek

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 <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From hhtp://www.richelbilderbeek.nl/ToolPerfectElasticCollision.htm
//---------------------------------------------------------------------------
#ifndef QTPERFECTELASTICCOLLISIONMAINDIALOG_H
#define QTPERFECTELASTICCOLLISIONMAINDIALOG_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "qthideandshowdialog.h"
#pragma GCC diagnostic pop

struct QTimer;

namespace Ui {
  class QtPerfectElasticCollisionMainDialog;
}

namespace ribi {

class QtPerfectElasticCollisionMainDialog : public QtHideAndShowDialog
{
  Q_OBJECT

public:
  explicit QtPerfectElasticCollisionMainDialog(QWidget *parent = 0);
  QtPerfectElasticCollisionMainDialog(const QtPerfectElasticCollisionMainDialog&) = delete;
  QtPerfectElasticCollisionMainDialog& operator=(const QtPerfectElasticCollisionMainDialog&) = delete;
  ~QtPerfectElasticCollisionMainDialog() noexcept;

protected:
  void paintEvent(QPaintEvent*);

private:
  Ui::QtPerfectElasticCollisionMainDialog *ui;
  QTimer * const m_timer;

private slots:
  void onAnyChange();
  void onCheck();
  void onTimer();


  //From http://www.richelbilderbeek.nl/CppDrawGlobe.htm
  static QPixmap DrawGlobe(
    const int width,
    const int height,
    const unsigned char r,
    const unsigned char g,
    const unsigned char b);

  //From http://www.richelbilderbeek.nl/CppPaint.htm
  static void Paint(
  QPixmap& pixmap,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b,
  const unsigned char a = 255);

  //From http://www.richelbilderbeek.nl/CppDoPerfectElasticCollision.htm
  static void DoPerfectElasticCollision(
  const double angleCollision,
  double& angle1,
  double& speed1,
  double& angle2,
  double& speed2);

  ///Obtain the angle in radians between two deltas
  ///12 o'clock is 0.0 * pi
  /// 3 o'clock is 0.5 * pi
  /// 6 o'clock is 1.0 * pi
  /// 9 o'clock is 1.5 * pi
  //From www.richelbilderbeek.nl/CppGetAngle.htm
  static double GetAngle(const double dx, const double dy);

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace ribi

#endif // QTPERFECTELASTICCOLLISIONMAINDIALOG_H

 

 

 

 

 

./ToolPerfectElasticCollision/qtperfectelasticcollisionmaindialog.cpp

 

//---------------------------------------------------------------------------
/*
PerfectElasticCollision, tool to investigate a perfect elastic collision
Copyright (C) 2010-2015 Richel Bilderbeek

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 <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From hhtp://www.richelbilderbeek.nl/ToolPerfectElasticCollision.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include "qtperfectelasticcollisionmaindialog.h"

#include <cassert>
#include <cstdlib>
#include <iostream>

#include <boost/lexical_cast.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/numeric/conversion/cast.hpp>

#include <QBitmap>
#include <QMessageBox>
#include <QPainter>
#include <QTimer>

#include "geometry.h"
#include "ui_qtperfectelasticcollisionmaindialog.h"
#pragma GCC diagnostic pop

ribi::QtPerfectElasticCollisionMainDialog::QtPerfectElasticCollisionMainDialog(QWidget *parent)
  : QtHideAndShowDialog(parent),
    ui(new Ui::QtPerfectElasticCollisionMainDialog),
    m_timer(new QTimer)
{
  #ifndef NDEBUG
  Test();
  #endif
  ui->setupUi(this);

  QObject::connect(this->ui->dial_angle,&QDial::sliderMoved,this,&ribi::QtPerfectElasticCollisionMainDialog::onAnyChange);
  QObject::connect(this->ui->dial_impulse_angle1,&QDial::sliderMoved,this,&ribi::QtPerfectElasticCollisionMainDialog::onAnyChange);
  QObject::connect(this->ui->dial_impulse_angle2,&QDial::sliderMoved,this,&ribi::QtPerfectElasticCollisionMainDialog::onAnyChange);
  QObject::connect(this->ui->slider_impulse_1,&QDial::sliderMoved,this,&ribi::QtPerfectElasticCollisionMainDialog::onAnyChange);
  QObject::connect(this->ui->slider_impulse_2,&QDial::sliderMoved,this,&ribi::QtPerfectElasticCollisionMainDialog::onAnyChange);
  QObject::connect(this->ui->check_demo,&QCheckBox::toggled,this,&ribi::QtPerfectElasticCollisionMainDialog::onCheck);
  QObject::connect(m_timer,&QTimer::timeout,this,&ribi::QtPerfectElasticCollisionMainDialog::onTimer);
}

ribi::QtPerfectElasticCollisionMainDialog::~QtPerfectElasticCollisionMainDialog() noexcept
{
  delete ui;
  delete m_timer;
}

void ribi::QtPerfectElasticCollisionMainDialog::paintEvent(QPaintEvent*)
{
  QPainter painter(this);
  assert(ui->dial_angle->minimum() == 0);
  assert(ui->dial_impulse_angle1->minimum() == 0);
  assert(ui->dial_impulse_angle2->minimum() == 0);
  assert(ui->slider_impulse_1->minimum() == 0);
  assert(ui->slider_impulse_2->minimum() == 0);

  const double pi = boost::math::constants::pi<double>();

  const double angle
    = 2.0 * pi * boost::numeric_cast<double>(ui->dial_angle->sliderPosition())
    / boost::numeric_cast<double>(ui->dial_angle->maximum());
  const double angle_impulse1
    = 2.0 * pi * boost::numeric_cast<double>(ui->dial_impulse_angle1->sliderPosition())
    / boost::numeric_cast<double>(ui->dial_impulse_angle1->maximum());
  const double angle_impulse2
    = 2.0 * pi * boost::numeric_cast<double>(ui->dial_impulse_angle2->sliderPosition())
    / boost::numeric_cast<double>(ui->dial_impulse_angle2->maximum());
  const double speed_impulse1
    = 100.0 * boost::numeric_cast<double>(ui->slider_impulse_1->sliderPosition())
    / boost::numeric_cast<double>(ui->slider_impulse_1->maximum());
  const double speed_impulse2
    = 100.0 * boost::numeric_cast<double>(ui->slider_impulse_2->sliderPosition())
    / boost::numeric_cast<double>(ui->slider_impulse_2->maximum());
  const int width = ui->widget_top->width();
  const int height = ui->widget_top->height();
  const int size = std::min(width,height);
  const int globe_size = size / 5;
  const double distance = boost::numeric_cast<double>(globe_size);
  const double dx =  std::sin(angle) * distance;
  const double dy = -std::cos(angle) * distance;
  const double midx = boost::numeric_cast<double>(size) / 2.0;
  const double midy = boost::numeric_cast<double>(size) / 2.0;
  const double midx1 = midx - (dx / 2.0);
  const double midy1 = midy - (dy / 2.0);
  const double midx2 = midx + (dx / 2.0);
  const double midy2 = midy + (dy / 2.0);
  const double x1 = midx1 - (boost::numeric_cast<double>(globe_size) / 2.0);
  const double y1 = midy1 - (boost::numeric_cast<double>(globe_size) / 2.0);
  const double x2 = midx2 - (boost::numeric_cast<double>(globe_size) / 2.0);
  const double y2 = midy2 - (boost::numeric_cast<double>(globe_size) / 2.0);
  //std::clog << "angle_impulse1: " << angle_impulse1 << '\n';
  //std::clog << "angle_impulse2: " << angle_impulse2 << '\n';

  //Draw black background
  {
    QPixmap pixmap(width,height);
    Paint(pixmap,1,1,1,255);
    painter.drawPixmap(ui->widget_top->geometry(),pixmap);
  }
  //Draw globe 1
  {
    QPixmap pixmap = DrawGlobe(globe_size,globe_size,255,0,0);
    painter.drawPixmap(x1,y1,pixmap);
  }
  //Draw globe 2
  {
    QPixmap pixmap = DrawGlobe(globe_size,globe_size,0,0,255);
    painter.drawPixmap(x2,y2,pixmap);
  }
  //Change the pen to white
  {
    QPen pen = painter.pen();
    pen.setColor(Qt::white);
    pen.setWidth(3);
    painter.setPen(pen);
  }
  //Draw impulses
  painter.drawLine(
    midx1,
    midy1,
    midx1 + (std::sin(angle_impulse1) * speed_impulse1),
    midy1 - (std::cos(angle_impulse1) * speed_impulse1) );
  painter.drawLine(
    midx2,
    midy2,
    midx2 + (std::sin(angle_impulse2) * speed_impulse2),
    midy2 - (std::cos(angle_impulse2) * speed_impulse2) );
  painter.drawText(
    midx1 + (std::sin(angle_impulse1) * speed_impulse1),
    midy1 - (std::cos(angle_impulse1) * speed_impulse1),112,16,0,"before1");
  painter.drawText(
    midx2 + (std::sin(angle_impulse2) * speed_impulse2),
    midy2 - (std::cos(angle_impulse2) * speed_impulse2),
    112,16,0,"before2");
  {
    double new_angle1 = angle_impulse1;
    double new_speed1 = speed_impulse1;
    double new_angle2 = angle_impulse2;
    double new_speed2 = speed_impulse2;
    DoPerfectElasticCollision(angle,new_angle1,new_speed1,new_angle2,new_speed2);
    const double impulse_before = speed_impulse1 + speed_impulse2;
    const double impulse_after  = new_speed1 + new_speed2;
    const double change = (impulse_after - impulse_before) / impulse_before;
    ui->label_error->setText("Impulse change: "
      + QString(boost::lexical_cast<std::string>(change * 100.0).c_str())
      + "%");
    //Draw resulting impulses
    {
      //Change the pen to white
      QPen pen = painter.pen();
      pen.setColor(Qt::gray);
      pen.setWidth(3);
      painter.setPen(pen);

    }
    painter.drawLine(
      midx1,
      midy1,
      midx1 + (std::sin(new_angle1) * new_speed1),
      midy1 - (std::cos(new_angle1) * new_speed1) );
    painter.drawLine(
      midx2,
      midy2,
      midx2 + (std::sin(new_angle2) * new_speed2),
      midy2 - (std::cos(new_angle2) * new_speed2) );
    painter.drawText(
      midx1 + (std::sin(new_angle1) * new_speed1),
      midy1 - (std::cos(new_angle1) * new_speed1),96,16,0,"after1");
    painter.drawText(
      midx2 + (std::sin(new_angle2) * new_speed2),
      midy2 - (std::cos(new_angle2) * new_speed2),96,16,0,"after2");
  }


}

void ribi::QtPerfectElasticCollisionMainDialog::onAnyChange()
{
  this->update();
}

void ribi::QtPerfectElasticCollisionMainDialog::onCheck()
{
  if (ui->check_demo->isChecked())
  {
    m_timer->start(10);
  }
  else
  {
    m_timer->stop();
  }
}

void ribi::QtPerfectElasticCollisionMainDialog::onTimer()
{
  ui->dial_angle->setSliderPosition(
     (ui->dial_angle->sliderPosition() + (std::rand() % 2))
    % ui->dial_angle->maximum() );
  ui->dial_impulse_angle1->setSliderPosition(
     (ui->dial_impulse_angle1->sliderPosition() + (std::rand() % 3))
    % ui->dial_impulse_angle1->maximum() );
  ui->dial_impulse_angle2->setSliderPosition(
     (ui->dial_impulse_angle2->sliderPosition() + (std::rand() % 4))
    % ui->dial_impulse_angle2->maximum() );
  this->update();
}

//From http://www.richelbilderbeek.nl/CppDrawGlobe.htm
QPixmap ribi::QtPerfectElasticCollisionMainDialog::DrawGlobe(
  const int width,
  const int height,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b)
{
  QPixmap pixmap(width,height);
  QImage image = pixmap.toImage();

  assert(image.bytesPerLine() / width == 4
    && "Assume there are 4 bytes per pixel");

  const double r_max = boost::numeric_cast<double>(r);
  const double g_max = boost::numeric_cast<double>(g);
  const double b_max = boost::numeric_cast<double>(b);
  const double midX = boost::numeric_cast<double>(width ) / 2.0;
  const double midY = boost::numeric_cast<double>(height) / 2.0;
  const double max_dist = std::min(midX,midY);

  for (int y=0; y!=height; ++y)
  {

    unsigned char * const line
      = static_cast<unsigned char *>(image.scanLine(y));
    const double y_d = boost::numeric_cast<double>(y);
    for (int x=0; x!=width; ++x)
    {
      const double x_d = boost::numeric_cast<double>(x);
      const double dist
        = std::sqrt(
            ((x_d - midX) * (x_d - midX))
          + ((y_d - midY) * (y_d - midY)) );
      if (dist <= max_dist)
      {
        const double rel_dist = dist / max_dist;
        const int r_here = rel_dist * r_max;
        const int g_here = rel_dist * g_max;
        const int b_here = rel_dist * b_max;
        assert( r_here >= 0);
        assert( r_here < 256);
        assert( g_here >= 0);
        assert( g_here < 256);
        assert( b_here >= 0);
        assert( b_here < 256);
        line[x*4+3] = 255; //Alpha value
        line[x*4+2] = r_here; //Red
        line[x*4+1] = g_here; //Green
        line[x*4+0] = b_here; //Blue
      }
      else
      {
        line[x*4+3] = 0; //Alpha value
        line[x*4+2] = 0; //Red
        line[x*4+1] = 0; //Green
        line[x*4+0] = 0; //Blue
      }
    }
  }
  pixmap = pixmap.fromImage(image);

  //Add transparency
  const QBitmap mask = pixmap.createMaskFromColor(QColor(0,0,0,0).rgb());
  pixmap.setMask(mask);

  return pixmap;
}

void ribi::QtPerfectElasticCollisionMainDialog::Paint(
  QPixmap& pixmap,
  const unsigned char r,
  const unsigned char g,
  const unsigned char b,
  const unsigned char a)
{
  const int width = pixmap.width();
  const int height = pixmap.height();

  QImage image = pixmap.toImage();

  assert(image.bytesPerLine() / width == 4
    && "Assume there are 4 bytes per pixel");

  for (int y=0; y!=height; ++y)
  {
    unsigned char * const line
      = static_cast<unsigned char *>(image.scanLine(y));
    for (int x=0; x!=width; ++x)
    {
      line[x*4+3] = a; //Alpha value
      line[x*4+2] = r; //Red
      line[x*4+1] = g; //Green
      line[x*4+0] = b; //Blue
    }
  }
  pixmap = pixmap.fromImage(image);
}

//From http://www.richelbilderbeek.nl/CppDoPerfectElasticCollision.htm
void ribi::QtPerfectElasticCollisionMainDialog::DoPerfectElasticCollision(
  const double angleCollision,
  double& angle1,
  double& speed1,
  double& angle2,
  double& speed2)
{
  const double pi = boost::math::constants::pi<double>();
  //The length of the impulse of player 1 (assumes both players have equal mass!)
  const double A = speed1;
  //The length of the impulse of player 2 (assumes both players have equal mass!)
  const double E = speed2;
  //The angles between the two globes
  const double c = angleCollision;
  //The angle between c and the impulse direction of player 1
  const double a = c - angle1;
  //The angle between c and the impulse direction of player 2
  const double b = c + pi - angle2;

  //Seperate the impulses to their impulses paralel and othoganal the angle of collision
  //The length of the impulse of player 1 parallel to the collision
  const double B = A * std::cos(a);
  //The length of the impulse of player 1 orthogonal to the collision
  const double C = A * std::sin(a);
  //The length of the impulse of player 2 parallel to the collision
  const double F = E * std::cos(b);
  //The length of the impulse of player 2 orthogonal to the collision
  const double G = E * std::sin(b);

  //Seperate the impulses in X and Y directions
  const double BdX = B *  std::sin(c + (0.0 * pi));
  const double BdY = B * -std::cos(c + (0.0 * pi));
  const double CdX = C *  std::sin(c + (1.5 * pi));
  const double CdY = C * -std::cos(c + (1.5 * pi));
  const double FdX = F *  std::sin(c + (1.0 * pi));
  const double FdY = F * -std::cos(c + (1.0 * pi));
  const double GdX = G *  std::sin(c + (0.5 * pi));
  const double GdY = G * -std::cos(c + (0.5 * pi));

  //The resulting impulses
  //The resulting impulse of player 1 in the X direction
  const double DdX = CdX + FdX;
  //The resulting impulse of player 1 in the Y direction
  const double DdY = CdY + FdY;
  //The resulting impulse of player 2 in the X direction
  const double HdX = BdX + GdX;
  //The resulting impulse of player 2 in the Y direction
  const double HdY = BdY + GdY;

  //Write the final results
  angle1 = GetAngle(DdX, DdY);
  angle2 = GetAngle(HdX, HdY);
  speed1 = std::sqrt( (DdX * DdX) + (DdY * DdY) ); //Pythagoras
  speed2 = std::sqrt( (HdX * HdX) + (HdY * HdY) ); //Pythagoras
}

double ribi::QtPerfectElasticCollisionMainDialog::GetAngle(const double dx, const double dy)
{
  return Geometry().GetAngleClockScreen(dx,dy);
}

#ifndef NDEBUG
void ribi::QtPerfectElasticCollisionMainDialog::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
}
#endif

 

 

 

 

 

./ToolPerfectElasticCollision/qtperfectelasticcollisionmenudialog.h

 

//---------------------------------------------------------------------------
/*
PerfectElasticCollision, tool to investigate a perfect elastic collision
Copyright (C) 2010-2015 Richel Bilderbeek

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 <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From hhtp://www.richelbilderbeek.nl/ToolPerfectElasticCollision.htm
//---------------------------------------------------------------------------
#ifndef QTPERFECTELASTICCOLLISIONMENUDIALOG_H
#define QTPERFECTELASTICCOLLISIONMENUDIALOG_H

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "qthideandshowdialog.h"
#pragma GCC diagnostic pop

namespace Ui {
  class QtPerfectElasticCollisionMenuDialog;
}

namespace ribi {

class QtPerfectElasticCollisionMenuDialog : public QtHideAndShowDialog
{
  Q_OBJECT

public:
  explicit QtPerfectElasticCollisionMenuDialog(QWidget *parent = 0);
  QtPerfectElasticCollisionMenuDialog(const QtPerfectElasticCollisionMenuDialog&) = delete;
  QtPerfectElasticCollisionMenuDialog& operator=(const QtPerfectElasticCollisionMenuDialog&) = delete;
  ~QtPerfectElasticCollisionMenuDialog() noexcept;

private slots:

  void on_button_start_clicked();
  void on_button_about_clicked();
  void on_button_quit_clicked() noexcept;

private:
  Ui::QtPerfectElasticCollisionMenuDialog *ui;

  #ifndef NDEBUG
  static void Test() noexcept;
  #endif
};

} //~namespace ribi

#endif // QTPERFECTELASTICCOLLISIONMENUDIALOG_H

 

 

 

 

 

./ToolPerfectElasticCollision/qtperfectelasticcollisionmenudialog.cpp

 

//---------------------------------------------------------------------------
/*
PerfectElasticCollision, tool to investigate a perfect elastic collision
Copyright (C) 2010-2015 Richel Bilderbeek

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 <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
//From hhtp://www.richelbilderbeek.nl/ToolPerfectElasticCollision.htm
//---------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#include "qtperfectelasticcollisionmenudialog.h"

#include "perfectelasticcollisionmenudialog.h"
#include "qtaboutdialog.h"
#include "qtperfectelasticcollisionmaindialog.h"
#include "ui_qtperfectelasticcollisionmenudialog.h"
#pragma GCC diagnostic pop

ribi::QtPerfectElasticCollisionMenuDialog::QtPerfectElasticCollisionMenuDialog(QWidget *parent)
  : QtHideAndShowDialog(parent),
    ui(new Ui::QtPerfectElasticCollisionMenuDialog)
{
  #ifndef NDEBUG
  Test();
  #endif
  ui->setupUi(this);
}

ribi::QtPerfectElasticCollisionMenuDialog::~QtPerfectElasticCollisionMenuDialog() noexcept
{
  delete ui;
}

void ribi::QtPerfectElasticCollisionMenuDialog::on_button_start_clicked()
{
  QtPerfectElasticCollisionMainDialog d;
  this->ShowChild(&d);
}

void ribi::QtPerfectElasticCollisionMenuDialog::on_button_about_clicked()
{
  About a = PerfectElasticCollisionMenuDialog().GetAbout();
  //a.AddLibrary("QtDialWidget version: " + QtDialWidget::GetVersion());
  QtAboutDialog d(a);
  this->ShowChild(&d);
}

void ribi::QtPerfectElasticCollisionMenuDialog::on_button_quit_clicked() noexcept
{
  close();
}

#ifndef NDEBUG
void ribi::QtPerfectElasticCollisionMenuDialog::Test() noexcept
{
  {
    static bool is_tested{false};
    if (is_tested) return;
    is_tested = true;
  }
  {
    QtPerfectElasticCollisionMainDialog d;
  }
}
#endif

 

 

 

 

 

Go back to Richel Bilderbeek's C++ page.

Go back to Richel Bilderbeek's homepage.

 

Valid XHTML 1.0 Strict

This page has been created by the tool CodeToHtml