@@ -1861,15 +1861,16 @@ class BezierPatch
1861
1861
}
1862
1862
1863
1863
/* !
1864
- * \brief Predicate to check if the Bezier patch is approximately planar
1864
+ * \brief Predicate to check if the Bezier patch is approximately planar (i.e. flat)
1865
1865
*
1866
1866
* This function checks if all control points of the BezierPatch
1867
1867
* are approximately on the plane defined by its four corners
1868
1868
*
1869
- * \param [in] tol Threshold for sum of squared distances
1870
- * \return True if c1 is near-planar
1869
+ * \param [in] sq_tol Threshold for sum of squared distances
1870
+ * \param [in] EPS Threshold for nearness to zero
1871
+ * \return True if the object is planar up to tolerance \a sq_tol
1871
1872
*/
1872
- bool isPlanar (double tol = 1E -8 ) const
1873
+ bool isPlanar (double sq_tol = 1e-8 , double EPS = 1e -8 ) const
1873
1874
{
1874
1875
const int ord_u = getOrder_u ();
1875
1876
const int ord_v = getOrder_v ();
@@ -1894,49 +1895,51 @@ class BezierPatch
1894
1895
if (!axom::utilities::isNearlyEqual (
1895
1896
VectorType::scalar_triple_product (v1, v2, v3),
1896
1897
0.0 ,
1897
- tol ))
1898
+ EPS ))
1898
1899
{
1899
1900
return false ;
1900
1901
}
1901
1902
1902
1903
// Find three points that produce a nonzero normal
1903
1904
Vector3D plane_normal = VectorType::cross_product (v1, v2);
1904
- if (axom::utilities::isNearlyEqual (plane_normal.norm (), 0.0 , tol ))
1905
+ if (axom::utilities::isNearlyEqual (plane_normal.norm (), 0.0 , EPS ))
1905
1906
{
1906
1907
plane_normal = VectorType::cross_product (v1, v3);
1907
1908
}
1908
- if (axom::utilities::isNearlyEqual (plane_normal.norm (), 0.0 , tol ))
1909
+ if (axom::utilities::isNearlyEqual (plane_normal.norm (), 0.0 , EPS ))
1909
1910
{
1910
1911
plane_normal = VectorType::cross_product (v2, v3);
1911
1912
}
1912
1913
plane_normal = plane_normal.unitVector ();
1913
1914
1914
- double sqDist = 0.0 ;
1915
-
1916
1915
// Check all control points for simplicity
1917
- for (int p = 0 ; p <= ord_u && sqDist <= tol ; ++p)
1916
+ for (int p = 0 ; p <= ord_u; ++p)
1918
1917
{
1919
- for (int q = ((p == 0 ) ? 1 : 0 ); q <= ord_v && sqDist <= tol ; ++q)
1918
+ for (int q = ((p == 0 ) ? 1 : 0 ); q <= ord_v; ++q)
1920
1919
{
1921
1920
const double signedDist =
1922
1921
plane_normal.dot (m_controlPoints (p, q) - m_controlPoints (0 , 0 ));
1923
- sqDist += signedDist * signedDist;
1922
+
1923
+ if (signedDist * signedDist > sq_tol)
1924
+ {
1925
+ return false ;
1926
+ }
1924
1927
}
1925
1928
}
1926
-
1927
- return (sqDist <= tol);
1929
+ return true ;
1928
1930
}
1929
1931
1930
1932
/* !
1931
1933
* \brief Predicate to check if the patch can be approximated by a polygon
1932
1934
*
1933
1935
* This function checks if a BezierPatch lies in a plane
1934
- * and that the edged are linear up to tolerance `tol `
1936
+ * and that the edges are linear up to tolerance `sq_tol `
1935
1937
*
1936
1938
* \param [in] tol Threshold for sum of squared distances
1937
- * \return True if c1 is near-planar-polygonal
1939
+ * \param [in] EPS Threshold for nearness to zero
1940
+ * \return True if c1 is planar-polygonal up to tolerance \a sq_tol
1938
1941
*/
1939
- bool isPolygonal (double tol = 1E -8 ) const
1942
+ bool isPolygonal (double sq_tol = 1e-8 , double EPS = 1e -8 ) const
1940
1943
{
1941
1944
const int ord_u = getOrder_u ();
1942
1945
const int ord_v = getOrder_v ();
@@ -1955,32 +1958,128 @@ class BezierPatch
1955
1958
}
1956
1959
1957
1960
// Check if the patch is planar
1958
- if (!isPlanar (tol ))
1961
+ if (!isPlanar (sq_tol, EPS ))
1959
1962
{
1960
1963
return false ;
1961
1964
}
1962
1965
1963
1966
// Check if each bounding curve is linear
1964
- if (!isocurve_u (0 ).isLinear (tol ))
1967
+ if (!isocurve_u (0 ).isLinear (sq_tol ))
1965
1968
{
1966
1969
return false ;
1967
1970
}
1968
- if (!isocurve_v (0 ).isLinear (tol ))
1971
+ if (!isocurve_v (0 ).isLinear (sq_tol ))
1969
1972
{
1970
1973
return false ;
1971
1974
}
1972
- if (!isocurve_u (1 ).isLinear (tol ))
1975
+ if (!isocurve_u (1 ).isLinear (sq_tol ))
1973
1976
{
1974
1977
return false ;
1975
1978
}
1976
- if (!isocurve_v (1 ).isLinear (tol ))
1979
+ if (!isocurve_v (1 ).isLinear (sq_tol ))
1977
1980
{
1978
1981
return false ;
1979
1982
}
1980
1983
1981
1984
return true ;
1982
1985
}
1983
1986
1987
+ /* !
1988
+ * \brief Predicate to check if the Bezier patch is approximately bilinear
1989
+ *
1990
+ * This function checks if the patch is (nearly) bilinear.
1991
+ * A necessary condition for a geometrically bilinear patch is that each line of
1992
+ * control points in the net is approximately linear.
1993
+ * A necessary condition for a parametrically bilinear patch is that the control
1994
+ * points are coincident with the surface of the bilinear patch defined by
1995
+ * its corners evaluated at uniform parameter values,
1996
+ * i.e. the control points are also equally spaced on the net.
1997
+ *
1998
+ * \param [in] sq_tol Threshold for absolute squared distances
1999
+ * \param [in] useStrictBilinear If true, require the patch be parametrically bilinear
2000
+ * \return True if patch is bilinear up to tolerance \a sq_tol
2001
+ */
2002
+ bool isBilinear (double sq_tol = 1e-8 , bool useStrictBilinear = false ) const
2003
+ {
2004
+ const int ord_u = getOrder_u ();
2005
+ const int ord_v = getOrder_v ();
2006
+
2007
+ if (ord_u <= 1 && ord_v <= 1 )
2008
+ {
2009
+ return true ;
2010
+ }
2011
+
2012
+ if (useStrictBilinear)
2013
+ {
2014
+ // Anonymous function to evaluate the bilinear patch defined by the corners
2015
+ auto bilinear_patch = [&](T u, T v) -> PointType {
2016
+ PointType val;
2017
+ for (int N = 0 ; N < NDIMS; ++N)
2018
+ {
2019
+ val[N] = axom::utilities::lerp (
2020
+ axom::utilities::lerp (m_controlPoints (0 , 0 )[N],
2021
+ m_controlPoints (0 , ord_v)[N],
2022
+ v),
2023
+ axom::utilities::lerp (m_controlPoints (ord_u, 0 )[N],
2024
+ m_controlPoints (ord_u, ord_v)[N],
2025
+ v),
2026
+ u);
2027
+ }
2028
+ return val;
2029
+ };
2030
+
2031
+ for (int u = 0 ; u <= ord_u; ++u)
2032
+ {
2033
+ for (int v = 0 ; v <= ord_v; ++v)
2034
+ {
2035
+ // Don't need to check the corners
2036
+ if ((u == 0 && v == 0 ) || (u == 0 && v == ord_v) ||
2037
+ (u == ord_u && v == 0 ) || (u == ord_u && v == ord_v))
2038
+ {
2039
+ continue ;
2040
+ }
2041
+
2042
+ // Evaluate where the control point would be if the patch *was* bilinear
2043
+ PointType bilinear_point =
2044
+ bilinear_patch (u / static_cast <T>(ord_u), v / static_cast <T>(ord_v));
2045
+
2046
+ if (squared_distance (m_controlPoints (u, v), bilinear_point) > sq_tol)
2047
+ {
2048
+ return false ;
2049
+ }
2050
+ }
2051
+ }
2052
+ }
2053
+ else
2054
+ {
2055
+ for (int p = 0 ; p <= ord_u; ++p)
2056
+ {
2057
+ Segment<T, 3 > seg (m_controlPoints (p, 0 ), m_controlPoints (p, ord_v));
2058
+ for (int q = 1 ; q < ord_v; ++q)
2059
+ {
2060
+ if (squared_distance (m_controlPoints (p, q), seg))
2061
+ {
2062
+ return false ;
2063
+ }
2064
+ }
2065
+ }
2066
+
2067
+ for (int q = 0 ; q <= ord_v; ++q)
2068
+ {
2069
+ Segment<T, 3 > seg (m_controlPoints (0 , q), m_controlPoints (ord_u, q));
2070
+ for (int p = 1 ; p < ord_u; ++p)
2071
+ {
2072
+ if (squared_distance (m_controlPoints (p, q), seg))
2073
+ {
2074
+ return false ;
2075
+ }
2076
+ }
2077
+ }
2078
+ }
2079
+
2080
+ return true ;
2081
+ }
2082
+
1984
2083
/* !
1985
2084
* \brief Simple formatted print of a Bezier Patch instance
1986
2085
*
0 commit comments