PeriDEM 0.3.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
openRectChannel2D.cpp
Go to the documentation of this file.
1/*
2 * -------------------------------------------
3 * Copyright (c) 2021 - 2026 Prashant K. Jha
4 * -------------------------------------------
5 * PeriDEM https://github.com/prashjha/PeriDEM
6 *
7 * Distributed under the Boost Software License, Version 1.0.
8 */
9
10#include "openRectChannel2D.h"
11#include "geomUtilFunctions.h"
12#include "util/function.h"
13#include "util/io.h"
14#include "util/vecMethods.h"
15#include <algorithm>
16#include <cmath>
17#include <limits>
18#include <sstream>
19#include <stdexcept>
20
21namespace geom {
22
23namespace {
24
25void validateParams(double x0, double y0, double x1, double y1, double t) {
26 constexpr double eps = 1.0e-12;
27 if (!(x1 > x0 + eps && y1 > y0 + eps && t > eps))
28 throw std::runtime_error(
29 "OpenRectChannel2D: require x0 < x1, y0 < y1, t > 0.");
30 if (!(x1 - x0 > 2. * t + eps && y1 - y0 > 2. * t + eps))
31 throw std::runtime_error(
32 "OpenRectChannel2D: require x1-x0 > 2t and y1-y0 > 2t so the U-channel exists.");
33}
34
35double distPointToSegment2D(const util::Point &p, const util::Point &a, const util::Point &b) {
36 const util::Point ab = b - a;
37 const util::Point ap = p - a;
38 const double L2 = ab * ab;
39 if (L2 < 1.0e-30)
40 return ap.length();
41 double s = (ap * ab) / L2;
42 s = std::max(0., std::min(1., s));
43 const util::Point proj = a + s * ab;
44 return (p - proj).length();
45}
46
47} // namespace
48
50 : GeomObject("open_rect_channel_2d", "") {
51}
52
53OpenRectChannel2D::OpenRectChannel2D(double x0, double y0, double x1, double y1, double t,
54 double z, std::string description)
55 : GeomObject("open_rect_channel_2d", std::move(description)),
56 d_x0(x0),
57 d_y0(y0),
58 d_x1(x1),
59 d_y1(y1),
60 d_t(t),
61 d_z(z) {
62 validateParams(x0, y0, x1, y1, t);
64}
65
67 : GeomObject(other.d_name, other.d_description),
68 d_x0(other.d_x0),
69 d_y0(other.d_y0),
70 d_x1(other.d_x1),
71 d_y1(other.d_y1),
72 d_t(other.d_t),
73 d_z(other.d_z),
74 d_vertices(other.d_vertices),
75 d_x(other.d_x) {
76 d_tags = other.d_tags;
77}
78
80 if (this != &other) {
81 d_tags = other.d_tags;
82 d_x0 = other.d_x0;
83 d_y0 = other.d_y0;
84 d_x1 = other.d_x1;
85 d_y1 = other.d_y1;
86 d_t = other.d_t;
87 d_z = other.d_z;
88 d_vertices = other.d_vertices;
89 d_x = other.d_x;
90 }
91 return *this;
92}
93
95 const double x0 = d_x0, y0 = d_y0, x1 = d_x1, y1 = d_y1, t = d_t, z = d_z;
96 d_vertices.clear();
97 d_vertices.reserve(10);
98 // CCW boundary of U-shaped solid with uniform wall thickness t everywhere: bottom slab
99 // [x0,x1]×[y0,y0+t], left/right columns [x0,x0+t]×[y0+t,y1] and [x1-t,x1]×[y0+t,y1]. Cavity
100 // (x0+t,x1-t)×(y0+t,y1) open at +y. Flat tops at y=y1 on each side wall.
101 d_vertices.push_back({x0, y0, z});
102 d_vertices.push_back({x1, y0, z});
103 d_vertices.push_back({x1, y1, z});
104 d_vertices.push_back({x1 - t, y1, z});
105 d_vertices.push_back({x1 - t, y1 - t, z});
106 d_vertices.push_back({x1 - t, y0 + t, z});
107 d_vertices.push_back({x0 + t, y0 + t, z});
108 d_vertices.push_back({x0 + t, y1 - t, z});
109 d_vertices.push_back({x0 + t, y1, z});
110 d_vertices.push_back({x0, y1, z});
112}
113
115 const auto &v = d_vertices;
116 if (v.size() < 3)
117 return false;
118 bool c = false;
119 const size_t n = v.size();
120 for (size_t i = 0, j = n - 1; i < n; j = i++) {
121 const double xi = v[i].d_x, yi = v[i].d_y;
122 const double xj = v[j].d_x, yj = v[j].d_y;
123 if (((yi > p.d_y) != (yj > p.d_y)) &&
124 (p.d_x < (xj - xi) * (p.d_y - yi) / (yj - yi + 1.0e-30) + xi))
125 c = !c;
126 }
127 return c;
128}
129
131 const auto &v = d_vertices;
132 if (v.size() < 3)
133 return 0.;
134 double a = 0.;
135 const size_t n = v.size();
136 for (size_t i = 0; i < n; ++i) {
137 const size_t j = (i + 1) % n;
138 a += v[i].d_x * v[j].d_y - v[j].d_x * v[i].d_y;
139 }
140 return 0.5 * std::abs(a);
141}
142
144 const auto &v = d_vertices;
145 if (v.size() < 3)
146 return {};
147 double cx = 0., cy = 0.;
148 double a = 0.;
149 const size_t n = v.size();
150 for (size_t i = 0; i < n; ++i) {
151 const size_t j = (i + 1) % n;
152 const double cross = v[i].d_x * v[j].d_y - v[j].d_x * v[i].d_y;
153 a += cross;
154 cx += (v[i].d_x + v[j].d_x) * cross;
155 cy += (v[i].d_y + v[j].d_y) * cross;
156 }
157 if (std::abs(a) < 1.0e-30)
158 return {(v[0].d_x + v[1].d_x) * 0.5, (v[0].d_y + v[1].d_y) * 0.5, v[0].d_z};
159 a *= 0.5;
160 return {cx / (6. * a), cy / (6. * a), v[0].d_z};
161}
162
163void OpenRectChannel2D::transform(const util::Point &translation, const double &scale,
164 const double &angle, const util::Point &axis,
165 const util::Point *rotationPoint) {
166 // Default pivot: cached centroid `d_x` (same as other geoms). Matches demModel when it passes
167 // p_geom->center().
168 const util::Point pivot = rotationPoint != nullptr ? *rotationPoint : d_x;
169 d_t *= scale;
170 // Same map as geom::mapSimilarity: p + s R(x-p) + t
171 for (auto &v : d_vertices) {
172 v = pivot + util::rotate(v - pivot, angle, axis) * scale + translation;
173 }
174 d_x0 = d_x1 = d_vertices[0].d_x;
175 d_y0 = d_y1 = d_vertices[0].d_y;
176 d_z = d_vertices[0].d_z;
177 for (const auto &v : d_vertices) {
178 d_x0 = std::min(d_x0, v.d_x);
179 d_x1 = std::max(d_x1, v.d_x);
180 d_y0 = std::min(d_y0, v.d_y);
181 d_y1 = std::max(d_y1, v.d_y);
182 d_z = v.d_z;
183 }
185}
186
188 return polygonArea2D();
189}
190
192
193std::pair<util::Point, util::Point> OpenRectChannel2D::box() const {
194 return box(0.);
195}
196
197std::pair<util::Point, util::Point> OpenRectChannel2D::box(const double &tol) const {
198 util::Point lo(std::numeric_limits<double>::max(), std::numeric_limits<double>::max(),
199 std::numeric_limits<double>::max());
200 util::Point hi(-std::numeric_limits<double>::max(), -std::numeric_limits<double>::max(),
201 -std::numeric_limits<double>::max());
202 for (const auto &v : d_vertices) {
203 lo.d_x = std::min(lo.d_x, v.d_x);
204 lo.d_y = std::min(lo.d_y, v.d_y);
205 lo.d_z = std::min(lo.d_z, v.d_z);
206 hi.d_x = std::max(hi.d_x, v.d_x);
207 hi.d_y = std::max(hi.d_y, v.d_y);
208 hi.d_z = std::max(hi.d_z, v.d_z);
209 }
210 return {lo - tol, hi + tol};
211}
212
214 return 0.5 * d_t;
215}
216
218 const util::Point &c = d_x;
219 double r = 0.;
220 for (const auto &v : d_vertices)
221 r = std::max(r, (v - c).length());
222 return r;
223}
224
226 if (std::abs(x.d_z - d_z) > 1.0e-9)
227 return false;
228 return pointInPolygon2D(x);
229}
230
232 return !isInside(x);
233}
234
235bool OpenRectChannel2D::isNear(const util::Point &x, const double &tol) const {
236 auto bbox = box(tol);
237 return geom::isPointInsideBox(x, 2, bbox);
238}
239
240bool OpenRectChannel2D::isNearBoundary(const util::Point &x, const double &tol,
241 const bool &within) const {
242 if (!isNear(x, within ? 0. : tol))
243 return false;
244 const size_t n = d_vertices.size();
245 for (size_t i = 0; i < n; ++i) {
246 const util::Point &a = d_vertices[i];
247 const util::Point &b = d_vertices[(i + 1) % n];
248 if (util::isLess(distPointToSegment2D(x, a, b), tol))
249 return true;
250 }
251 return false;
252}
253
255 return isNearBoundary(x, 1.0e-8, false);
256}
257
258bool OpenRectChannel2D::isInside(const std::pair<util::Point, util::Point> &bx) const {
259 for (auto p : geom::getCornerPoints(2, bx))
260 if (!this->isInside(p))
261 return false;
262 return true;
263}
264
265bool OpenRectChannel2D::isOutside(const std::pair<util::Point, util::Point> &bx) const {
266 bool intersect = false;
267 for (auto p : geom::getCornerPoints(2, bx))
268 if (!intersect)
269 intersect = this->isInside(p);
270 return !intersect;
271}
272
273bool OpenRectChannel2D::isNear(const std::pair<util::Point, util::Point> &bx,
274 const double &tol) const {
275 return geom::areBoxesNear(this->box(), bx, tol, 2);
276}
277
278bool OpenRectChannel2D::doesIntersect(const std::pair<util::Point, util::Point> &bx) const {
279 for (auto p : geom::getCornerPoints(2, bx))
280 if (this->isInside(p))
281 return true;
282 return false;
283}
284
285std::string OpenRectChannel2D::printStr(int nt, int lvl) const {
286 auto tabS = util::io::getTabS(nt);
287 std::ostringstream oss;
288 oss << tabS << "------- OpenRectChannel2D (U-channel, open +y) --------" << std::endl;
289 oss << tabS << "Outer box: [" << d_x0 << "," << d_y0 << "] — [" << d_x1 << "," << d_y1 << "], z="
290 << d_z << ", t=" << d_t << std::endl;
291 if (lvl > 0)
292 oss << tabS << "Vertices = " << util::io::printStr(d_vertices, 0) << std::endl;
293 return oss.str();
294}
295
296} // namespace geom
Defines abstract geometrical domain.
std::vector< std::string > d_tags
Tags/attributes about the object.
2D U-shaped cavity: thick rectangular frame with the top (+y) side open.
std::pair< util::Point, util::Point > box() const override
Computes the bounding box of object.
bool pointInPolygon2D(const util::Point &p) const
bool isInside(const util::Point &x) const override
Checks if point is inside this object.
double inscribedRadius() const override
Computes the radius of biggest circle/sphere completely within the object.
util::Point center() const override
Computes the center of object.
util::Point polygonCentroid2D() const
OpenRectChannel2D & operator=(const OpenRectChannel2D &other)
void transform(const util::Point &translation, const double &scale, const double &angle, const util::Point &axis, const util::Point *rotationPoint) override
Similarity about pivot (default: old center d_x), then rigid displacement = translation: ....
std::vector< util::Point > d_vertices
CCW boundary of the U-shaped solid (10 vertices, uniform thickness t).
std::string printStr(int nt=0, int lvl=0) const override
Returns the string containing printable information about the object.
bool doesIntersect(const util::Point &x) const override
Checks if point lies exactly on the boundary.
bool isOutside(const util::Point &x) const override
Checks if point is outside of this object.
bool isNearBoundary(const util::Point &x, const double &tol, const bool &within) const override
Checks if point is within given distance of this object.
double boundingRadius() const override
Computes the radius of smallest circle/sphere such that object can be fit into it.
util::Point d_x
Area centroid of the polygon (same convention as d_x on other GeomObjects).
bool isNear(const util::Point &x, const double &tol) const override
Checks if point is within given distance of this object.
double volume() const override
Computes the volume (area in 2d, length in 1d) of object.
double distPointToSegment2D(const util::Point &p, const util::Point &a, const util::Point &b)
bool isPointInsideBox(util::Point x, size_t dim, const std::pair< util::Point, util::Point > &box)
Returns true if point is inside box.
bool areBoxesNear(const std::pair< util::Point, util::Point > &b1, const std::pair< util::Point, util::Point > &b2, const double &tol, size_t dim)
Checks if given two boxes are within given distance from each other.
std::vector< util::Point > getCornerPoints(size_t dim, const std::pair< util::Point, util::Point > &box)
Returns all corner points in the box.
std::string getTabS(int nt)
Returns tab spaces of a given size.
Definition io.h:39
std::string printStr(const T &msg, int nt=print_default_tab)
Returns formatted string for output.
Definition io.h:53
bool isLess(const double &a, const double &b)
Returns true if a < b.
Definition function.cpp:20
util::Point rotate(const util::Point &p, const double &theta, const util::Point &axis)
Returns the vector after rotating by desired angle.
A structure to represent 3d vectors.
Definition point.h:30
double d_y
the y coordinate
Definition point.h:36
double d_z
the z coordinate
Definition point.h:39
double length() const
Computes the Euclidean length of the vector.
Definition point.h:124
double d_x
the x coordinate
Definition point.h:33