Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
dumux-repositories
dumux
Commits
ec972325
Commit
ec972325
authored
Jan 24, 2018
by
Timo Koch
Browse files
[geometry] Implement polyhedron-polygon and segment-polygon intersections in 3D
parent
9a2323e9
Changes
3
Hide whitespace changes
Inline
Side-by-side
dumux/common/geometry/boundingboxtreeintersection.hh
View file @
ec972325
...
...
@@ -45,12 +45,13 @@ class BoundingBoxTreeIntersection
using
GlobalPosition
=
Dune
::
FieldVector
<
ctype
,
dimworld
>
;
public:
template
<
class
Corners
>
explicit
BoundingBoxTreeIntersection
(
std
::
size_t
a
,
std
::
size_t
b
,
std
::
vector
<
GlobalPosition
>
&&
c
)
Corners
&&
c
)
:
a_
(
a
)
,
b_
(
b
)
,
corners_
(
std
::
move
(
c
))
,
corners_
(
c
.
begin
(),
c
.
end
(
))
{
static_assert
(
int
(
EntitySet0
::
dimensionworld
)
==
int
(
EntitySet1
::
dimensionworld
),
"Can only store intersections of entity sets with the same world dimension"
);
...
...
dumux/common/geometry/geometryintersection.hh
View file @
ec972325
...
...
@@ -23,14 +23,16 @@
#ifndef DUMUX_GEOMETRY_INTERSECTION_HH
#define DUMUX_GEOMETRY_INTERSECTION_HH
#include
<dune/common/version.hh>
#include
<dune/common/exceptions.hh>
#include
<dune/common/promotiontraits.hh>
#include
<dune/geometry/referenceelements.hh>
#include
<dumux/common/math.hh>
#include
<dumux/common/geometry/intersectspointgeometry.hh>
#include
<dumux/common/geometry/grahamconvexhull.hh>
namespace
Dumux
{
namespace
Dumux
{
/*!
* \ingroup Common
...
...
@@ -46,11 +48,8 @@ template
class
GeometryIntersection
{
public:
using
ctype
=
typename
Dune
::
PromotionTraits
<
typename
Geometry1
::
ctype
,
typename
Geometry2
::
ctype
>::
PromotedType
;
using
GlobalPosition
=
Dune
::
FieldVector
<
ctype
,
dimworld
>
;
using
IntersectionType
=
std
::
vector
<
GlobalPosition
>
;
//! Determine if the two geometries intersect and compute the intersection corners
template
<
class
IntersectionType
>
static
bool
intersection
(
const
Geometry1
&
geo1
,
const
Geometry2
&
geo2
,
IntersectionType
&
intersection
)
{
static_assert
(
dimworld
==
Geometry2
::
coorddimension
,
"Can only intersect geometries of same coordinate dimension"
);
...
...
@@ -59,19 +58,18 @@ public:
}
};
//!
Geometry collision detection with 3d and 1d geometry
in 3d space
//!
polyhedron--segment intersection
in 3d space
template
<
class
Geometry1
,
class
Geometry2
>
class
GeometryIntersection
<
Geometry1
,
Geometry2
,
3
,
3
,
1
>
{
enum
{
dimworld
=
3
};
enum
{
dim1
=
3
};
enum
{
dim2
=
1
};
enum
{
dimis
=
dim2
};
// the intersection dimension
public:
using
ctype
=
typename
Dune
::
PromotionTraits
<
typename
Geometry1
::
ctype
,
typename
Geometry2
::
ctype
>::
PromotedType
;
using
GlobalPosition
=
Dune
::
FieldVector
<
ctype
,
dimworld
>
;
using
IntersectionType
=
std
::
vector
<
GlobalPosition
>
;
using
Point
=
Dune
::
FieldVector
<
ctype
,
dimworld
>
;
using
IntersectionType
=
std
::
array
<
std
::
vector
<
Point
>
,
1
>
;
private:
static
constexpr
ctype
eps_
=
1.5e-7
;
// base epsilon for floating point comparisons
...
...
@@ -80,7 +78,8 @@ private:
public:
/*!
* \brief Colliding segment and convex polyhedron
* \note Algorithm from "Real-Time Collision Detection" by Christer Ericson
* \note Algorithm based on the one from "Real-Time Collision Detection" by Christer Ericson,
* published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.
* Basis is the theorem that for any two non-intersecting convex polyhedrons
* a separating plane exists.
* \param geo1/geo2 The geometries to intersect
...
...
@@ -116,7 +115,8 @@ public:
facets
=
{{
1
,
2
,
0
},
{
0
,
1
,
3
},
{
0
,
3
,
2
},
{
1
,
2
,
3
}};
break
;
default:
DUNE_THROW
(
Dune
::
NotImplemented
,
"Collision of segment and geometry of type "
<<
geo1
.
type
()
<<
", "
<<
geo1
.
corners
()
<<
" corners."
);
DUNE_THROW
(
Dune
::
NotImplemented
,
"Collision of segment and geometry of type "
<<
geo1
.
type
()
<<
", "
<<
geo1
.
corners
()
<<
" corners."
);
}
return
facets
;
...
...
@@ -168,7 +168,258 @@ public:
}
// If we made it until here an intersection exists. We also export
// the intersections geometry now s(t) = a + t(b-a) in [tfirst, tlast]
intersection
=
{
geo2
.
global
(
tfirst
),
geo2
.
global
(
tlast
)};
intersection
=
{
std
::
vector
<
Point
>
({
geo2
.
global
(
tfirst
),
geo2
.
global
(
tlast
)})};
return
true
;
}
};
//! polyhedron--polygon intersection in 3d space
template
<
class
Geometry1
,
class
Geometry2
>
class
GeometryIntersection
<
Geometry1
,
Geometry2
,
3
,
3
,
2
>
{
enum
{
dimworld
=
3
};
enum
{
dim1
=
3
};
enum
{
dim2
=
2
};
public:
using
ctype
=
typename
Dune
::
PromotionTraits
<
typename
Geometry1
::
ctype
,
typename
Geometry2
::
ctype
>::
PromotedType
;
using
Point
=
Dune
::
FieldVector
<
ctype
,
dimworld
>
;
using
IntersectionType
=
std
::
vector
<
std
::
array
<
Point
,
3
>>
;
private:
static
constexpr
ctype
eps_
=
1.5e-7
;
// base epsilon for floating point comparisons
using
ReferenceElementsGeo1
=
typename
Dune
::
ReferenceElements
<
ctype
,
dim1
>
;
using
ReferenceElementsGeo2
=
typename
Dune
::
ReferenceElements
<
ctype
,
dim2
>
;
public:
/*!
* \brief Colliding segment and convex polyhedron
* \note First we find the vertex candidates for the intersection region as follows:
* Add triangle vertices that are inside the tetrahedron
* Add tetrahedron vertices that are inside the triangle
* Add all intersection points of tetrahedron edges (codim 2) with the triangle (codim 0) (6*1 tests)
* Add all intersection points of triangle edges (codim 1) with tetrahedron faces (codim 1) (3*4 tests)
* Remove duplicate points from the list
* Compute the convex hull polygon
* Return a triangulation of that polygon as intersection
* \param geo1/geo2 The geometries to intersect
* \param intersection A triangulation of the intersection polygon
*/
static
bool
intersection
(
const
Geometry1
&
geo1
,
const
Geometry2
&
geo2
,
IntersectionType
&
intersection
)
{
static_assert
(
int
(
dimworld
)
==
int
(
Geometry2
::
coorddimension
),
"Can only collide geometries of same coordinate dimension"
);
// the candidate intersection points
std
::
vector
<
Point
>
points
;
points
.
reserve
(
10
);
// add 3d geometry corners that are inside the 2d geometry
for
(
int
i
=
0
;
i
<
geo1
.
corners
();
++
i
)
if
(
intersectsPointGeometry
(
geo1
.
corner
(
i
),
geo2
))
points
.
emplace_back
(
geo1
.
corner
(
i
));
// add 2d geometry corners that are inside the 3d geometry
for
(
int
i
=
0
;
i
<
geo2
.
corners
();
++
i
)
if
(
intersectsPointGeometry
(
geo2
.
corner
(
i
),
geo1
))
points
.
emplace_back
(
geo2
.
corner
(
i
));
// get some geometry types
using
PolyhedronFaceGeometry
=
Dune
::
MultiLinearGeometry
<
ctype
,
2
,
dimworld
>
;
using
SegGeometry
=
Dune
::
MultiLinearGeometry
<
ctype
,
1
,
dimworld
>
;
#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6)
const
auto
referenceElement1
=
ReferenceElementsGeo1
::
general
(
geo1
.
type
());
const
auto
referenceElement2
=
ReferenceElementsGeo2
::
general
(
geo2
.
type
());
#else
const
auto
&
referenceElement1
=
ReferenceElementsGeo1
::
general
(
geo1
.
type
());
const
auto
&
referenceElement2
=
ReferenceElementsGeo2
::
general
(
geo2
.
type
());
#endif
// add intersection points of all polyhedron edges (codim dim-1) with the polygon
for
(
int
i
=
0
;
i
<
referenceElement1
.
size
(
dim1
-
1
);
++
i
)
{
const
auto
localEdgeGeom
=
referenceElement1
.
template
geometry
<
dim1
-
1
>(
i
);
const
auto
p
=
geo1
.
global
(
localEdgeGeom
.
corner
(
0
));
const
auto
q
=
geo1
.
global
(
localEdgeGeom
.
corner
(
1
));
const
auto
segGeo
=
SegGeometry
(
Dune
::
GeometryTypes
::
line
,
std
::
vector
<
Point
>
{
p
,
q
});
using
PolySegTest
=
GeometryIntersection
<
Geometry2
,
SegGeometry
>
;
typename
PolySegTest
::
IntersectionType
intersection
;
if
(
PolySegTest
::
template
intersection
<
2
>(
geo2
,
segGeo
,
intersection
))
points
.
emplace_back
(
intersection
[
0
]);
}
// add intersection points of all polygon faces (codim 1) with the polyhedron faces
for
(
int
i
=
0
;
i
<
referenceElement1
.
size
(
1
);
++
i
)
{
const
auto
faceGeo
=
[
&
]()
{
const
auto
localFaceGeo
=
referenceElement1
.
template
geometry
<
1
>(
i
);
if
(
localFaceGeo
.
corners
()
==
4
)
{
const
auto
a
=
geo1
.
global
(
localFaceGeo
.
corner
(
0
));
const
auto
b
=
geo1
.
global
(
localFaceGeo
.
corner
(
1
));
const
auto
c
=
geo1
.
global
(
localFaceGeo
.
corner
(
2
));
const
auto
d
=
geo1
.
global
(
localFaceGeo
.
corner
(
3
));
return
PolyhedronFaceGeometry
(
Dune
::
GeometryTypes
::
cube
(
2
),
std
::
vector
<
Point
>
{
a
,
b
,
c
,
d
});
}
else
{
const
auto
a
=
geo1
.
global
(
localFaceGeo
.
corner
(
0
));
const
auto
b
=
geo1
.
global
(
localFaceGeo
.
corner
(
1
));
const
auto
c
=
geo1
.
global
(
localFaceGeo
.
corner
(
2
));
return
PolyhedronFaceGeometry
(
Dune
::
GeometryTypes
::
simplex
(
2
),
std
::
vector
<
Point
>
{
a
,
b
,
c
});
}
}();
for
(
int
j
=
0
;
j
<
referenceElement2
.
size
(
1
);
++
j
)
{
const
auto
localEdgeGeom
=
referenceElement2
.
template
geometry
<
1
>(
j
);
const
auto
p
=
geo2
.
global
(
localEdgeGeom
.
corner
(
0
));
const
auto
q
=
geo2
.
global
(
localEdgeGeom
.
corner
(
1
));
const
auto
segGeo
=
SegGeometry
(
Dune
::
GeometryTypes
::
line
,
std
::
vector
<
Point
>
{
p
,
q
});
using
PolySegTest
=
GeometryIntersection
<
PolyhedronFaceGeometry
,
SegGeometry
>
;
typename
PolySegTest
::
IntersectionType
intersection
;
if
(
PolySegTest
::
template
intersection
<
2
>(
faceGeo
,
segGeo
,
intersection
))
points
.
emplace_back
(
intersection
[
0
]);
}
}
// return if no intersection points were found
if
(
points
.
empty
())
return
false
;
// remove duplicates
const
auto
eps
=
(
geo1
.
corner
(
0
)
-
geo1
.
corner
(
1
)).
two_norm
()
*
eps_
;
std
::
sort
(
points
.
begin
(),
points
.
end
(),
[
&
eps
](
const
auto
&
a
,
const
auto
&
b
)
->
bool
{
return
(
abs
(
a
[
0
]
-
b
[
0
])
>
eps
?
a
[
0
]
<
b
[
0
]
:
(
abs
(
a
[
1
]
-
b
[
1
])
>
eps
?
a
[
1
]
<
b
[
1
]
:
(
a
[
2
]
<
b
[
2
])));
});
auto
removeIt
=
std
::
unique
(
points
.
begin
(),
points
.
end
(),
[
&
eps
](
const
auto
&
a
,
const
auto
&
b
)
{
return
(
b
-
a
).
two_norm
()
<
eps
;
});
points
.
erase
(
removeIt
,
points
.
end
());
// return false if we don't have more than three unique points
if
(
points
.
size
()
<
3
)
return
false
;
// compute convex hull
const
auto
convexHull
=
grahamConvexHull2d3d
(
points
);
// the intersections are the triangulation of the convex hull polygon
intersection
=
triangulateConvexHull
(
convexHull
);
return
true
;
}
};
//! polygon--segment intersection in 3d space
template
<
class
Geometry1
,
class
Geometry2
>
class
GeometryIntersection
<
Geometry1
,
Geometry2
,
3
,
2
,
1
>
{
enum
{
dimworld
=
3
};
enum
{
dim1
=
2
};
enum
{
dim2
=
1
};
public:
using
ctype
=
typename
Dune
::
PromotionTraits
<
typename
Geometry1
::
ctype
,
typename
Geometry2
::
ctype
>::
PromotedType
;
using
Point
=
Dune
::
FieldVector
<
ctype
,
dimworld
>
;
using
IntersectionType
=
std
::
vector
<
Point
>
;
private:
static
constexpr
ctype
eps_
=
1.5e-7
;
// base epsilon for floating point comparisons
using
ReferenceElements
=
typename
Dune
::
ReferenceElements
<
ctype
,
dim1
>
;
public:
/*!
* \brief Colliding segment and convex polyhedron
* \note Algorithm based on the one from "Real-Time Collision Detection" by Christer Ericson,
* published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc. (Chapter 5.3.6)
* \param geo1/geo2 The geometries to intersect
* \param intersection If the geometries collide intersection holds the corner points of
* the intersection object in global coordinates.
*/
template
<
int
dimIntersection
>
static
bool
intersection
(
const
Geometry1
&
geo1
,
const
Geometry2
&
geo2
,
IntersectionType
&
is
)
{
if
(
dimIntersection
!=
2
)
DUNE_THROW
(
Dune
::
NotImplemented
,
"Only simplex intersections are currently implemented!"
);
static_assert
(
int
(
dimworld
)
==
int
(
Geometry2
::
coorddimension
),
"Can only collide geometries of same coordinate dimension"
);
const
auto
p
=
geo2
.
corner
(
0
);
const
auto
q
=
geo2
.
corner
(
1
);
const
auto
a
=
geo1
.
corner
(
0
);
const
auto
b
=
geo1
.
corner
(
1
);
const
auto
c
=
geo1
.
corner
(
2
);
if
(
geo1
.
corners
()
==
3
)
return
intersection
<
dimIntersection
>
(
a
,
b
,
c
,
p
,
q
,
is
);
else
if
(
geo1
.
corners
()
==
4
)
{
const
auto
d
=
geo1
.
corner
(
3
);
if
(
intersection
<
dimIntersection
>
(
a
,
b
,
d
,
p
,
q
,
is
))
return
true
;
else
if
(
intersection
<
dimIntersection
>
(
a
,
d
,
c
,
p
,
q
,
is
))
return
true
;
else
return
false
;
}
else
DUNE_THROW
(
Dune
::
NotImplemented
,
"Collision of segment and geometry of type "
<<
geo1
.
type
()
<<
", "
<<
geo1
.
corners
()
<<
" corners."
);
}
// triangle--segment intersection with points as input
template
<
int
dimIntersection
>
static
bool
intersection
(
const
Point
&
a
,
const
Point
&
b
,
const
Point
&
c
,
const
Point
&
p
,
const
Point
&
q
,
IntersectionType
&
is
)
{
if
(
dimIntersection
!=
2
)
DUNE_THROW
(
Dune
::
NotImplemented
,
"Only simplex intersections are currently implemented!"
);
const
auto
ab
=
b
-
a
;
const
auto
ac
=
c
-
a
;
const
auto
qp
=
p
-
q
;
// compute the triangle normal that defines the triangle plane
const
auto
normal
=
crossProduct
(
ab
,
ac
);
// compute the denominator
// if denom is 0 the segment is parallel and we can return
const
auto
denom
=
normal
*
qp
;
const
auto
eps
=
eps_
*
ab
.
two_norm2
()
*
qp
.
two_norm
();
using
std
::
abs
;
if
(
abs
(
denom
)
<
eps
)
return
false
;
// compute intersection t value of pq with plane of triangle.
// a segment intersects if and only if 0 <= t <= 1.
const
auto
ap
=
p
-
a
;
const
auto
t
=
(
ap
*
normal
)
/
denom
;
if
(
t
<
0.0
-
eps_
)
return
false
;
if
(
t
>
1.0
+
eps_
)
return
false
;
// compute the barycentric coordinates and check if the intersection point
// is inside the bounds of the triangle
const
auto
e
=
crossProduct
(
qp
,
ap
);
const
auto
v
=
(
ac
*
e
)
/
denom
;
if
(
v
<
-
eps_
||
v
>
1.0
+
eps_
)
return
false
;
const
auto
w
=
-
(
ab
*
e
)
/
denom
;
if
(
w
<
-
eps_
||
v
+
w
>
1.0
+
eps_
)
return
false
;
// Now we are sure there is an intersection points
// Perform delayed division compute the last barycentric coordinate component
const
auto
u
=
1.0
-
v
-
w
;
Point
ip
(
0.0
);
ip
.
axpy
(
u
,
a
);
ip
.
axpy
(
v
,
b
);
ip
.
axpy
(
w
,
c
);
is
=
{
ip
};
return
true
;
}
};
...
...
dumux/common/geometry/intersectingentities.hh
View file @
ec972325
...
...
@@ -145,7 +145,10 @@ void intersectingEntities(const BoundingBoxTree<EntitySet0>& treeA,
std
::
decay_t
<
decltype
(
geometryB
)
>
>
;
typename
IntersectionAlgorithm
::
IntersectionType
intersection
;
if
(
IntersectionAlgorithm
::
intersection
(
geometryA
,
geometryB
,
intersection
))
intersections
.
emplace_back
(
eIdxA
,
eIdxB
,
std
::
move
(
intersection
));
{
for
(
int
i
=
0
;
i
<
intersection
.
size
();
++
i
)
intersections
.
emplace_back
(
eIdxA
,
eIdxB
,
std
::
move
(
intersection
[
i
]));
}
}
// if we reached the leaf in treeA, just continue in treeB
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment