diff --git a/lckernel/CMakeLists.txt b/lckernel/CMakeLists.txt index 7597a695a..e54e2ac4f 100644 --- a/lckernel/CMakeLists.txt +++ b/lckernel/CMakeLists.txt @@ -147,6 +147,9 @@ pkg_check_modules(LOG4CXX REQUIRED liblog4cxx) include_directories(${LOG4CXX_INCLUDE_DIRS}) link_directories(${LOG4CXX_LIBRARY_DIRS}) +pkg_check_modules(EIGEN REQUIRED eigen3) +include_directories(${EIGEN_INCLUDE_DIRS}) + # BUILDING CONFIG # SEPERATE BUILDING FLAG set(SEPARATE_BUILD OFF) diff --git a/lckernel/cad/math/lcmath.cpp b/lckernel/cad/math/lcmath.cpp index 2823d6bfc..b80ab98f6 100644 --- a/lckernel/cad/math/lcmath.cpp +++ b/lckernel/cad/math/lcmath.cpp @@ -3,6 +3,8 @@ #include "lcmath.h" #include "cad/const.h" #include +#include + using namespace lc; using namespace geo; @@ -63,111 +65,53 @@ double Math::getAngleDifference(double start, double end, bool CCW) { } -std::vector Math::quadraticSolver(const std::vector& ce) -//quadratic solver for -// x^2 + ce[0] x + ce[1] =0 -{ +/** quadratic solver +* x^2 + ce[0] x + ce[1] = 0 +@ce, a vector of size 2 contains the coefficient in order +@return, a vector contains real roots +**/ +std::vector Math::quadraticSolver(const std::vector& ce) { std::vector ans(0, 0.); if (ce.size() != 2) { return ans; } - double b = 0.25 * ce[0] * ce[0]; - double discriminant = b - ce[1]; + Eigen::PolynomialSolver solver; + Eigen::VectorXd coeff(3); - if (discriminant >= - LCTOLERANCE * std::max(std::abs(b), std::abs(ce[1]))) { - b = sqrt(std::abs(discriminant)); - double a = -0.5 * ce[0]; + coeff[0] = ce[1]; + coeff[1] = ce[0]; + coeff[2] = 1; - if (b >= LCTOLERANCE * std::abs(a)) { - ans.push_back(a + b); - ans.push_back(a - b); - } else { - ans.push_back(a); - } - } + solver.compute(coeff); + solver.realRoots(ans); return ans; } -std::vector Math::cubicSolver(const std::vector& ce) -//cubic equation solver -// x^3 + ce[0] x^2 + ce[1] x + ce[2] = 0 -{ - // std::cout<<"x^3 + ("< Math::cubicSolver(const std::vector& ce) { std::vector ans(0, 0.); - if (ce.size() != 3) { return ans; } - // depressed cubic, Tschirnhaus transformation, x= t - b/(3a) - // t^3 + p t +q =0 - double shift = (1. / 3) * ce[0]; - double p = ce[1] - shift * ce[0]; - double q = ce[0] * ((2. / 27) * ce[0] * ce[0] - (1. / 3) * ce[1]) + ce[2]; - //Cardano's method, - // t=u+v - // u^3 + v^3 + ( 3 uv + p ) (u+v) + q =0 - // select 3uv + p =0, then, - // u^3 + v^3 = -q - // u^3 v^3 = - p^3/27 - // so, u^3 and v^3 are roots of equation, - // z^2 + q z - p^3/27 = 0 - // and u^3,v^3 are, - // -q/2 \pm sqrt(q^2/4 + p^3/27) - // discriminant= q^2/4 + p^3/27 - //std::cout<<"p="< 0) ? -pow(q, (1. / 3)) : pow(-q, (1. / 3))); - ans[0] -= shift; - // DEBUG_HEADER(); - // std::cout<<"cubic: one root: "< u(q, 0), rt[3]; - u = std::pow(-0.5 * u - sqrt(0.25 * u * u + p * p * p / 27), 1. / 3); - rt[0] = u - p / (3.*u) - shift; - std::complex w(-0.5, sqrt(3.) / 2); - rt[1] = u * w - p / (3.*u * w) - shift; - rt[2] = u / w - p * w / (3.*u) - shift; - // DEBUG_HEADER(); - // std::cout<<"Roots:\n"; - // std::cout< Math::cubicSolver(const std::vector& ce) @return, a vector contains real roots **/ std::vector Math::quarticSolver(const std::vector& ce) { + // std::cout<<"x^4+("< ans(0, 0.); + Eigen::PolynomialSolver solver; + Eigen::VectorXd coeff(5); - // if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){ - // DEBUG_HEADER(); - // std::cout<<"expected array size=4, got "<getLevel()>=RS_Debug::D_INFORMATIONAL){ - // std::cout<<"x^4+("<getLevel()>=RS_Debug::D_INFORMATIONAL){ - // DEBUG_HEADER(); - // std::cout<<"x^4+("< cubic(3, 0.); - cubic[1] = p; - cubic[2] = q; - ans.push_back(0.); - auto&& r = cubicSolver(cubic); - std::copy(r.begin(), r.end(), back_inserter(ans)); - - for (size_t i = 0; i < ans.size(); i++) { - ans[i] -= shift; - } - - return ans; - } - - // depressed quartic to two quadratic equations - // t^4 + p t^2 + q t + r = ( t^2 + u t + v) ( t^2 - u t + w) - // so, - // p + u^2= w+v - // q/u= w-v - // r= wv - // so, - // (p+u^2)^2 - (q/u)^2 = 4 r - // y=u^2, - // y^3 + 2 p y^2 + ( p^2 - 4 r) y - q^2 =0 - // - std::vector cubic(3, 0.); - cubic[0] = 2.*p; - cubic[1] = p * p - 4.*r; - cubic[2] = -q * q; - auto&& r3 = cubicSolver(cubic); - - //std::cout<<"quartic_solver:: real roots from cubic: "< ce2(2, 0.); - ce2[0] = -sqrtz0; - ce2[1] = 0.5 * (p + r3[0]) + 0.5 * q / sqrtz0; - auto r1 = quadraticSolver(ce2); - - if (r1.size() == 0) { - ce2[0] = sqrtz0; - ce2[1] = 0.5 * (p + r3[0]) - 0.5 * q / sqrtz0; - r1 = quadraticSolver(ce2); - } - - for (size_t i = 0; i < r1.size(); i++) { - r1[i] -= shift; - } - - return r1; - } - - if (r3[0] > 0. && r3[1] > 0.) { - double sqrtz0 = sqrt(r3[0]); - std::vector ce2(2, 0.); - ce2[0] = -sqrtz0; - ce2[1] = 0.5 * (p + r3[0]) + 0.5 * q / sqrtz0; - ans = quadraticSolver(ce2); - ce2[0] = sqrtz0; - ce2[1] = 0.5 * (p + r3[0]) - 0.5 * q / sqrtz0; - auto&& r1 = quadraticSolver(ce2); - std::copy(r1.begin(), r1.end(), back_inserter(ans)); - - for (size_t i = 0; i < ans.size(); i++) { - ans[i] -= shift; - } + coeff[0] = ce[3]; + coeff[1] = ce[2]; + coeff[2] = ce[1]; + coeff[3] = ce[0]; + coeff[4] = 1; - return ans; - } + solver.compute(coeff); + solver.realRoots(ans); return ans; + } /** quartic solver @@ -331,10 +151,7 @@ std::vector Math::quarticSolver(const std::vector& ce) { *ToDo, need a robust algorithm to locate zero terms, better handling of tolerances **/ std::vector Math::quarticSolverFull(const std::vector& ce) { - // if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){ - // DEBUG_HEADER(); - // std::cout< roots(0, 0.); @@ -520,6 +337,7 @@ std::vector Math::simultaneousQuadraticSolverFull(const std // } //quarticSolver auto&& roots = quarticSolverFull(qy); + // if(RS_DEBUG->getLevel()>=RS_Debug::D_INFORMATIONAL){ // std::cout<<"roots.size()= "< +#include + using namespace lc; using namespace entity; diff --git a/unittest/main.cpp b/unittest/main.cpp index 76b7f5b3b..a9009e956 100644 --- a/unittest/main.cpp +++ b/unittest/main.cpp @@ -18,38 +18,6 @@ int main(int argc, char **argv) { return RUN_ALL_TESTS(); } -TEST(test, quad) { - test c; - - - EXPECT_DOUBLE_EQ(-2, c.quad(5, 6)[0]); - EXPECT_DOUBLE_EQ(-3, c.quad(5, 6)[1]); - - EXPECT_TRUE(fabs(c.quad(100, 50)[0]) - 0.50252531694167146 < 0.000000001); - EXPECT_DOUBLE_EQ(-99.497474683058329, c.quad(100, 50)[1]); - - // EXPECT_DOUBLE_EQ(-2, c.quad(5, 6)[0]); - // EXPECT_DOUBLE_EQ(-3, c.quad(5, 6)[1]); - - // EXPECT_DOUBLE_EQ(-2, c.quad(5, 6)[0]); - // EXPECT_DOUBLE_EQ(-3, c.quad(5, 6)[1]); -} - -TEST(test, cubic) { - test c; - - EXPECT_TRUE(fabs(c.cubic(5, 6, 1)[0]) - 0.19806226419516171 < .00000001); - EXPECT_DOUBLE_EQ(-1.5549581320873713, c.cubic(5, 6, 1)[1]); - EXPECT_DOUBLE_EQ(-3.2469796037174667, c.cubic(5, 6, 1)[2]); -} - -TEST(test, quartic) { - test c; - - EXPECT_DOUBLE_EQ(-2.0, c.quartic(5, 6, 1, 2)[0]); - EXPECT_DOUBLE_EQ(-3.1038034027355366, c.quartic(5, 6, 1, 2)[1]); -} - TEST(test, testin) { test a; const double rootY = 200. / sqrt(100. * 100. + 1.); diff --git a/unittest/testmatrices.h b/unittest/testmatrices.h index 27dc01f77..4da467c54 100644 --- a/unittest/testmatrices.h +++ b/unittest/testmatrices.h @@ -3,9 +3,25 @@ #include "cad/geometry/geovector.h" #include "cad/math/lcmath.h" #include +#include using namespace std; +TEST(EIGEN, QUARTICFULL) { + std::vector z = {1080, -126, -123, 6, 3 }; + std::vectorres = {-4,3,-6,5}; + auto v = lc::Math::quarticSolverFull(z); + for(int i = 0; i < v.size(); i++) { + ASSERT_NEAR(res[i], v[i], 1e-6); + } + + std::vector z2 = {2,-41,-42, 360}; + auto v2 = lc::Math::quarticSolver(z2); + for(int i = 0; i < v2.size(); i++) { + ASSERT_NEAR(res[i], v2[i], 1e-6); + } +} + TEST(Matrix, Move) { auto x = lc::maths::Equation(1,2,3,4,5,6).move(lc::geo::Coordinate(5,5)).Coefficients(); @@ -40,7 +56,7 @@ TEST(QM, QUADQUAD) { auto qm2 = ret2.move(_c2); std::vector x = lc::maths::Intersection::QuadQuad(qm1, qm2); - + ASSERT_EQ(x.size(), 2); EXPECT_DOUBLE_EQ(x[0].x(), 3) << "X differs"; EXPECT_DOUBLE_EQ(x[0].y(), 4) << "Y differs"; EXPECT_DOUBLE_EQ(x[1].x(), 3) << "X differs";