【问题标题】:CGAL: Point on the line?CGAL:点就行了?
【发布时间】:2014-05-29 16:27:02
【问题描述】:

我在 CGAL 中遇到了一件奇怪的事情。我有一条线和一个应该在这条线上的点。这段代码

typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;

int main( ) {
  CGAL::Line_2<Kernel> l(0.2, 1.0, -1.4);

  std::cout << l.has_on(CGAL::Point_2<Kernel>(-3.0, 2.0)) << std::endl;
  std::cout << l.y_at_x(-3.0).exact() << std::endl;

  return 0;
}

产生输出:

0
36028797018963967/18014398509481984

好吧,也许Exact_predicates_exact_constructions_kernel 不够好...(为什么?)

我尝试改用CGAL::Quotient 定义的内核:

typedef CGAL::Quotient<CGAL::MP_Float> NT;
typedef CGAL::Cartesian<NT> Kernel;

int main( ) {
  CGAL::Line_2<Kernel> l(0.2, 1.0, -1.4);

  std::cout << l.has_on(CGAL::Point_2<Kernel>(-3.0, 2.0)) << std::endl;
  std::cout << l.y_at_x(-3.0) << std::endl;

  return 0;
}

结果对我来说更加神秘:

0
2/1

是我遗漏了什么还是一个错误?

【问题讨论】:

    标签: precision cgal


    【解决方案1】:

    当您从 0.2 构造线时,会发生两次转换。编译器将字符串“0.2”转换为双精度。然后,这个 double 被转换为内核的数字类型(在这种情况下是一个精确的有理数)。

    问题在于 0.2 到 double 的转换并不精确,因为 0.2 是一个不能用浮点值表示的有理数,因此引入了一些不精确性。 CGAL 对此无能为力。

    如果你需要准确地表示 0.2,你需要使用类似的东西:

      CGAL::Line_2<Kernel> l(NT(2)/NT(10), 1.0, NT(-14)/NT(10));
    

    或者,将您的问题按 10 次方缩放,以便您的所有坐标都变为整数。

    也有可能某些有理数类型能够直接从表示有理数的字符串构造而无需任何舍入,但我认为CGAL::Quotient&lt;MP_Float&gt; 不能。

    【讨论】:

    • 谢谢!这消除了我的一些困惑。你能解释一下为什么l.y_at_x(-3.0) 在第二种情况下会产生2/1 吗?为什么在这种情况下,前一行给出的是 0 而不是 1?
    • 这里发生的情况是该值不完全是 2,而是在打印时四舍五入为 2。您可以通过减去 2 来查看差异: std::cout
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-22
    • 2014-06-22
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多