Skip to content
Snippets Groups Projects
particles.cpp 11.35 KiB
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/ba3d/model/particles.cpp
//! @brief     Implements Particle class
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "GUI/ba3d/model/particles.h"
#include <cmath>

namespace GUI::RealSpace::Particles {

QString const& name(EShape k)
{
    static QString names[] = {"",
                              "BarGauss",
                              "BarLorentz",
                              "Bipyramid4",
                              "Box",
                              "CantellatedCube",
                              "Cone",
                              "CosineRippleBox",
                              "CosineRippleGauss",
                              "CosineRippleLorentz",
                              "Cylinder",
                              "Dodecahedron",
                              "EllipsoidalCylinder",
                              "Sphere",
                              "Spheroid",
                              "HemiEllipsoid",
                              "HorizontalCylinder",
                              "Icosahedron",
                              "PlatonicOctahedron",
                              "PlatonicTetrahedron",
                              "Prism3",
                              "Prism6",
                              "Pyramid2",
                              "Pyramid3",
                              "Pyramid4",
                              "Pyramid6",
                              "SawtoothRippleBox",
                              "SawtoothRippleGauss",
                              "SawtoothRippleLorentz",
                              "TruncatedCube",
                              "TruncatedSphere",
                              "TruncatedSpheroid"};
    return names[uint(k)];
}

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

using namespace GeometricID;

Particle::Particle(Key key)
    : Object(key)
    , scale(F3(1, 1, 1))
{
}

void Particle::set()
{
    transform(F3(0, 0, 0), F3(0, 0, 0));
}

void Particle::transform(F3 rotate_, F3 translate_)
{
    Object::transform(turn, scale, (rotate = rotate_), offset + (translate = translate_));
}

void Particle::fancy(F3 rotate, float r)
{
    Object::transform(turn, scale * r, rotate, offset + translate);
}

void Particle::addTransform(F3 rotate_, F3 translate_)
{
    Object::transform(turn, scale, (rotate = rotate + rotate_),
                      offset + (translate = translate + translate_));
}

void Particle::addTranslation(F3 translate_)
{
    Object::transform(turn, scale, rotate, offset + (translate = translate + translate_));
}

void Particle::addExtrinsicRotation(F3 rotateExtrinsic)
{
    Object::addExtrinsicRotation(turn, scale, rotate, rotateExtrinsic,
                                 (translate = offset + translate));
}

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

static float const pi = float(M_PI);
static float const pi2f = float(M_PI_2);
static float const sqrt2f = std::sqrt(2.f);
static float const sqrt3f = std::sqrt(3.f);

// see ~/BornAgain/GUI/ba3d/ba3d/model/geometry/ for BaseShape construction

// TODO : issue #269 : wrong BaseShape model. Now Pyramid2 always has top vertex. The true Pyramid2
// should have top edge if L!=W.
Pyramid2::Pyramid2(float L, float W, float H, float alpha)
    : Particle(Key(BaseShape::Column, (1.0f - H / (std::min(L, W) / 2 * std::tan(alpha))), 4))
{
    isNull = (L <= 0 || W <= 0 || H <= 0 || alpha <= 0);
    turn = F3(0, 0, 45 * pi / 180.0f);
    scale = F3(L * sqrt2f, W * sqrt2f, H);
    offset = F3(0, 0, 0);
    set();
}

BarGauss::BarGauss(float L, float W, float H)
    : Particle(Key(BaseShape::Column, 1.0f, 4))
{
    isNull = (L < 0 || W < 0 || H < 0) || (L <= 0 && W <= 0 && H <= 0);
    turn = F3(0, 0, 45 * pi / 180.0f);
    scale = F3(L * sqrt2f, W * sqrt2f, H);
    offset = F3(0, 0, 0);
    set();
}

BarLorentz::BarLorentz(float L, float W, float H)
    : Particle(Key(BaseShape::Column, 1.0f, 4))
{
    isNull = (L < 0 || W < 0 || H < 0) || (L <= 0 && W <= 0 && H <= 0);
    turn = F3(0, 0, 45 * pi / 180.0f);
    scale = F3(L * sqrt2f, W * sqrt2f, H);
    offset = F3(0, 0, 0);
    set();
}

Box::Box(float L, float W, float H)
    : Particle(Key(BaseShape::Column, 1.0f, 4))
{
    isNull = (L < 0 || W < 0 || H < 0) || (L <= 0 && W <= 0 && H <= 0);
    turn = F3(0, 0, 45 * pi / 180.0f);
    scale = F3(L * sqrt2f, W * sqrt2f, H);
    offset = F3(0, 0, 0);
    set();
}

Cone::Cone(float R, float H, float alpha)
    : Particle(Key(BaseShape::Column, (1.0f - H / (R * std::tan(alpha))), 0))
{
    isNull = (R <= 0 || H <= 0 || alpha <= 0);
    scale = F3(R * 2, R * 2, H);
    offset = F3(0, 0, 0);
    set();
}

Pyramid6::Pyramid6(float R, float H, float alpha)
    : Particle(Key(BaseShape::Column, (1.0f - H / (R * sqrt3f / 2 * std::tan(alpha))), 6))
{
    isNull = (R <= 0 || H <= 0 || alpha <= 0);
    scale = F3(R * 2, R * 2, H);
    offset = F3(0, 0, 0);
    set();
}

Bipyramid4::Bipyramid4(float L, float H, float rH, float alpha)
    : Particle(Key(BaseShape::Bipyramid4, rH, alpha, H / L))
{
    isNull = (L <= 0 || H <= 0 || rH <= 0 || alpha >= pi2f);
    scale = F3(L, L, L);
    offset = F3(0, 0, 0);
    set();
}

Cylinder::Cylinder(float R, float H)
    : Particle(Key(BaseShape::Column, 1.0f, 0))
{
    isNull = (R <= 0 || H <= 0);
    scale = F3(R * 2, R * 2, H);
    offset = F3(0, 0, 0);
    set();
}

Dodecahedron::Dodecahedron(float L)
    : Particle(Key(BaseShape::Dodecahedron))
{
    isNull = (L <= 0);
    float R = L / DodecahedronL2R;
    scale = F3(R * 2, R * 2, R * 2);
    offset = F3(0, 0, 0);
    set();
}

EllipsoidalCylinder::EllipsoidalCylinder(float Ra, float Rb, float H)
    : Particle(Key(BaseShape::Column, 1.0f, 0))
{
    isNull = (Ra <= 0 || Rb <= 0 || H <= 0);
    scale = F3(Ra * 2, Rb * 2, H);
    offset = F3(0, 0, 0);
    set();
}

Sphere::Sphere(float R)
    : Particle(Key(BaseShape::Sphere, 0, 0.5f))
{
    isNull = (R <= 0);
    float D = 2 * R;
    scale = F3(D, D, D);
    offset = F3(0, 0, 0);
    set();
}

Spheroid::Spheroid(float R, float H)
    : Particle(Key(BaseShape::Sphere, 0, 0.5f))
{
    isNull = (R <= 0 || H <= 0);
    scale = F3(R * 2, R * 2, H);
    offset = F3(0, 0, 0);
    set();
}

HemiEllipsoid::HemiEllipsoid(float Ra, float Rb, float H)
    : Particle(Key(BaseShape::Sphere, .5f, 0.0f))
{
    isNull = (Ra <= 0 || Rb <= 0 || H <= 0);
    scale = F3(Ra * 2, Rb * 2, H * 2);
    offset = F3(0, 0, 0);
    set();
}

Icosahedron::Icosahedron(float L)
    : Particle(Key(BaseShape::Icosahedron))
{
    isNull = (L <= 0);
    scale = F3(L, L, L);
    offset = F3(0, 0, 0);
    set();
}

Prism3::Prism3(float L, float H)
    : Particle(Key(BaseShape::Column, 1.0f, 3))
{
    isNull = (L <= 0 || H <= 0);
    float D = L / sqrt3f;
    scale = F3(D * 2, D * 2, H);
    offset = F3(0, 0, 0);
    set();
}

Prism6::Prism6(float R, float H)
    : Particle(Key(BaseShape::Column, 1.0f, 6))
{
    isNull = (R <= 0 || H <= 0);
    scale = F3(R * 2, R * 2, H);
    offset = F3(0, 0, 0);
    set();
}

Pyramid4::Pyramid4(float L, float H, float alpha)
    : Particle(Key(BaseShape::Column, (1.0f - H / (L / 2 * std::tan(alpha))), 4))
{
    isNull = (L <= 0 || H <= 0 || alpha <= 0);
    float L2 = L * sqrt2f;
    turn = F3(0, 0, 45 * pi / 180.0f);
    scale = F3(L2, L2, H);
    offset = F3(0, 0, 0);
    set();
}

CosineRippleBox::CosineRippleBox(float L, float W, float H)
    : Particle(Key(BaseShape::Ripple, 0, 0))
{
    isNull = (L < 0 || W < 0 || H < 0) || (L <= 0 && W <= 0 && H <= 0);
    turn = F3(0, 0, 0);
    scale = F3(L, W, H);
    offset = F3(0, 0, 0);
    set();
}

CosineRippleGauss::CosineRippleGauss(float L, float W, float H)
    : Particle(Key(BaseShape::Ripple, 0, 0))
{
    isNull = (L < 0 || W < 0 || H < 0) || (L <= 0 && W <= 0 && H <= 0);
    turn = F3(0, 0, 0);
    scale = F3(L, W, H);
    offset = F3(0, 0, 0);
    set();
}

CosineRippleLorentz::CosineRippleLorentz(float L, float W, float H)
    : Particle(Key(BaseShape::Ripple, 0, 0))
{
    isNull = (L < 0 || W < 0 || H < 0) || (L <= 0 && W <= 0 && H <= 0);
    turn = F3(0, 0, 0);
    scale = F3(L, W, H);
    offset = F3(0, 0, 0);
    set();
}

SawtoothRippleBox::SawtoothRippleBox(float L, float W, float H)
    : Particle(Key(BaseShape::Ripple, 0, 0))
{
    isNull = (L < 0 || W < 0 || H < 0) || (L <= 0 && W <= 0 && H <= 0);
    turn = F3(0, 0, 0);
    scale = F3(L, W, H);
    offset = F3(0, 0, 0);
    set();
}

SawtoothRippleGauss::SawtoothRippleGauss(float L, float W, float H)
    : Particle(Key(BaseShape::Ripple, 0, 0))
{
    isNull = (L < 0 || W < 0 || H < 0) || (L <= 0 && W <= 0 && H <= 0);
    turn = F3(0, 0, 0);
    scale = F3(L, W, H);
    offset = F3(0, 0, 0);
    set();
}

SawtoothRippleLorentz::SawtoothRippleLorentz(float L, float W, float H)
    : Particle(Key(BaseShape::Ripple, 0, 0))
{
    isNull = (L < 0 || W < 0 || H < 0) || (L <= 0 && W <= 0 && H <= 0);
    turn = F3(0, 0, 0);
    scale = F3(L, W, H);
    offset = F3(0, 0, 0);
    set();
}

Pyramid3::Pyramid3(float L, float H, float alpha)
    : Particle(Key(BaseShape::Column, (1.0f - H / (L / (2 * sqrt3f) * std::tan(alpha))), 3))
{
    isNull = (L <= 0 || H <= 0 || alpha <= 0);
    float D = L / sqrt3f;
    scale = F3(D * 2, D * 2, H);
    offset = F3(0, 0, 0);
    set();
}

TruncatedCube::TruncatedCube(float L, float t)
    : Particle(Key(BaseShape::TruncatedBox, 2 * t / L))
{
    isNull = (L <= 0);
    scale = F3(L, L, L);
    offset = F3(0, 0, 0);
    set();
}
TruncatedSphere::TruncatedSphere(float R, float H, float deltaH)
    : Particle(Key(BaseShape::Sphere, 1 - H / R / 2, (H - R) / R / 2, deltaH / R / 2))
{
    isNull = (R <= 0 || H <= 0);
    float D = 2 * R;
    scale = F3(D, D, D);
    offset = F3(0, 0, 0);
    set();
}

TruncatedSpheroid::TruncatedSpheroid(float R, float H, float fp, float deltaH)
    : Particle(
        Key(BaseShape::Sphere, 1 - H / fp / R / 2, (H - fp * R) / fp / R / 2, deltaH / fp / R / 2))
{
    isNull = (R <= 0 || H <= 0 || fp <= 0);
    scale = F3(R * 2, R * 2, fp * R * 2);
    offset = F3(0, 0, 0);
    set();
}

// TODO : issue #269 : change base shape to cantellated box
CantellatedCube::CantellatedCube(float L, float t)
    : Particle(Key(BaseShape::TruncatedBox, 2 * t / L))
{
    isNull = (L <= 0);
    scale = F3(L, L, L);
    offset = F3(0, 0, 0);
    set();
}

HorizontalCylinder::HorizontalCylinder(float R, float L, float s_b, float s_t)
    : Particle(Key(BaseShape::Column, 1.0f, 0))
{
    isNull = (R <= 0 || L <= 0 || s_b >= s_t);
    turn = F3(90 * pi / 180.0f, 90 * pi / 180.0f, 0);
    scale = F3(L, R * 2, R * 2);
    offset = F3(0, 0, 0);
    set();
}

PlatonicOctahedron::PlatonicOctahedron(float L)
    : Particle(Key(BaseShape::Bipyramid4, 1.0f, asin(sqrt(2.0f / 3)), 1.0f / sqrt(2.0f)))
{
    isNull = (L <= 0);
    scale = F3(L, L, L);
    offset = F3(0, 0, 0);
    set();
}

PlatonicTetrahedron::PlatonicTetrahedron(float L)
    : Particle(Key(BaseShape::Column, 0, 3))
{
    isNull = (L <= 0);
    float D = L / sqrt3f;
    scale = F3(D * 2, D * 2, L * sqrt(6.f) / 3);
    offset = F3(0, 0, 0);
    set();
}

} // namespace GUI::RealSpace::Particles