16 #include "Base/Const/Units.h"
22 #include "Sample/HardParticle/HardParticles.h"
23 #include "Sample/Particle/MesoCrystal.h"
24 #include "Sample/Particle/Particle.h"
25 #include "Sample/Particle/ParticleCoreShell.h"
31 bool isPositionInsideMesoCrystal(
const IFormFactor* outerShape, R3 positionInside)
34 if (
const auto* ff_Pyramid2 =
dynamic_cast<const Pyramid2*
>(outerShape)) {
35 double L = ff_Pyramid2->length();
36 double W = ff_Pyramid2->width();
37 double H = ff_Pyramid2->height();
38 double alpha = ff_Pyramid2->alpha();
42 - positionInside.z() / std::tan(alpha);
45 - positionInside.z() / std::tan(alpha);
46 if (std::abs(positionInside.x()) <= l_z && std::abs(positionInside.y()) <= w_z
47 && (positionInside.z() >= 0 && positionInside.z() <= H))
49 }
else if (
const auto* ff_BarGauss =
dynamic_cast<const BarGauss*
>(outerShape)) {
50 double L = ff_BarGauss->length();
51 double W = ff_BarGauss->width();
52 double H = ff_BarGauss->height();
54 if (std::abs(positionInside.x()) <= L / 2 && std::abs(positionInside.y()) <= W / 2
55 && (positionInside.z() >= 0 && positionInside.z() <= H))
57 }
else if (
const auto* ff_BarLorentz =
dynamic_cast<const BarLorentz*
>(outerShape)) {
58 double L = ff_BarLorentz->length();
59 double W = ff_BarLorentz->width();
60 double H = ff_BarLorentz->height();
62 if (std::abs(positionInside.x()) <= L / 2 && std::abs(positionInside.y()) <= W / 2
63 && (positionInside.z() >= 0 && positionInside.z() <= H))
65 }
else if (
const auto* ff_Box =
dynamic_cast<const Box*
>(outerShape)) {
66 double L = ff_Box->length();
67 double W = ff_Box->width();
68 double H = ff_Box->height();
70 if (std::abs(positionInside.x()) <= L / 2 && std::abs(positionInside.y()) <= W / 2
71 && (positionInside.z() >= 0 && positionInside.z() <= H))
73 }
else if (
const auto* ff_Cone =
dynamic_cast<const Cone*
>(outerShape)) {
74 double R = ff_Cone->radius();
75 double H = ff_Cone->height();
76 double alpha = ff_Cone->alpha();
78 if (std::abs(positionInside.x()) > R || std::abs(positionInside.y()) > R
79 || positionInside.z() < 0 || positionInside.z() > H)
82 double R_z = R - positionInside.z() / std::tan(alpha);
83 if (std::pow(positionInside.x() / R_z, 2) + std::pow(positionInside.y() / R_z, 2) <= 1)
85 }
else if (
const auto* ff_Pyramid6 =
dynamic_cast<const Pyramid6*
>(outerShape)) {
86 double B = ff_Pyramid6->baseEdge();
87 double H = ff_Pyramid6->height();
88 double alpha = ff_Pyramid6->alpha();
90 if (std::abs(positionInside.x()) > B || std::abs(positionInside.y()) > B
91 || positionInside.z() < 0 || positionInside.z() > H)
94 double l_z = B - positionInside.z() / std::tan(alpha);
95 double theta_prime = 0;
96 if (positionInside.x() != 0 || positionInside.y() != 0)
97 theta_prime = Units::rad2deg(std::asin(
98 std::abs(positionInside.y())
99 / std::sqrt(std::pow(positionInside.x(), 2) + std::pow(positionInside.y(), 2))));
100 int c =
static_cast<int>(theta_prime / 60);
101 double theta = Units::deg2rad(theta_prime - c * 60);
102 double k_z = l_z / (std::cos(theta) + std::sin(theta) / std::tan(M_PI / 3));
104 if (std::pow(positionInside.x(), 2) + std::pow(positionInside.y(), 2) <= std::pow(k_z, 2))
106 }
else if (
const auto* ff_Bipyramid4 =
dynamic_cast<const Bipyramid4*
>(outerShape)) {
107 double L = ff_Bipyramid4->length();
108 double H = ff_Bipyramid4->height();
109 double rH = ff_Bipyramid4->heightRatio();
110 double alpha = ff_Bipyramid4->alpha();
112 double total_Height = H + rH * H;
114 if (std::abs(positionInside.x()) > L / 2 || std::abs(positionInside.y()) > L / 2
115 || positionInside.z() < 0 || positionInside.z() > total_Height)
119 double l_z = L / 2 - std::abs(H - positionInside.z()) / std::tan(alpha);
120 if (std::abs(positionInside.x()) <= l_z && std::abs(positionInside.y()) <= l_z)
122 }
else if (
const auto* ff_Cylinder =
dynamic_cast<const Cylinder*
>(outerShape)) {
123 double R = ff_Cylinder->radius();
124 double H = ff_Cylinder->height();
126 if (std::abs(positionInside.x()) > R || std::abs(positionInside.y()) > R
127 || positionInside.z() < 0 || positionInside.z() > H)
130 if (std::pow(positionInside.x() / R, 2) + std::pow(positionInside.y() / R, 2) <= 1)
132 }
else if (
dynamic_cast<const Dodecahedron*
>(outerShape)) {
134 std::ostringstream ostr;
135 ostr <<
"Sorry, outer shape Dodecahedron not yet implemented for Mesocrystal";
136 ostr <<
"\n\nStay tuned!";
137 throw std::runtime_error(ostr.str());
138 }
else if (
const auto* ff_EllipsoidalCylinder =
140 double a = ff_EllipsoidalCylinder->radiusX();
141 double b = ff_EllipsoidalCylinder->radiusY();
142 double H = ff_EllipsoidalCylinder->height();
144 if (std::abs(positionInside.x()) > a || std::abs(positionInside.y()) > b
145 || positionInside.z() < 0 || positionInside.z() > H)
148 if (std::pow(positionInside.x() / a, 2) + std::pow(positionInside.y() / b, 2) <= 1)
150 }
else if (
const auto* ff_Sphere =
dynamic_cast<const Sphere*
>(outerShape)) {
151 double R = ff_Sphere->radius();
153 if (std::abs(positionInside.x()) > R || std::abs(positionInside.y()) > R
154 || positionInside.z() < 0 || positionInside.z() > 2 * R)
157 if (std::pow(positionInside.x() / R, 2) + std::pow(positionInside.y() / R, 2)
158 + std::pow((positionInside.z() - R) / R, 2)
161 }
else if (
const auto* ff_Spheroid =
dynamic_cast<const Spheroid*
>(outerShape)) {
162 double a = ff_Spheroid->radius();
163 double H = ff_Spheroid->height();
166 if (std::abs(positionInside.x()) > a || std::abs(positionInside.y()) > a
167 || positionInside.z() < 0 || positionInside.z() > H)
170 if (std::pow(positionInside.x() / a, 2) + std::pow(positionInside.y() / a, 2)
171 + std::pow((positionInside.z() - c) / c, 2)
174 }
else if (
const auto* ff_HemiEllipsoid =
dynamic_cast<const HemiEllipsoid*
>(outerShape)) {
175 double a = ff_HemiEllipsoid->radiusX();
176 double b = ff_HemiEllipsoid->radiusY();
177 double c = ff_HemiEllipsoid->height();
179 if (std::abs(positionInside.x()) > a || std::abs(positionInside.y()) > b
180 || positionInside.z() < 0 || positionInside.z() > c)
183 if (std::pow(positionInside.x() / a, 2) + std::pow(positionInside.y() / b, 2)
184 + std::pow(positionInside.z() / c, 2)
187 }
else if (
dynamic_cast<const Icosahedron*
>(outerShape)) {
189 std::ostringstream ostr;
190 ostr <<
"Sorry, outer shape Icosahedron not yet implemented for Mesocrystal";
191 ostr <<
"\n\nStay tuned!";
192 throw std::runtime_error(ostr.str());
193 }
else if (
const auto* ff_Prism3 =
dynamic_cast<const Prism3*
>(outerShape)) {
194 double B = ff_Prism3->baseEdge();
195 double H = ff_Prism3->height();
197 double l = B * std::sin(M_PI / 3);
198 double x_shift = B / 2 * std::tan(M_PI / 6);
200 if (positionInside.x() + x_shift < 0 || positionInside.x() + x_shift > l
201 || std::abs(positionInside.y()) > B / 2 || positionInside.z() < 0
202 || positionInside.z() > H)
206 if (positionInside.x() + x_shift != 0 || positionInside.y() != 0)
207 theta = std::asin(std::abs(positionInside.y())
208 / std::sqrt(std::pow(positionInside.x() + x_shift, 2)
209 + std::pow(positionInside.y(), 2)));
211 double k = l / (std::sin(theta) / std::tan(M_PI / 6) + std::cos(theta));
213 if (std::pow(positionInside.x() + x_shift, 2) + std::pow(positionInside.y(), 2)
216 }
else if (
const auto* ff_Prism6 =
dynamic_cast<const Prism6*
>(outerShape)) {
217 double B = ff_Prism6->baseEdge();
218 double H = ff_Prism6->height();
220 if (std::abs(positionInside.x()) > B || std::abs(positionInside.y()) > B
221 || positionInside.z() < 0 || positionInside.z() > H)
224 double theta_prime = 0;
225 if (positionInside.x() != 0 || positionInside.y() != 0)
226 theta_prime = Units::rad2deg(std::asin(
227 std::abs(positionInside.y())
228 / std::sqrt(std::pow(positionInside.x(), 2) + std::pow(positionInside.y(), 2))));
229 int c =
static_cast<int>(theta_prime / 60);
230 double theta = Units::deg2rad(theta_prime - c * 60);
231 double k_z = B / (std::cos(theta) + std::sin(theta) / std::tan(M_PI / 3));
233 if (std::pow(positionInside.x(), 2) + std::pow(positionInside.y(), 2) <= std::pow(k_z, 2))
235 }
else if (
const auto* ff_Pyramid4 =
dynamic_cast<const Pyramid4*
>(outerShape)) {
236 double B = ff_Pyramid4->baseEdge();
237 double H = ff_Pyramid4->height();
238 double alpha = ff_Pyramid4->alpha();
241 B / 2 - positionInside.z() / std::tan(alpha);
242 if (std::abs(positionInside.x()) <= l_z && std::abs(positionInside.y()) <= l_z
243 && (positionInside.z() >= 0 && positionInside.z() <= H))
247 std::ostringstream ostr;
248 ostr <<
"Sorry, outer shape CosineRippleBox not yet implemented for Mesocrystal";
249 ostr <<
"\n\nStay tuned!";
250 throw std::runtime_error(ostr.str());
253 std::ostringstream ostr;
254 ostr <<
"Sorry, outer shape CosineRippleGauss not yet implemented for Mesocrystal";
255 ostr <<
"\n\nStay tuned!";
256 throw std::runtime_error(ostr.str());
259 std::ostringstream ostr;
260 ostr <<
"Sorry, outer shape CosineRippleLorentz not yet implemented for Mesocrystal";
261 ostr <<
"\n\nStay tuned!";
262 throw std::runtime_error(ostr.str());
265 std::ostringstream ostr;
266 ostr <<
"Sorry, outer shape SawtoothRippleBox not yet implemented for Mesocrystal";
267 ostr <<
"\n\nStay tuned!";
268 throw std::runtime_error(ostr.str());
271 std::ostringstream ostr;
272 ostr <<
"Sorry, outer shape SawtoothRippleGauss not yet implemented for Mesocrystal";
273 ostr <<
"\n\nStay tuned!";
274 throw std::runtime_error(ostr.str());
277 std::ostringstream ostr;
278 ostr <<
"Sorry, outer shape SawtoothRippleLorentz not yet implemented for Mesocrystal";
279 ostr <<
"\n\nStay tuned!";
280 throw std::runtime_error(ostr.str());
281 }
else if (
const auto* ff_Pyramid3 =
dynamic_cast<const Pyramid3*
>(outerShape)) {
282 double B = ff_Pyramid3->baseEdge();
283 double H = ff_Pyramid3->height();
284 double alpha = ff_Pyramid3->alpha();
287 B - positionInside.z() * 2 / std::tan(alpha);
289 double l = B_z * std::sin(M_PI / 3);
290 double x_shift = B_z / 2 * std::tan(M_PI / 6);
292 if (positionInside.x() + x_shift < 0 || positionInside.x() + x_shift > l
293 || std::abs(positionInside.y()) > B_z / 2 || positionInside.z() < 0
294 || positionInside.z() > H)
298 if (positionInside.x() + x_shift != 0 || positionInside.y() != 0)
299 theta = std::asin(std::abs(positionInside.y())
300 / std::sqrt(std::pow(positionInside.x() + x_shift, 2)
301 + std::pow(positionInside.y(), 2)));
303 double k = l / (std::sin(theta) / std::tan(M_PI / 6) + std::cos(theta));
305 if (std::pow(positionInside.x() + x_shift, 2) + std::pow(positionInside.y(), 2)
310 std::ostringstream ostr;
311 ostr <<
"Sorry, outer shape Truncated cube not yet implemented for Mesocrystal";
312 ostr <<
"\n\nStay tuned!";
313 throw std::runtime_error(ostr.str());
314 }
else if (
const auto* ff_TruncatedSphere =
dynamic_cast<const TruncatedSphere*
>(outerShape)) {
315 double R = ff_TruncatedSphere->radius();
316 double H = ff_TruncatedSphere->height();
317 double deltaH = ff_TruncatedSphere->removedTop();
318 if (std::abs(positionInside.x()) > R || std::abs(positionInside.y()) > R
319 || positionInside.z() < 0 || positionInside.z() > (H - deltaH))
322 if (std::pow(positionInside.x() / R, 2) + std::pow(positionInside.y() / R, 2)
323 + std::pow((positionInside.z() - (H - R)) / R, 2)
328 std::ostringstream ostr;
329 ostr <<
"Sorry, outer shape Truncated spheroid not yet implemented for Mesocrystal";
330 ostr <<
"\n\nStay tuned!";
331 throw std::runtime_error(ostr.str());
334 std::ostringstream ostr;
335 ostr <<
"Sorry, outer shape Cantellated cube not yet implemented for Mesocrystal";
336 ostr <<
"\n\nStay tuned!";
337 throw std::runtime_error(ostr.str());
340 std::ostringstream ostr;
341 ostr <<
"Sorry, outer shape Horizontal cylinder not yet implemented for Mesocrystal";
342 ostr <<
"\n\nStay tuned!";
343 throw std::runtime_error(ostr.str());
346 std::ostringstream ostr;
347 ostr <<
"Sorry, outer shape Platonic octahedron not yet implemented for Mesocrystal";
348 ostr <<
"\n\nStay tuned!";
349 throw std::runtime_error(ostr.str());
352 std::ostringstream ostr;
353 ostr <<
"Sorry, outer shape Platonic tetrahedron not yet implemented for Mesocrystal";
354 ostr <<
"\n\nStay tuned!";
355 throw std::runtime_error(ostr.str());
364 const MesoCrystalItem* mesoCrystalItem,
double total_abundance,
const QVector3D& origin,
365 std::function<QColor(
const QString&)> fnColorFromMaterialName)
370 m_builderUtils = std::make_unique<GUI::RealSpace::BuilderUtils>(fnColorFromMaterialName);
377 std::unique_ptr<MesoCrystal> M_clone(mesoCrystal->clone());
385 const auto* mesoCrystal_rotation = M_clone->rotation();
386 auto mesoCrystal_translation = M_clone->particlePosition();
390 if (
dynamic_cast<const ParticleComposition*
>(particleBasis.get())) {
391 const auto* particleComposition =
392 dynamic_cast<const ParticleComposition*
>(particleBasis.get());
393 mesoCrystalBasis3DContainer =
395 }
else if (
dynamic_cast<const ParticleCoreShell*
>(particleBasis.get())) {
396 const auto* particleCoreShell =
dynamic_cast<const ParticleCoreShell*
>(particleBasis.get());
397 mesoCrystalBasis3DContainer =
399 }
else if (
dynamic_cast<const MesoCrystal*
>(particleBasis.get())) {
402 std::ostringstream ostr;
403 ostr <<
"Sorry, MesoCrystal inside MesoCrystal not yet implemented";
404 ostr <<
"\n\nStay tuned!";
405 throw std::runtime_error(ostr.str());
407 const auto* particle =
dynamic_cast<const Particle*
>(particleBasis.get());
408 mesoCrystalBasis3DContainer =
414 for (
int k = -n; k <= n; k++) {
415 for (
int j = -n; j <= n; j++) {
416 for (
int i = -n; i <= n; i++) {
417 auto positionInside = i * lattice.basisVectorA() + j * lattice.basisVectorB()
418 + k * lattice.basisVectorC();
420 if (isPositionInsideMesoCrystal(outerShapeff.get(), positionInside)) {
421 for (
size_t it = 0; it < mesoCrystalBasis3DContainer.
containerSize(); ++it) {
423 particle3D->addTranslation(
424 QVector3D(
static_cast<float>(positionInside.x()),
425 static_cast<float>(positionInside.y()),
426 static_cast<float>(positionInside.z())));
428 particle3D->addExtrinsicRotation(
430 mesoCrystal_rotation));
432 particle3D->addTranslation(
433 QVector3D(
static_cast<float>(mesoCrystal_translation.x()),
434 static_cast<float>(mesoCrystal_translation.y()),
435 static_cast<float>(mesoCrystal_translation.z())));
438 particle3D.release(), mesoCrystalBasis3DContainer.
particle3DBlend(it));
447 outerShape3D->addTransform(
448 m_builderUtils->implementParticleRotationfromIRotation(mesoCrystal_rotation),
449 QVector3D(
static_cast<float>(mesoCrystal_translation.x()),
450 static_cast<float>(mesoCrystal_translation.y()),
451 static_cast<float>(mesoCrystal_translation.z())));
455 color.setAlphaF(0.3);
456 outerShape3D->color = color;
457 mesoCrystal3DContainer.
addParticle(outerShape3D.release(),
true);
463 return mesoCrystal3DContainer;
Defines class MesoCrystalItem.
Implements namespace GUI::View::TransformTo3D.
Defines class ParticleCompositionItem.
Defines GUI::RealSpace::BuilderUtils namespace.
Defines GUI::RealSpace::BuilderUtils namespace.
std::unique_ptr< IFormFactor > getOuterShape() const
std::unique_ptr< MesoCrystal > createMesoCrystal() const
std::unique_ptr< IParticle > getBasis() const
Lattice3D getLattice() const
std::unique_ptr< GUI::RealSpace::Particles::Particle > createParticle(const size_t &index) const
void setCumulativeAbundance(double cumulativeAbundance)
void addParticle(GUI::RealSpace::Particles::Particle *particle3D, bool blend)
size_t containerSize() const
void setParticleType(QString particleType)
bool particle3DBlend(const size_t &index) const
std::unique_ptr< GUI::RealSpace::BuilderUtils > m_builderUtils
RealSpaceMesoCrystal(const MesoCrystalItem *mesoCrystalItem, double total_abundance, const QVector3D &origin, std::function< QColor(const QString &)> fnColorFromMaterialName)
Particle3DContainer populateMesoCrystal()
const MesoCrystalItem * m_mesoCrystalItem