OOFEM 3.0
Loading...
Searching...
No Matches
geometry.C
Go to the documentation of this file.
1/*
2 *
3 * ##### ##### ###### ###### ### ###
4 * ## ## ## ## ## ## ## ### ##
5 * ## ## ## ## #### #### ## # ##
6 * ## ## ## ## ## ## ## ##
7 * ## ## ## ## ## ## ## ##
8 * ##### ##### ## ###### ## ##
9 *
10 *
11 * OOFEM : Object Oriented Finite Element Code
12 *
13 * Copyright (C) 1993 - 2025 Borek Patzak
14 *
15 *
16 *
17 * Czech Technical University, Faculty of Civil Engineering,
18 * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19 *
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 */
34
35#include "mathfem.h"
36#include "geometry.h"
37#include "element.h"
38#include "dofmanager.h"
39#include "classfactory.h"
40#include "inputrecord.h"
41#include "dynamicinputrecord.h"
42#include "xfem/xfemtolerances.h"
43#include "feinterpol.h"
44#include "xfem/tipinfo.h"
45
46
47#include <fstream>
48#include <limits>
49
50namespace oofem {
58
59BasicGeometry :: BasicGeometry(const BasicGeometry &iBasicGeometry) :
60 mVertices(iBasicGeometry.mVertices)
61{ }
62
63BasicGeometry :: ~BasicGeometry()
64{ }
65
66
67void BasicGeometry :: removeDuplicatePoints(const double &iTolSquare)
68{
69 if ( mVertices.size() > 1 ) {
70 for ( size_t i = mVertices.size()-1; i > 0; i--) {
71 if ( distance_square(mVertices[i], mVertices[i-1]) < iTolSquare ) {
72 mVertices.erase( mVertices.begin()+i );
73 }
74 }
75 }
76}
77
78void BasicGeometry :: translate(const FloatArray &iTrans)
79{
80 for ( size_t i = 0; i < mVertices.size(); i++ ) {
81 mVertices[i].add(iTrans);
82 }
83}
84
85
86double BasicGeometry :: computeLineDistance(const FloatArray &iP1, const FloatArray &iP2, const FloatArray &iQ1, const FloatArray &iQ2)
87{
88 FloatArray u;
89 u.beDifferenceOf(iP2, iP1);
90
91 const double LengthP = u.computeNorm();
92
93 FloatArray v;
94 v.beDifferenceOf(iQ2, iQ1);
95 const double LengthQ = v.computeNorm();
96
97
98 // Regularization coefficients (to make it possible to solve when lines are parallel)
99 const double c1 = (1.0e-14)*LengthP*LengthP;
100 const double c2 = (1.0e-14)*LengthQ*LengthQ;
101
102 const size_t minIter = 2;
103 const size_t maxIter = 5;
104 const double absTol = 1.0e-12;
105
106 double xi = 0.0, eta = 0.0;
107
108 FloatArray d;
109 d = iP1;
110 d.add(xi,u);
111 d.add(-1.0, iQ1);
112 d.add(-eta, v);
113
114 FloatMatrix K(2,2), KInv;
115 FloatArray dXi;
116
117 bool lockXi = false, lockEta = false;
118
119 for ( size_t iter = 0; iter < maxIter; iter++ ) {
120
121 if ( xi < 0.0 ) {
122 xi = 0.0;
123 lockXi = true;
124 }
125
126 if ( xi > 1.0 ) {
127 xi = 1.0;
128 lockXi = true;
129 }
130
131
132 if ( eta < 0.0 ) {
133 eta = 0.0;
134 lockEta = true;
135 }
136
137 if ( eta > 1.0 ) {
138 eta = 1.0;
139 lockEta = true;
140 }
141
142 FloatArray R=Vec2( d.dotProduct(u) + c1*xi,
143 -d.dotProduct(v) + c2*eta);
144
145 if ( lockXi ) {
146 R[0] = 0.0;
147 }
148
149 if ( lockEta ) {
150 R[1] = 0.0;
151 }
152
153 const double res = R.computeNorm();
154// printf("iter: %lu res: %e\n", iter, res);
155
156 if ( res < absTol && iter >= minIter ) {
157// printf("xi: %e eta: %e\n", xi, eta);
158 break;
159 }
160
161 K(0,0) = -u.dotProduct(u)-c1;
162 K(0,1) = u.dotProduct(v);
163 K(1,0) = u.dotProduct(v);
164 K(1,1) = -v.dotProduct(v)-c2;
165
166
167 if ( lockXi ) {
168 K(0,0) = -1.0;
169 K(0,1) = K(1,0) = 0.0;
170 }
171
172 if ( lockEta ) {
173 K(0,1) = K(1,0) = 0.0;
174 K(1,1) = -1.0;
175 }
176
177
178 KInv.beInverseOf(K);
179
180 dXi.beProductOf(KInv, R);
181
182 xi += dXi[0];
183 eta += dXi[1];
184
185 d = iP1;
186 d.add(xi,u);
187 d.add(-1.0, iQ1);
188 d.add(-eta, v);
189 }
190
191 if ( xi < 0.0 ) {
192 xi = 0.0;
193 }
194
195 if ( xi > 1.0 ) {
196 xi = 1.0;
197 }
198
199 if ( eta < 0.0 ) {
200 eta = 0.0;
201 }
202
203 if ( eta > 1.0 ) {
204 eta = 1.0;
205 }
206
207 d = iP1;
208 d.add(xi,u);
209 d.add(-1.0, iQ1);
210 d.add(-eta, v);
211
212 const double dist = d.computeNorm();
213
214 return dist;
215}
216
217bool Line :: intersects(Element *element)
218{
219 int ip = this->computeNumberOfIntersectionPoints(element);
220 return ( ip > 0 );
221}
222
223Line :: Line(const FloatArray &iPointA, const FloatArray &iPointB) : BasicGeometry()
224{
225 mVertices.push_back(iPointA);
226 mVertices.push_back(iPointB);
227}
228
229double Line :: computeDistanceTo(const FloatArray &point)
230{
231 // TODO: Is this function correct?! /ES
232 const auto &pointA = mVertices [ 0 ];
233 const auto &pointB = mVertices [ 1 ];
234 double a = pointA.at(2) - pointB.at(2);
235 double b = pointB.at(1) - pointA.at(1);
236 double c = pointA.at(1) * pointB.at(2) - pointB.at(1) * pointA.at(2);
237 double l = distance(pointA, pointB);
238 return ( a * point.at(1) + b * point.at(2) + c ) / l;
239}
240
241void Line :: computeProjection(FloatArray &answer)
242{
243 answer.beDifferenceOf(mVertices [ 1 ], mVertices [ 0 ]);
244}
245
246double Line :: computeTangentialDistanceToEnd(const FloatArray &point)
247{
248 FloatArray projection;
249 this->computeProjection(projection);
250 FloatArray tmp;
251 tmp.beDifferenceOf(point, mVertices [ 1 ]);
252 return tmp.dotProduct(projection) / projection.computeNorm();
253}
254
255void Line :: computeTangentialSignDist(double &oDist, const FloatArray &iPoint, double &oMinArcDist) const
256{
257 PolygonLine pl;
260
261 pl.computeTangentialSignDist(oDist, iPoint, oMinArcDist);
262}
263
264int Line :: computeNumberOfIntersectionPoints(Element *element)
265{
266
267 int numIntersec = 0;
268 const double relTol = 1.0e-3;
269 const double LineLength = giveLength();
270 const double absTol = relTol*std::max(LineLength, XfemTolerances::giveCharacteristicElementLength() );
271
272 const int numEdges = element->giveInterpolation()->giveNumberOfEdges(element->giveGeometryType());
273
274 for ( int edgeIndex = 1; edgeIndex <= numEdges; edgeIndex++ ) {
275 auto bNodes = element->giveInterpolation()->boundaryGiveNodes(edgeIndex, element->giveGeometryType());
276
277 const int nsLoc = bNodes.at(1);
278 const int neLoc = bNodes.at( bNodes.giveSize() );
279
280 FloatArray xS = element->giveNode(nsLoc)->giveCoordinates();
281 xS.resizeWithValues(2);
282 FloatArray xE = element->giveNode(neLoc)->giveCoordinates();
283 xE.resizeWithValues(2);
284
285 const double dist = BasicGeometry :: computeLineDistance(xS, xE, mVertices[0], mVertices[1]);
286
287 if(dist < absTol) {
288 numIntersec++;
289 }
290 }
291
292 return numIntersec;
293}
294
295void Line :: computeIntersectionPoints(Element *element, std :: vector< FloatArray > &oIntersectionPoints)
296{
297 for ( int i = 1; i <= element->giveNumberOfDofManagers(); i++ ) {
298 int n1 = i;
299 int n2 = 0;
300 if ( i < element->giveNumberOfDofManagers() ) {
301 n2 = i + 1;
302 } else {
303 n2 = 1;
304 }
305
306 double lsn1 = computeDistanceTo( element->giveDofManager(n1)->giveCoordinates() );
307 double lsn2 = computeDistanceTo( element->giveDofManager(n2)->giveCoordinates() );
308 double lst1 = computeTangentialDistanceToEnd( element->giveDofManager(n1)->giveCoordinates() );
309 double lst2 = computeTangentialDistanceToEnd( element->giveDofManager(n2)->giveCoordinates() );
310 if ( lsn1 * lsn2 <= 0 && lst1 <= 0 && lst2 <= 0 ) {
311 double r = lsn1 / ( lsn1 - lsn2 );
312 if ( i <= element->giveNumberOfDofManagers() ) {
313 FloatArray answer(2);
314 for ( int j = 1; j <= answer.giveSize(); j++ ) {
315 answer.at(j) = ( 1 - r ) * element->giveDofManager(n1)->giveCoordinate(j)
316 + r *element->giveDofManager(n2)->giveCoordinate(j);
317 }
318
319 oIntersectionPoints.push_back(answer);
320 }
321 }
322 }
323}
324
325double Line :: computeInclinationAngle()
326{
327 const FloatArray &pointA = mVertices [ 0 ];
328 const FloatArray &pointB = mVertices [ 1 ];
329 double y = pointB.at(2) - pointA.at(2);
330 double x = pointB.at(1) - pointA.at(1);
331 return atan2(y, x);
332}
333
334void Line :: computeTransformationMatrix(FloatMatrix &answer)
335{
336 answer.resize(2, 2);
337 double alpha = this->computeInclinationAngle();
338 answer.at(1, 1) = cos(alpha);
339 answer.at(1, 2) = sin(alpha);
340 answer.at(2, 1) = -sin(alpha);
341 answer.at(2, 2) = cos(alpha);
342}
343
344void Line :: transformIntoPolar(FloatArray *point, FloatArray &answer)
345{
346 FloatArray xp;
347 FloatMatrix Qt;
348 FloatArray help;
350 help.beDifferenceOf(* point, mVertices [ 1 ]);
351 xp.beProductOf(Qt, help);
352 answer.resize(2);
353 answer.at(1) = xp.computeNorm();
354 answer.at(2) = atan2( xp.at(2), xp.at(1) );
355}
356
357void Line :: initializeFrom(InputRecord &ir)
358{
359 mVertices.resize(2);
362}
363
364bool Line :: isPointInside(FloatArray *point)
365{
366 double maxX, minX, maxY, minY;
367 if ( mVertices [ 0 ].at(1) > mVertices [ 1 ].at(1) ) {
368 maxX = mVertices [ 0 ].at(1);
369 minX = mVertices [ 1 ].at(1);
370 } else {
371 minX = mVertices [ 0 ].at(1);
372 maxX = mVertices [ 1 ].at(1);
373 }
374
375 if ( mVertices [ 0 ].at(2) > mVertices [ 1 ].at(2) ) {
376 maxY = mVertices [ 0 ].at(2);
377 minY = mVertices [ 1 ].at(2);
378 } else {
379 minY = mVertices [ 0 ].at(2);
380 maxY = mVertices [ 1 ].at(2);
381 }
382
383 if ( point->at(1) >= minX && point->at(1) <= maxX &&
384 point->at(2) >= minY && point->at(2) <= maxY ) {
385 return true;
386 } else {
387 return false;
388 }
389}
390
391bool Line :: isOutside(BasicGeometry *bg)
392{ // equivalent to up
393 int count = 0;
394 for ( int i = 1; i <= bg->giveNrVertices(); i++ ) {
395 if ( this->computeDistanceTo( bg->giveVertex(i) ) > 0.1 ) {
396 count++;
397 }
398 }
399
400 return ( count != 0 );
401}
402
403Triangle :: Triangle(const FloatArray &iP1, const FloatArray &iP2, const FloatArray &iP3) : BasicGeometry()
404{
405 mVertices.push_back(iP1);
406 mVertices.push_back(iP2);
407 mVertices.push_back(iP3);
408}
409
410double Triangle :: getArea()
411{
412 return fabs( 0.5 * ( mVertices [ 0 ].at(1) * ( mVertices [ 1 ].at(2) - mVertices [ 2 ].at(2) )
413 + mVertices [ 1 ].at(1) * ( mVertices [ 2 ].at(2) - mVertices [ 0 ].at(2) ) +
414 mVertices [ 2 ].at(1) * ( mVertices [ 0 ].at(2) - mVertices [ 1 ].at(2) ) ) );
415}
416
417double Triangle :: getRadiusOfCircumCircle()
418{
419 return 0.25 * distance(mVertices [ 0 ], mVertices [ 1 ]) *
420 distance(mVertices [ 1 ], mVertices [ 2 ]) *
421 distance(mVertices [ 0 ], mVertices [ 2 ]) / this->getArea();
422}
423
424void Triangle :: computeBarycentrCoor(FloatArray &answer) const
425{
426 double c = distance(mVertices [ 0 ], mVertices [ 1 ]);
427 double a = distance(mVertices [ 1 ], mVertices [ 2 ]);
428 double b = distance(mVertices [ 0 ], mVertices [ 2 ]);
429
430 // just to avoid multiple multiplication
431 double aPow = a * a;
432 double bPow = b * b;
433 double cPow = c * c;
434
435 answer.resize(3);
436 answer.at(1) = aPow * ( -aPow + bPow + cPow );
437 answer.at(2) = bPow * ( aPow - bPow + cPow );
438 answer.at(3) = cPow * ( aPow + bPow - cPow );
439}
440
441void Triangle :: computeCenterOfCircumCircle(FloatArray &answer) const
442{
443 FloatArray bar;
444 this->computeBarycentrCoor(bar);
445 double sum = bar.at(1) + bar.at(2) + bar.at(3);
446 // center of the circumcircle
447 answer.resize(2);
448 for ( int i = 1; i <= answer.giveSize(); i++ ) {
449 answer.at(i) = ( bar.at(1) * mVertices [ 0 ].at(i) + bar.at(2) * mVertices [ 1 ].at(i) + bar.at(3) * mVertices [ 2 ].at(i) ) / sum;
450 }
451}
452
453void Triangle :: printYourself()
454{
455 printf("Triangle: ");
456 for ( size_t i = 0; i < mVertices.size(); i++ ) {
457 mVertices [ i ].printYourself();
458 }
459
460 printf("\n");
461}
462
463bool Triangle :: isOrientedAnticlockwise()
464{
465 FloatMatrix fm(3, 3);
466 for ( int i = 1; i <= 3; i++ ) {
467 for ( int j = 1; j <= 2; j++ ) {
468 fm.at(i, j) = this->giveVertex(i).at(j);
469 }
470 fm.at(i, 3) = 1.;
471 }
472
473 if ( fm.giveDeterminant() > 0.0001 ) {
474 return true;
475 } else {
476 return false;
477 }
478}
479
480void Triangle :: changeToAnticlockwise()
481{
482 std :: swap(mVertices [ 1 ], mVertices [ 2 ]);
483}
484
485bool Triangle :: pointIsInTriangle(const FloatArray &iP) const
486{
487 FloatArray P(iP);
488
489 const double tol2 = 1.0e-18;
490
491 // Compute triangle normal
492 FloatArray p1p2;
493 p1p2.beDifferenceOf(mVertices [ 1 ], mVertices [ 0 ]);
494
495 FloatArray p1p3;
496 p1p3.beDifferenceOf(mVertices [ 2 ], mVertices [ 0 ]);
497
498
499 // Edge 1
500 FloatArray t1;
501 t1.beDifferenceOf(mVertices [ 1 ], mVertices [ 0 ]);
502 if(t1.computeSquaredNorm() < tol2) {
503 // The triangle is degenerated
504 return false;
505 }
506 else {
507 t1.normalize();
508 }
509
510
511 FloatArray a1;
512
513 // Edge 2
514 FloatArray t2;
515 t2.beDifferenceOf(mVertices [ 2 ], mVertices [ 1 ]);
516 if(t2.computeSquaredNorm() < tol2) {
517 // The triangle is degenerated
518 return false;
519 }
520 else {
521 t2.normalize();
522 }
523
524 FloatArray a2;
525
526
527 // Edge 3
528 FloatArray t3;
529 t3.beDifferenceOf(mVertices [ 0 ], mVertices [ 2 ]);
530 if(t3.computeSquaredNorm() < tol2) {
531 // The triangle is degenerated
532 return false;
533 }
534 else {
535 t3.normalize();
536 }
537
538 FloatArray a3;
539
540
541 // Project point onto triangle plane
542 FloatArray pProj = P;
543
544 if( p1p2.giveSize() == 2 ) {
545 // 2D
546 a1 = Vec2(-t1[1], t1[0]);
547 a2 = Vec2(-t2[1], t2[0]);
548 a3 = Vec2(-t3[1], t3[0]);
549 }
550 else {
551 // 3D
553
554 N.beVectorProductOf(p1p2, p1p3);
555
556 if(N.computeSquaredNorm() < tol2) {
557 // The triangle is degenerated
558 return false;
559 }
560 else {
561 N.normalize();
562 }
563
564 // Compute normal distance from triangle to point
565 FloatArray p1p;
566 p1p.beDifferenceOf(P, mVertices [ 0 ]);
567 double d = p1p.dotProduct(N);
568
569 pProj.add(-d, N);
570
571
572 a1.beVectorProductOf(N, t1);
573// if(a1.computeSquaredNorm() < tol2) {
574// // The triangle is degenerated
575// return false;
576// }
577// else {
578// a1.normalize();
579// }
580
581 a2.beVectorProductOf(N, t2);
582// if(a2.computeSquaredNorm() < tol2) {
583// // The triangle is degenerated
584// return false;
585// }
586// else {
587// a2.normalize();
588// }
589
590 a3.beVectorProductOf(N, t3);
591// if(a3.computeSquaredNorm() < tol2) {
592// // The triangle is degenerated
593// return false;
594// }
595// else {
596// a3.normalize();
597// }
598
599 }
600
601
602 // Check if the point is on the correct side of all edges
603
604
605 FloatArray p1pProj;
606 p1pProj.beDifferenceOf(pProj, mVertices [ 0 ], mVertices[0].giveSize());
607 if ( p1pProj.dotProduct(a1) < 0.0 ) {
608 return false;
609 }
610
611
612
613 FloatArray p2pProj;
614 p2pProj.beDifferenceOf(pProj, mVertices [ 1 ], mVertices[1].giveSize());
615 if ( p2pProj.dotProduct(a2) < 0.0 ) {
616 return false;
617 }
618
619 FloatArray p3pProj;
620 p3pProj.beDifferenceOf(pProj, mVertices [ 2 ], mVertices[2].giveSize());
621 if ( p3pProj.dotProduct(a3) < 0.0 ) {
622 return false;
623 }
624
625 return true;
626}
627
628void Triangle :: refineTriangle(std::vector<Triangle> &oRefinedTri, const Triangle &iTri)
629{
630 const FloatArray &p1 = iTri.giveVertex(1);
631 const FloatArray &p2 = iTri.giveVertex(2);
632 const FloatArray &p3 = iTri.giveVertex(3);
633
634 // Compute edge midpoints
635 FloatArray q1, q2, q3;
636
637 q1.beScaled(0.5, p1);
638 q1.add(0.5, p2);
639
640 q2.beScaled(0.5, p2);
641 q2.add(0.5, p3);
642
643 q3.beScaled(0.5, p3);
644 q3.add(0.5, p1);
645
646 oRefinedTri.push_back( Triangle(p1, q1, q3) );
647 oRefinedTri.push_back( Triangle(q1, q2, q3) );
648 oRefinedTri.push_back( Triangle(q1, p2, q2) );
649 oRefinedTri.push_back( Triangle(q3, q2, p3) );
650}
651
652Circle :: Circle(FloatArray &center, double radius) :
653 mTangSignDist(1.0)
654{
655 mVertices.push_back(center);
656
657 this->radius = radius;
658}
659
660void Circle :: computeNormalSignDist(double &oDist, const FloatArray &iPoint) const
661{
662 oDist = distance(mVertices [ 0 ], iPoint) - radius;
663}
664
665void Circle :: giveGlobalCoordinates(FloatArray &oGlobalCoord, const double &iArcPos) const
666{
667 double angle = 2.0*M_PI*iArcPos;
668
669 oGlobalCoord.resize(2);
670 oGlobalCoord = Vec2( mVertices[0][0] + radius*cos(angle), mVertices[0][1] + radius*sin(angle) );
671}
672
673void Circle :: initializeFrom(InputRecord &ir)
674{
675 mVertices.resize(1);
678}
679
680bool Circle :: intersects(Element *element)
681{
682 int count = 0;
683 for ( int i = 1; i <= element->giveNumberOfDofManagers(); i++ ) {
684 const auto &nodeCoor = element->giveDofManager(i)->giveCoordinates();
685 // distance from the node to the center of the circle
686 double dist = distance(nodeCoor, mVertices [ 0 ]);
687 if ( dist > this->radius ) {
688 count++;
689 }
690 }
691
692 if ( count == 0 || count == element->giveNumberOfDofManagers() ) {
693 return false;
694 } else {
695 return true;
696 }
697}
698
699
700
701bool
702Circle :: isInside(const FloatArray &point)
703{
704 double dist = distance(this->giveVertex(1), point);
705 if ( dist < this->radius ) {
706 return true;
707 }
708 return false;
709}
710
711
712bool Circle :: isInside(Element *element)
713{ // condition should maybe be that all nodes should be inside
714 for ( int i = 1; i <= element->giveNumberOfDofManagers(); i++ ) {
715 const auto &nodeCoord = element->giveDofManager(i)->giveCoordinates();
716 if ( isInside(nodeCoord) ) {
717 return true;
718 }
719 }
720 return false;
721}
722
723
724
725
726void Circle :: computeIntersectionPoints(Element *element, std :: vector< FloatArray > &oIntersectionPoints)
727{
728 if ( intersects(element) ) {
729 for ( int i = 1; i <= element->giveNumberOfBoundarySides(); i++ ) {
730 std :: vector< FloatArray >oneLineIntersects;
732 const auto &a = element->giveDofManager ( i )->giveCoordinates();
733 const auto &b = ( i != element->giveNumberOfBoundarySides() ) ?
734 element->giveDofManager ( i + 1 )->giveCoordinates() :
735 element->giveDofManager ( 1 )->giveCoordinates();
736
737 Line l(a, b);
738 computeIntersectionPoints(& l, oneLineIntersects);
739 for ( int j = 1; j <= int ( oneLineIntersects.size() ); j++ ) {
740 oIntersectionPoints.push_back(oneLineIntersects [ j - 1 ]);
741 }
742 }
743 }
744}
745
746void Circle :: computeIntersectionPoints(Line *l, std :: vector< FloatArray > &oIntersectionPoints)
747{
748 double x1 = l->giveVertex(1).at(1);
749 double y1 = l->giveVertex(1).at(2);
750 double x2 = l->giveVertex(2).at(1);
751 double y2 = l->giveVertex(2).at(2);
752 double c1 = mVertices [ 0 ].at(1);
753 double c2 = mVertices [ 0 ].at(2);
754 double distX = x2 - x1;
755 double distY = y2 - y1;
756 double a = 0., b = 0., A, B, C;
757 if ( distX != 0.0 ) {
758 a = distY / distX;
759 b = y1 - a * x1;
760 A = 1 + a * a;
761 B = 2 * ( ( -1 ) * c1 + b * a - a * c2 );
762 C = c1 * c1 + b * b - 2 * c2 * b + c2 * c2 - radius * radius;
763 } else {
764 A = 1;
765 B = ( -1 ) * 2 * c2;
766 C = x1 * x1 - 2 * x1 * c1 + c1 * c1 + c2 * c2 - radius * radius;
767 }
768
769 double D = B * B - 4 * A * C;
770 int sz = 0;
771 if ( D < 0 ) {
772 sz = 0;
773 } else if ( D == 0 ) {
774 sz = 1;
775 } else {
776 sz = 2;
777 }
778
779 for ( int i = 1; i <= sz; i++ ) {
780 FloatArray point(2);
781 double fn;
782 if ( i == 1 ) {
783 fn = sqrt(D);
784 } else {
785 fn = ( -1 ) * sqrt(D);
786 }
787
788 if ( distX != 0.0 ) {
789 point.at(1) = ( ( -1 ) * B + fn ) / ( 2 * A );
790 point.at(2) = a * point.at(1) + b;
791 } else {
792 point.at(1) = x1;
793 point.at(2) = ( ( -1 ) * B + fn ) / ( 2 * A );
794 }
795
796 if ( l->isPointInside(& point) ) {
797 oIntersectionPoints.push_back(point);
798 }
799 }
800}
801
802int
803Circle :: computeNumberOfIntersectionPoints(Element *element)
804{
805 std :: vector< FloatArray >intersecPoints;
806
807 this->computeIntersectionPoints(element, intersecPoints);
808 return (int) intersecPoints.size();
809}
810
811bool Circle :: isOutside(BasicGeometry *bg)
812{
813 int count = 0;
814 for ( int i = 1; i <= bg->giveNrVertices(); i++ ) {
815 if ( 0.9999 * distance(bg->giveVertex(i), mVertices [ 0 ]) > this->radius ) {
816 count++;
817 }
818 }
819
820 if ( count != 0 ) {
821 return true;
822 } else {
823 return false;
824 }
825}
826
827void Circle :: printYourself()
828{
829 printf("Circle: radius = %e, center = ", this->radius);
830 mVertices [ 0 ].printYourself();
831 printf("\n");
832}
833
834void Circle :: giveBoundingSphere(FloatArray &oCenter, double &oRadius)
835{
836 oCenter = mVertices [ 0 ];
837 oRadius = radius;
838}
839
840
841PolygonLine :: PolygonLine() : BasicGeometry()
842{
843 mDebugVtk = false;
844#ifdef __BOOST_MODULE
845 LC.x(0.0);
846 LC.y(0.0);
847
848 UC.x(0.0);
849 UC.y(0.0);
850#endif
851}
852
853void PolygonLine :: computeNormalSignDist(double &oDist, const FloatArray &iPoint) const
854{
855 FloatArray point = Vec2(iPoint[0], iPoint[1]);
856
857 oDist = std :: numeric_limits< double > :: max();
858 int numSeg = this->giveNrVertices() - 1;
859
860 // TODO: This can probably be done in a nicer way.
861 // Ensure that we work in 2d.
862 const int dim = 2;
863
864 for ( int segId = 1; segId <= numSeg; segId++ ) {
865 // Crack segment
866 const FloatArray &crackP1( this->giveVertex ( segId ) );
867
868 const FloatArray &crackP2( this->giveVertex ( segId + 1 ) );
869
870 double dist2 = 0.0;
871 if ( segId == 1 ) {
872 // Vector from start P1 to point X
873 FloatArray u = Vec2( point.at(1) - crackP1.at(1), point.at(2) - crackP1.at(2) );
874
875 // Line tangent vector
876 FloatArray t = Vec2( crackP2.at(1) - crackP1.at(1), crackP2.at(2) - crackP1.at(2) );
877 double l2 = t.computeSquaredNorm();
878
879 if ( l2 > 0.0 ) {
880 double l = t.normalize_giveNorm();
881 double s = dot(u, t);
882
883 if ( s > l ) {
884 // X is closest to P2
885 dist2 = distance_square(point, crackP2);
886 } else {
887 double xi = s / l;
888 auto q = ( 1.0 - xi ) * crackP1 + xi * crackP2;
889 dist2 = distance_square(point, q);
890 }
891 } else {
892 // If the points P1 and P2 coincide,
893 // we can compute the distance to any
894 // of these points.
895 dist2 = distance_square(point, crackP1);
896 }
897 } else if ( segId == numSeg ) {
898 // Vector from start P1 to point X
899 FloatArray u = Vec2(point.at(1) - crackP1.at(1), point.at(2) - crackP1.at(2));
900
901 // Line tangent vector
902 FloatArray t = Vec2(crackP2.at(1) - crackP1.at(1), crackP2.at(2) - crackP1.at(2));
903 double l2 = t.computeSquaredNorm();
904
905 if ( l2 > 0.0 ) {
906 double l = t.normalize_giveNorm();
907 double s = dot(u, t);
908
909 if ( s < 0.0 ) {
910 // X is closest to P1
911 dist2 = distance_square(point, crackP1);
912 } else {
913 double xi = s / l;
914 auto q = ( 1.0 - xi ) * crackP1 + xi * crackP2;
915 dist2 = distance_square(point, q);
916 }
917 } else {
918 // If the points P1 and P2 coincide,
919 // we can compute the distance to any
920 // of these points.
921 dist2 = distance_square(point, crackP1);
922 }
923 } else {
924 double arcPos = -1.0, dummy;
925 dist2 = point.distance_square(crackP1, crackP2, arcPos, dummy);
926 }
927
928 if ( dist2 < oDist*oDist ) {
929 FloatArray lineToP;
930 lineToP.beDifferenceOf(point, crackP1, dim);
931
932 FloatArray t;
933 t.beDifferenceOf(crackP2, crackP1, dim);
934
935 FloatArray n = Vec2(-t.at(2), t.at(1));
936
937 oDist = sgn( lineToP.dotProduct(n) ) * sqrt(dist2);
938 }
939 }
940}
941
942void PolygonLine :: computeTangentialSignDist(double &oDist, const FloatArray &iPoint, double &oMinArcDist) const
943{
944 FloatArray point = iPoint;
945 point.resizeWithValues(2);
946
947 const int numSeg = this->giveNrVertices() - 1;
948
949 double xi = 0.0, xiUnbounded = 0.0;
950
951 if ( numSeg == 0 ) {
952 FloatArray crackP1 = giveVertex ( 1 );
953 oDist = distance(crackP1, iPoint);
954 oMinArcDist = 0.0;
955 return;
956 }
957
958 if ( numSeg == 1 ) {
959 FloatArray crackP1 = giveVertex ( 1 );
960 crackP1.resizeWithValues(2);
961 FloatArray crackP2 = giveVertex ( 2 );
962 crackP2.resizeWithValues(2);
963 point.distance(crackP1, crackP2, xi, xiUnbounded);
964
965 if( xiUnbounded < 0.0 ) {
966 oDist = xiUnbounded * distance(crackP1, crackP2);
967 oMinArcDist = 0.0;
968 return;
969 }
970
971 if( xiUnbounded > 1.0 ) {
972 oDist = -(xiUnbounded-1.0) * distance(crackP1, crackP2);
973 oMinArcDist = 1.0;
974 return;
975 }
976
977 const double L = computeLength();
978 double distToStart = xi*L;
979
980 oDist = std::min(distToStart, (L - distToStart) );
981 oMinArcDist = distToStart/L;
982 return;
983 }
984
985 bool isBeforeStart = false, isAfterEnd = false;
986 double distBeforeStart = 0.0, distAfterEnd = 0.0;
987
989 // Check first segment
990 FloatArray crackP1_start = giveVertex ( 1 );
991 crackP1_start.resizeWithValues(2);
992 FloatArray crackP2_start = giveVertex ( 2 );
993 crackP2_start.resizeWithValues(2);
994 const double distSeg_start = point.distance(crackP1_start, crackP2_start, xi, xiUnbounded);
995
996 if( xiUnbounded < 0.0 ) {
997 isBeforeStart = true;
998 distBeforeStart = xiUnbounded * distance(crackP1_start, crackP2_start);
999 }
1000
1001 double arcPosPassed = distance(crackP1_start, crackP2_start);
1002 double distToStart = xi * distance(crackP1_start, crackP2_start);
1003
1004 double minGeomDist = distSeg_start;
1005
1006
1007
1008
1010 // Check interior segments
1011 for ( int segId = 2; segId <= numSeg-1; segId++ ) {
1012 FloatArray crackP1 = giveVertex ( segId );
1013 crackP1.resizeWithValues(2);
1014 FloatArray crackP2 = giveVertex ( segId+1 );
1015 crackP2.resizeWithValues(2);
1016
1017 const double distSeg = point.distance(crackP1, crackP2, xi, xiUnbounded);
1018
1019 if(distSeg < minGeomDist) {
1020 isBeforeStart = false;
1021 minGeomDist = distSeg;
1022 distToStart = arcPosPassed + xi * distance(crackP1, crackP2);
1023 }
1024
1025 arcPosPassed += distance(crackP1, crackP2);
1026
1027 }
1028
1029
1030
1032 // Check last segment
1033 FloatArray crackP1_end = giveVertex ( numSeg );
1034 crackP1_end.resizeWithValues(2);
1035 FloatArray crackP2_end = giveVertex ( numSeg+1 );
1036 crackP2_end.resizeWithValues(2);
1037 const double distSeg_end = point.distance(crackP1_end, crackP2_end, xi, xiUnbounded);
1038
1039 if ( numSeg > 1 ) {
1040 if( xiUnbounded > 1.0 ) {
1041 arcPosPassed += xiUnbounded * distance(crackP1_end, crackP2_end);
1042 }
1043 else {
1044 arcPosPassed += xi * distance(crackP1_end, crackP2_end);
1045 }
1046 }
1047
1048 if ( distSeg_end < minGeomDist ) {
1049 isBeforeStart = false;
1050
1051 if( xiUnbounded > 1.0 ) {
1052 isAfterEnd = true;
1053 distAfterEnd = -(xiUnbounded-1.0) * distance(crackP1_end, crackP2_end);
1054 }
1055
1056 distToStart = arcPosPassed;
1057 }
1058
1060 // Return result
1061
1062 if ( isBeforeStart ) {
1063 oDist = distBeforeStart;
1064 oMinArcDist = 0.0;
1065 return;
1066 }
1067
1068 if ( isAfterEnd ) {
1069 oDist = distAfterEnd;
1070 oMinArcDist = 1.0;
1071 return;
1072 }
1073
1074 const double L = computeLength();
1075
1076 oDist = std::min(distToStart, (L - distToStart) );
1077 oMinArcDist = distToStart/L;
1078}
1079
1080void PolygonLine :: computeLocalCoordinates(FloatArray &oLocCoord, const FloatArray &iPoint) const
1081{ }
1082
1083double PolygonLine :: computeLength() const
1084{
1085 if ( mVertices.size() == 0 ) {
1086 return 0.0;
1087 }
1088
1089 double L = 0.0;
1090
1091 size_t numSeg = mVertices.size() - 1;
1092
1093 if ( numSeg == 0 ) {
1094 return 0.0;
1095 }
1096
1097 for ( size_t i = 0; i < numSeg; i++ ) {
1098 L += distance(mVertices [ i ], mVertices [ i + 1 ]);
1099 }
1100
1101 return L;
1102}
1103
1104void PolygonLine :: giveSubPolygon(std :: vector< FloatArray > &oPoints, const double &iXiStart, const double &iXiEnd) const
1105{
1106 double L = computeLength();
1107 double xSegStart = 0.0, xSegEnd = 0.0;
1108 double xiSegStart = 0.0, xiSegEnd = 0.0;
1109 size_t numSeg = mVertices.size() - 1;
1110 const double xiTol = 1.0e-9;
1111 if ( iXiStart < xiTol ) {
1112 // Add first point
1113 oPoints.push_back(mVertices [ 0 ]);
1114 }
1115
1116 for ( size_t i = 0; i < numSeg; i++ ) {
1117 xSegEnd += distance(mVertices [ i ], mVertices [ i + 1 ]);
1118
1119 xiSegStart = xSegStart / L;
1120 xiSegEnd = xSegEnd / L;
1121
1122 if ( iXiStart > xiSegStart-xiTol && iXiStart < xiSegEnd+xiTol ) {
1123 // Start point is within the segment
1124 FloatArray p;
1125 double elXi = ( iXiStart - xiSegStart ) / ( xiSegEnd - xiSegStart );
1126 p.beScaled( ( 1.0 - elXi ), mVertices [ i ] );
1127 p.add(elXi, mVertices [ i + 1 ]);
1128 oPoints.push_back(p);
1129 }
1130
1131
1132 if ( iXiEnd > xiSegStart && iXiEnd < xiSegEnd ) {
1133 // End point is within the segment
1134 FloatArray p;
1135 double elXi = ( iXiEnd - xiSegStart ) / ( xiSegEnd - xiSegStart );
1136 p.beScaled( ( 1.0 - elXi ), mVertices [ i ] );
1137 p.add(elXi, mVertices [ i + 1 ]);
1138 oPoints.push_back(p);
1139 }
1140
1141 if ( xiSegEnd > iXiStart && xiSegEnd < iXiEnd + xiTol ) {
1142 // End point of the segment is within range
1143 oPoints.push_back(mVertices [ i + 1 ]);
1144 }
1145
1146 xSegStart = xSegEnd;
1147 }
1148}
1149
1150void PolygonLine :: giveGlobalCoordinates(FloatArray &oGlobalCoord, const double &iArcPos) const
1151{
1152 double L = computeLength();
1153 double xSegStart = 0.0, xSegEnd = 0.0;
1154 double xiSegStart = 0.0, xiSegEnd = 0.0;
1155 size_t numSeg = mVertices.size() - 1;
1156 const double xiTol = 1.0e-9;
1157 if ( iArcPos < xiTol ) {
1158 oGlobalCoord = mVertices [ 0 ];
1159 return;
1160 }
1161
1162 for ( size_t i = 0; i < numSeg; i++ ) {
1163 xSegEnd += distance(mVertices [ i ], mVertices [ i + 1 ]);
1164
1165 xiSegStart = xSegStart / L;
1166 xiSegEnd = xSegEnd / L;
1167
1168 if ( iArcPos > xiSegStart-xiTol && iArcPos < xiSegEnd+xiTol ) {
1169 // Point is within the segment
1170 FloatArray p;
1171 double elXi = ( iArcPos - xiSegStart ) / ( xiSegEnd - xiSegStart );
1172 p.beScaled( ( 1.0 - elXi ), mVertices [ i ] );
1173 p.add(elXi, mVertices [ i + 1 ]);
1174 oGlobalCoord = p;
1175 return;
1176 }
1177
1178 }
1179}
1180
1181void PolygonLine :: giveNormal(FloatArray &oNormal, const double &iArcPosition) const
1182{
1183 double L = computeLength();
1184 double xSegStart = 0.0, xSegEnd = 0.0;
1185 double xiSegStart = 0.0, xiSegEnd = 0.0;
1186 size_t numSeg = mVertices.size() - 1;
1187 const double xiTol = 1.0e-9;
1188
1189 for ( size_t i = 0; i < numSeg; i++ ) {
1190 xSegEnd += distance(mVertices [ i ], mVertices [ i + 1 ]);
1191
1192 xiSegStart = xSegStart / L;
1193 xiSegEnd = xSegEnd / L;
1194
1195 if ( iArcPosition > xiSegStart-xiTol && iArcPosition < xiSegEnd+xiTol ) {
1196 // The given point is within the segment
1197
1198 const FloatArray &p1 = mVertices [ i ];
1199 const FloatArray &p2 = mVertices [ i+1 ];
1200
1201 FloatArray t = Vec2(p2(0) - p1(0), p2(1) - p1(1));
1202
1203 oNormal.resize(2);
1204 oNormal(0) = -t(1);
1205 oNormal(1) = t(0);
1206 oNormal.normalize();
1207
1208 return;
1209 }
1210
1211 }
1212
1213 OOFEM_ERROR("Arc position not found.")
1214}
1215
1216void PolygonLine :: giveTangent(FloatArray &oTangent, const double &iArcPosition) const
1217{
1218 double L = computeLength();
1219 double xSegStart = 0.0, xSegEnd = 0.0;
1220 double xiSegStart = 0.0, xiSegEnd = 0.0;
1221 size_t numSeg = mVertices.size() - 1;
1222 const double xiTol = 1.0e-9;
1223
1224 for ( size_t i = 0; i < numSeg; i++ ) {
1225 xSegEnd += distance(mVertices [ i ], mVertices [ i + 1 ]);
1226
1227 xiSegStart = xSegStart / L;
1228 xiSegEnd = xSegEnd / L;
1229
1230 if ( iArcPosition > xiSegStart-xiTol && iArcPosition < xiSegEnd+xiTol ) {
1231 // The given point is within the segment
1232
1233 const FloatArray &p1 = mVertices [ i ];
1234 const FloatArray &p2 = mVertices [ i+1 ];
1235
1236 oTangent = Vec2(p2(0) - p1(0), p2(1) - p1(1));
1237
1238 oTangent.normalize();
1239
1240 return;
1241 }
1242
1243 }
1244
1245 OOFEM_ERROR("Arc position not found.")
1246}
1247
1248void PolygonLine :: initializeFrom(InputRecord &ir)
1249{
1250 FloatArray points;
1252
1253 int numPoints = points.giveSize() / 2;
1254
1255 for ( int i = 1; i <= numPoints; i++ ) {
1256 mVertices.push_back(Vec2(points.at(2 * ( i - 1 ) + 1), points.at( 2 * ( i ) )));
1257 }
1258
1259#ifdef __BOOST_MODULE
1260 // Precompute bounding box to speed up calculation of intersection points.
1261 calcBoundingBox(LC, UC);
1262#endif
1263}
1264
1265void PolygonLine :: giveInputRecord(DynamicInputRecord &input)
1266{
1267 input.setRecordKeywordField( "PolygonLine", 1 );
1268
1269 FloatArray points;
1270 int nVert = (int) mVertices.size();
1271 points.resize(nVert * 2);
1272
1273 for ( int i = 0; i < nVert; i++ ) {
1274 points.at(2 * i + 1) = mVertices [ i ].at(1);
1275 points.at(2 * i + 2) = mVertices [ i ].at(2);
1276 }
1277
1278 input.setField(points, _IFT_PolygonLine_points);
1279}
1280
1281#ifdef __BOOST_MODULE
1282bool PolygonLine :: boundingBoxIntersects(Element *element)
1283{
1284 // Compute element bounding box
1285 bPoint2 eLC, eUC;
1286 eLC.x( element->giveNode(1)->giveCoordinate(1) );
1287 eLC.y( element->giveNode(1)->giveCoordinate(2) );
1288
1289 eUC.x( element->giveNode(1)->giveCoordinate(1) );
1290 eUC.y( element->giveNode(1)->giveCoordinate(2) );
1291
1292 int numNodes = element->giveNumberOfNodes();
1293 for ( int i = 2; i <= numNodes; i++ ) {
1294 eLC.x( min( eLC.x(), element->giveNode(i)->giveCoordinate(1) ) );
1295 eLC.y( min( eLC.y(), element->giveNode(i)->giveCoordinate(2) ) );
1296
1297 eUC.x( max( eUC.x(), element->giveNode(i)->giveCoordinate(1) ) );
1298 eUC.y( max( eUC.y(), element->giveNode(i)->giveCoordinate(2) ) );
1299 }
1300
1301 //printf("eLC: (%e, %e) eUC: (%e, %e) ", eLC.x(), eLC.y(), eUC.x(), eUC.y() );
1302 //printf(" LC: (%e, %e) UC: (%e, %e)\n", LC.x(), LC.y(), UC.x(), UC.y() );
1303
1304
1305 // Check if there is any chance of overlap
1306 if ( !bOverlap(eLC, eUC, LC, UC) ) {
1307 // If the bounding boxes do not overlap,
1308 // there will certainly not be any intersections
1309 return false;
1310 }
1311
1312
1313 return true;
1314}
1315#endif
1316
1317bool PolygonLine :: intersects(Element *element)
1318{
1319 printf("Warning: entering PolygonLine :: intersects(Element *element).\n");
1320
1321#ifdef __BOOST_MODULE
1322 if ( !boundingBoxIntersects(element) ) {
1323 return false;
1324 }
1325
1326 double distTol = 1.0e-9;
1327
1328 int numSeg = this->giveNrVertices() - 1;
1329
1330
1331 // Loop over the crack segments and test each segment for
1332 // overlap with the element
1333 for ( int segId = 1; segId <= numSeg; segId++ ) {
1334 if ( element->giveGeometryType() == EGT_triangle_1 ) {
1335 // Crack segment
1336 bPoint2 crackP1( this->giveVertex ( segId )->at(1), this->giveVertex ( segId )->at(2) );
1337 bPoint2 crackP2( this->giveVertex ( segId + 1 )->at(1), this->giveVertex ( segId + 1 )->at(2) );
1338 bSeg2 crackSeg(crackP1, crackP2);
1339
1340
1341 // Triangle vertices
1342 bPoint2 x1( element->giveNode ( 1 )->giveCoordinate(1), element->giveNode ( 1 )->giveCoordinate(2) );
1343 bPoint2 x2( element->giveNode ( 2 )->giveCoordinate(1), element->giveNode ( 2 )->giveCoordinate(2) );
1344 bPoint2 x3( element->giveNode ( 3 )->giveCoordinate(1), element->giveNode ( 3 )->giveCoordinate(2) );
1345
1346 bSeg2 edge1(x1, x2);
1347 bSeg2 edge2(x2, x3);
1348 bSeg2 edge3(x3, x1);
1349
1350 double d1 = bDist(crackSeg, edge1);
1351 if ( d1 < distTol ) {
1352 return true;
1353 }
1354
1355 double d2 = bDist(crackSeg, edge2);
1356 if ( d2 < distTol ) {
1357 return true;
1358 }
1359
1360 double d3 = bDist(crackSeg, edge3);
1361 if ( d3 < distTol ) {
1362 return true;
1363 }
1364 }
1365 }
1366
1367
1368
1369#endif
1370
1371 return false;
1372}
1373
1374
1375bool PolygonLine :: isInside(Element *element)
1376{
1377 return false;
1378}
1379
1380bool
1381PolygonLine :: isInside(const FloatArray &point)
1382{
1383 return false;
1384}
1385
1386
1387
1388#ifdef __BOOST_MODULE
1389void PolygonLine :: calcBoundingBox(bPoint2 &oLC, bPoint2 &oUC)
1390{
1391 oLC.x( vertices->at(1)->at(1) );
1392 oLC.y( vertices->at(1)->at(2) );
1393
1394 oUC.x( vertices->at(1)->at(1) );
1395 oUC.y( vertices->at(1)->at(2) );
1396
1397 int numPoints = vertices->giveSize();
1398 for ( int i = 2; i <= numPoints; i++ ) {
1399 oLC.x( min( oLC.x(), vertices->at(i)->at(1) ) );
1400 oLC.y( min( oLC.y(), vertices->at(i)->at(2) ) );
1401
1402 oUC.x( max( oUC.x(), vertices->at(i)->at(1) ) );
1403 oUC.y( max( oUC.y(), vertices->at(i)->at(2) ) );
1404 }
1405}
1406#endif
1407
1408
1409void PolygonLine :: computeIntersectionPoints(Element *element, std :: vector< FloatArray > &oIntersectionPoints)
1410{
1411
1412 for ( int i = 1; i <= element->giveNumberOfBoundarySides(); i++ ) {
1413 std :: vector< FloatArray > oneLineIntersects;
1415 const auto &xStart = element->giveDofManager ( i )->giveCoordinates();
1416 const auto &xEnd = ( i != element->giveNumberOfBoundarySides() ) ?
1417 element->giveDofManager ( i + 1 )->giveCoordinates() :
1418 element->giveDofManager ( 1 )->giveCoordinates();
1419
1420 computeIntersectionPoints(xStart, xEnd, oneLineIntersects);
1421
1422 for ( auto &interSect: oneLineIntersects ) {
1423 // Check that the intersection point has not already been identified.
1424 // This may happen if the crack intersects the element exactly at a node,
1425 // so that intersection is detected for both element edges in that node.
1426
1427 // TODO: Set tolerance in a more transparent way.
1428 double distTol = 1.0e-9;
1429
1430 bool alreadyFound = false;
1431
1432 for ( auto &pInterSect: oIntersectionPoints ) {
1433
1434 if ( distance(pInterSect, interSect) < distTol ) {
1435 alreadyFound = true;
1436 break;
1437 }
1438 }
1439
1440 if ( !alreadyFound ) {
1441 oIntersectionPoints.push_back(interSect);
1442 }
1443 }
1444
1445
1446 }
1447
1448#if 0
1449 printf("Warning: entering PolygonLine :: computeIntersectionPoints(Element *element, std::vector< FloatArray > &oIntersectionPoints).\n");
1450#ifdef __BOOST_MODULE
1451
1452 if ( !boundingBoxIntersects(element) ) {
1453 return;
1454 }
1455
1456
1457 for ( int i = 1; i <= element->giveNumberOfBoundarySides(); i++ ) {
1458 std :: vector< FloatArray >oneLineIntersects;
1460 const auto &a = * element->giveDofManager ( i )->giveCoordinates();
1461 const auto &b = ( i != element->giveNumberOfBoundarySides() ) ?
1462 * element->giveDofManager ( i + 1 )->giveCoordinates() :
1463 * element->giveDofManager ( 1 )->giveCoordinates();
1464
1465 Line l(a, b);
1466
1467 computeIntersectionPoints(& l, oneLineIntersects);
1468 for ( FloatArray &interSect: oneLineIntersects ) {
1469 // Check that the intersection point has not already been identified.
1470 // This may happen if the crack intersects the element exactly at a node,
1471 // so that intersection is detected for both element edges in that node.
1472
1473 // TODO: Set tolerance in a more transparent way.
1474 double distTol = 1.0e-9;
1475
1476 bool alreadyFound = false;
1477
1478 bPoint2 pNew( interSect.at(1), interSect.at(2) );
1479
1480 for ( FloatArray &pInterSect: oIntersectionPoints ) {
1481 bPoint2 pOld( pInterSect.at(1), pInterSect.at(2) );
1482
1483 if ( bDist(pOld, pNew) < distTol ) {
1484 alreadyFound = true;
1485 break;
1486 }
1487 }
1488
1489 if ( !alreadyFound ) {
1490 oIntersectionPoints.push_back(interSect);
1491 }
1492 }
1493 }
1494#endif
1495
1496#endif
1497}
1498
1499void PolygonLine :: computeIntersectionPoints(Line *l, std :: vector< FloatArray > &oIntersectionPoints)
1500{
1501 printf("Warning: entering PolygonLine :: computeIntersectionPoints(Line *l, std::vector< FloatArray > &oIntersectionPoints).\n");
1502
1503#ifdef __BOOST_MODULE
1504
1505
1506 int numSeg = this->giveNrVertices() - 1;
1507
1508
1509 // Segment
1510 bPoint2 lineP1( l->giveVertex ( 1 )->at(1), l->giveVertex ( 1 )->at(2) );
1511 bPoint2 lineP2( l->giveVertex ( 2 )->at(1), l->giveVertex ( 2 )->at(2) );
1512 bSeg2 lineSeg(lineP1, lineP2);
1513
1514
1515 double distTol = 1.0e-9;
1516
1517 bool foundOverlap = false;
1518
1519 // Loop over the crack segments and test each segment for
1520 // overlap with the element
1521 for ( int segId = 1; segId <= numSeg; segId++ ) {
1522 // Crack segment
1523 bPoint2 crackP1( this->giveVertex ( segId )->at(1), this->giveVertex ( segId )->at(2) );
1524 bPoint2 crackP2( this->giveVertex ( segId + 1 )->at(1), this->giveVertex ( segId + 1 )->at(2) );
1525 bSeg2 crackSeg(crackP1, crackP2);
1526
1527 bPoint2 intersectionPoint(0.0, 0.0);
1528 double d = bDist(crackSeg, lineSeg, & intersectionPoint);
1529 if ( d < distTol ) {
1530 if ( !foundOverlap ) {
1531 foundOverlap = true;
1532 oIntersectionPoints.emplace_back({intersectionPoint.x(), intersectionPoint.y()});
1533 }
1534 }
1535 }
1536
1537#endif
1538}
1539
1540void PolygonLine :: computeIntersectionPoints(const PolygonLine &iPolygonLine, std :: vector< FloatArray > &oIntersectionPoints) const
1541{
1542 int numSeg = this->giveNrVertices() - 1;
1543 for(int segIndex = 1; segIndex <= numSeg; segIndex++) {
1544
1545 const FloatArray &xStart = this->giveVertex(segIndex);
1546 const FloatArray &xEnd = this->giveVertex(segIndex+1);
1547
1548 iPolygonLine.computeIntersectionPoints(xStart, xEnd, oIntersectionPoints);
1549 }
1550}
1551
1552void PolygonLine :: computeIntersectionPoints(const FloatArray &iXStart, const FloatArray &iXEnd, std :: vector< FloatArray > &oIntersectionPoints) const
1553{
1554 const double detTol = 1.0e-15;
1555
1556 int numSeg = this->giveNrVertices() - 1;
1557 for(int segIndex = 1; segIndex <= numSeg; segIndex++) {
1558
1559 const FloatArray &xStart = this->giveVertex(segIndex);
1560 const FloatArray &xEnd = this->giveVertex(segIndex+1);
1561
1562 const FloatArray t1 = {xEnd(0) - xStart(0), xEnd(1) - xStart(1)};
1563 const FloatArray t2 = {iXEnd(0) - iXStart(0), iXEnd(1) - iXStart(1)};
1564
1565 double xi1 = 0.0, xi2 = 0.0;
1566 int maxIter = 1;
1567
1568 for(int iter = 0; iter < maxIter; iter++) {
1569 FloatArray temp = {iXStart(0) + xi2*t2(0) - xStart(0) - xi1*t1(0), iXStart(1) + xi2*t2(1) - xStart(1) - xi1*t1(1)};
1570 FloatArray res = {-t1.dotProduct(temp), t2.dotProduct(temp)};
1571
1572 //printf("iter: %d res: %e\n", iter, res.computeNorm() );
1573
1574 FloatMatrix K(2,2);
1575 K(0,0) = t1.dotProduct(t1);
1576 K(0,1) = -t1.dotProduct(t2);
1577 K(1,0) = -t1.dotProduct(t2);
1578 K(1,1) = t2.dotProduct(t2);
1579
1580 double detK = K.giveDeterminant();
1581
1582 if(detK < detTol) {
1583 return;
1584 }
1585
1586 FloatMatrix KInv;
1587 KInv.beInverseOf(K);
1588
1589 FloatArray dxi;
1590 dxi.beProductOf(KInv, res);
1591
1592 xi1 -= dxi[0];
1593 xi2 -= dxi[1];
1594 }
1595
1596// printf("xi1: %e xi2: %e\n", xi1, xi2);
1597
1598
1599 if(xi1 >= 0.0 && xi1 <= 1.0 && xi2 >= 0.0 && xi2 <= 1.0) {
1600 FloatArray pos = xStart;
1601 pos.add(xi1, t1);
1602 oIntersectionPoints.push_back(pos);
1603 }
1604
1605 }
1606
1607}
1608
1609int
1610PolygonLine :: computeNumberOfIntersectionPoints(Element *element)
1611{
1612 std :: vector< FloatArray >intersecPoints;
1613 this->computeIntersectionPoints(element, intersecPoints);
1614 return (int) intersecPoints.size();
1615}
1616
1617bool PolygonLine :: isOutside(BasicGeometry *bg)
1618{
1619 return true;
1620}
1621
1622void PolygonLine :: printYourself()
1623{
1624 printf("PolygonLine:\n");
1625
1626 for(const FloatArray &x : mVertices) {
1627 x.printYourself();
1628 }
1629
1630 printf("\n");
1631}
1632
1633void PolygonLine :: printVTK(int iTStepIndex, int iLineIndex)
1634{
1635 // Debugging function: write crack geometry to vtk.
1636
1637 // Write crack geometry to vtk
1638 std :: string vtkFileName;
1639 vtkFileName.append("crack");
1640 char lineIdNumberString [ 100 ];
1641 sprintf(lineIdNumberString, "%d", iLineIndex);
1642 vtkFileName.append(lineIdNumberString);
1643
1644 vtkFileName.append("Step");
1645 char stepString [ 100 ];
1646
1647 sprintf(stepString, "%d", iTStepIndex);
1648 vtkFileName.append(stepString);
1649
1650 vtkFileName.append(".vtk");
1651
1652
1653 int numPoints = this->giveNrVertices();
1654
1655
1656 std :: ofstream file;
1657 file.open( vtkFileName.data() );
1658
1659 // Write header
1660 file << "# vtk DataFile Version 2.0\n";
1661 file << "Geometry of a PolygonLine\n";
1662 file << "ASCII\n";
1663
1664 file << "DATASET UNSTRUCTURED_GRID\n";
1665
1666
1667 // Write points
1668 file << "POINTS " << numPoints << "double\n";
1669
1670 for ( int i = 1; i <= numPoints; i++ ) {
1671 file << this->giveVertex(i).at(1) << " " << this->giveVertex(i).at(2) << " 0.0\n";
1672 }
1673
1674
1675 // Write segments
1676 int numSeg = numPoints - 1;
1677 file << "CELLS " << numSeg << " " << numSeg * 3 << "\n";
1678
1679 int numPointsPerSeg = 2;
1680 for ( int i = 0; i < numSeg; i++ ) {
1681 file << numPointsPerSeg << " " << i << " " << i + 1 << "\n";
1682 }
1683
1684
1685 // Write cell types
1686 file << "CELL_TYPES " << numSeg << "\n";
1687 int vtkCellType = 3; // line segment
1688 for ( int i = 0; i < numSeg; i++ ) {
1689 file << vtkCellType << "\n";
1690 }
1691
1692 file.close();
1693}
1694
1695
1696bool PolygonLine :: giveTips(TipInfo &oStartTipInfo, TipInfo &oEndTipInfo) const
1697{
1698 int nVert = giveNrVertices();
1699 if ( nVert > 1 ) {
1700 // Start tip
1701 TipInfo info1;
1702 const FloatArray &p1S = ( giveVertex(1) );
1703 const FloatArray &p2S = ( giveVertex(2) );
1704
1705 // Tip position
1706 info1.mGlobalCoord = p1S;
1707
1708 // Tip tangent
1709 info1.mTangDir.beDifferenceOf(p1S, p2S);
1710 info1.mTangDir.normalize();
1711
1712 // Tip normal
1713 info1.mNormalDir = {
1714 -info1.mTangDir.at(2), info1.mTangDir.at(1)
1715 };
1716
1717 info1.mTipIndex = 0;
1718 info1.mArcPos = 0.0;
1719
1720 oStartTipInfo = info1;
1721
1722 // End tip
1723 TipInfo info2;
1724 const FloatArray &p1E = ( giveVertex(nVert - 1) );
1725 const FloatArray &p2E = ( giveVertex(nVert) );
1726
1727 // Tip position
1728 info2.mGlobalCoord = p2E;
1729
1730 // Tip tangent
1731 info2.mTangDir.beDifferenceOf(p2E, p1E);
1732 info2.mTangDir.normalize();
1733
1734 // Tip normal
1735 info2.mNormalDir = {
1736 -info2.mTangDir.at(2), info2.mTangDir.at(1)
1737 };
1738
1739 info2.mTipIndex = 1;
1740 info2.mArcPos = 1.0;
1741
1742 oEndTipInfo = info2;
1743
1744 return true;
1745 }
1746
1747 return false;
1748}
1749
1750void PolygonLine :: giveBoundingSphere(FloatArray &oCenter, double &oRadius)
1751{
1752 int nVert = giveNrVertices();
1753 oCenter = {
1754 0.0, 0.0
1755 };
1756 oRadius = 0.0;
1757
1758 if ( nVert > 0 ) {
1759 for ( int i = 1; i <= nVert; i++ ) {
1760 oCenter.add( giveVertex(i) );
1761 }
1762
1763 oCenter.times( 1.0 / double( nVert ) );
1764
1765 for ( int i = 1; i <= nVert; i++ ) {
1766 oRadius = std :: max( oRadius, distance(oCenter, giveVertex(i) ) );
1767 }
1768 }
1769
1770}
1771
1772void PolygonLine :: cropPolygon(const double &iArcPosStart, const double &iArcPosEnd)
1773{
1774 std::vector<FloatArray> points;
1775 giveSubPolygon(points, iArcPosStart, iArcPosEnd);
1776 setVertices(points);
1777
1778 const double tol2 = 1.0e-18;
1780
1781}
1782
1783void PointSwarm :: initializeFrom(InputRecord &ir)
1784{
1786
1788
1789 for ( int i = 1; i <= idList.giveSize(); i++ ) {
1790 this->idList.push_back( idList.at(i) );
1791 }
1792}
1793} // end namespace oofem
#define N(a, b)
#define REGISTER_Geometry(class)
void insertVertexBack(const FloatArray &iP)
Definition geometry.h:131
const FloatArray & giveVertex(int n) const
Definition geometry.h:124
int giveNrVertices() const
Returns number of Geometry vertices.
Definition geometry.h:144
BasicGeometry()
Constructor.
std ::vector< FloatArray > mVertices
List of geometry vertices.
Definition geometry.h:85
void setVertices(const std::vector< FloatArray > &iVertices)
Definition geometry.h:126
void removeDuplicatePoints(const double &iTolSquare)
Definition geometry.C:67
const double mTangSignDist
Definition geometry.h:256
void computeIntersectionPoints(Element *element, std ::vector< FloatArray > &oIntersectionPoints) override
Gives intersection points between this Geometry and Element.
Definition geometry.C:726
bool intersects(Element *element) override
Checks whether an element is interacted, Element reference will be later replaced by Geometry.
Definition geometry.C:680
bool isInside(Element *element) override
Definition geometry.C:712
double radius
Definition geometry.h:255
double giveCoordinate(int i) const
Definition dofmanager.h:383
const FloatArray & giveCoordinates() const
Definition dofmanager.h:390
void setRecordKeywordField(std ::string keyword, int number)
void setField(int item, InputFieldType id)
Node * giveNode(int i) const
Definition element.h:629
virtual FEInterpolation * giveInterpolation() const
Definition element.h:648
virtual int giveNumberOfBoundarySides()
Returns number of boundaries (entities of element_dimension-1: points, edges, surfaces).
Definition element.C:1430
virtual int giveNumberOfNodes() const
Definition element.h:703
virtual int giveNumberOfDofManagers() const
Definition element.h:695
DofManager * giveDofManager(int i) const
Definition element.C:553
virtual Element_Geometry_Type giveGeometryType() const =0
virtual IntArray boundaryGiveNodes(int boundary, const Element_Geometry_Type) const =0
virtual int giveNumberOfEdges(const Element_Geometry_Type) const
Definition feinterpol.h:550
double computeNorm() const
Definition floatarray.C:861
void resize(Index s)
Definition floatarray.C:94
double distance(const FloatArray &x) const
Definition floatarray.C:551
double & at(Index i)
Definition floatarray.h:202
double computeSquaredNorm() const
Definition floatarray.C:867
double dotProduct(const FloatArray &x) const
Definition floatarray.C:524
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
void resizeWithValues(Index s, std::size_t allocChunk=0)
Definition floatarray.C:103
void beDifferenceOf(const FloatArray &a, const FloatArray &b)
Definition floatarray.C:403
double distance_square(const FloatArray &iP1, const FloatArray &iP2, double &oXi, double &oXiUnbounded) const
Definition floatarray.C:561
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:689
double normalize_giveNorm()
Definition floatarray.C:850
void beScaled(double s, const FloatArray &b)
Definition floatarray.C:208
void beVectorProductOf(const FloatArray &v1, const FloatArray &v2)
Definition floatarray.C:476
void add(const FloatArray &src)
Definition floatarray.C:218
void times(double s)
Definition floatarray.C:834
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
bool beInverseOf(const FloatMatrix &src)
double giveDeterminant() const
double at(std::size_t i, std::size_t j) const
int & at(std::size_t i)
Definition intarray.h:104
int computeNumberOfIntersectionPoints(Element *element) override
Gives number of intersection points of Geometry entity with an element, Element reference will be lat...
Definition geometry.C:264
bool isPointInside(FloatArray *point)
Definition geometry.C:364
double computeInclinationAngle()
Definition geometry.C:325
double computeDistanceTo(const FloatArray &point) override
Computes normal signed distance between this object and a point.
Definition geometry.C:229
void computeTransformationMatrix(FloatMatrix &answer)
Definition geometry.C:334
double giveLength() const
Definition geometry.h:214
void computeProjection(FloatArray &answer)
Definition geometry.C:241
double computeTangentialDistanceToEnd(const FloatArray &point)
Definition geometry.C:246
std ::list< int > idList
Definition geometry.h:361
void giveSubPolygon(std ::vector< FloatArray > &oPoints, const double &iXiStart, const double &iXiEnd) const override
Definition geometry.C:1104
void computeIntersectionPoints(Element *element, std ::vector< FloatArray > &oIntersectionPoints) override
Gives intersection points between this Geometry and Element.
Definition geometry.C:1409
void computeTangentialSignDist(double &oDist, const FloatArray &iPoint, double &oMinDistArcPos) const override
Definition geometry.C:942
double computeLength() const
Definition geometry.C:1083
FloatArray mTangDir
Definition tipinfo.h:32
FloatArray mNormalDir
Definition tipinfo.h:33
double mArcPos
Definition tipinfo.h:31
FloatArray mGlobalCoord
Definition tipinfo.h:30
void computeBarycentrCoor(FloatArray &answer) const
Definition geometry.C:424
double getArea()
Definition geometry.C:410
Triangle(const FloatArray &iP1, const FloatArray &iP2, const FloatArray &iP3)
Definition geometry.C:403
static double giveCharacteristicElementLength()
#define OOFEM_ERROR(...)
Definition error.h:79
#define _IFT_Line_start
Definition geometry.h:57
#define _IFT_Circle_radius
Definition geometry.h:53
#define _IFT_PointSwarm_nodeID
Definition geometry.h:61
#define _IFT_Circle_center
Definition geometry.h:54
#define _IFT_PolygonLine_points
Definition geometry.h:65
#define _IFT_Line_end
Definition geometry.h:58
#define IR_GIVE_FIELD(__ir, __value, __id)
Definition inputrecord.h:67
#define M_PI
Definition mathfem.h:52
static FloatArray Vec2(const double &a, const double &b)
Definition floatarray.h:606
FloatArrayF< N > min(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
FloatArrayF< N > max(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
double sum(const FloatArray &x)
double dot(const FloatArray &x, const FloatArray &y)
double sgn(double i)
Returns the signum of given value (if value is < 0 returns -1, otherwise returns 1).
Definition mathfem.h:104
double distance(const FloatArray &x, const FloatArray &y)
double distance_square(const FloatArray &x, const FloatArray &y)

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011