c++ - 几何库中的算法和数据分离(需要三重调度?)

标签 c++ downcast double-dispatch

我在设计处理几何的应用程序部分时遇到问题。特别是,我希望有一个类的层次结构和用于交叉点的单独方法。

问题

层次结构是这样的:

  • 几何
    • 网格
    • 参数化
      • 盒子
      • 领域

交集方法类似于:

namespace intersections
{
  bool intersection( const Box &, const Box &);
  bool intersection( const Box &, const Sphere &);
}

这很简单。现在问题出现了,当我想将所有几何图形一起存储在一个结构中时,例如 std::vector (或 KD 树,或其他)。

为此,我需要使用 std::vector<Geometry*> .然而,从这个 vector 中读取会让我得到 Geometry*对象,因此我无法调用适当的交集函数。

问题示例:

std::vector<Geometry*> arrGeometry;

// add the elements
arrGeometry.push( new Box() );
arrGeometry.push( new Sphere() );

// ... some more code

// try to intersect them?
Geometry* g1 = arrGeometry[0];
Geometry* g2 = arrGeometry[1];
bool intersecting = intersections::intersection( g1, g2 ); //< As expected, this does
                                                          // not work

如果我在几何对象内部实现算法,问题可以由访问者和一些非常奇怪的函数调用弹跳来解决。

但是,我想将相交算法保留在几何类之外。原因是:

  • 避免决定谁应该拥有所有权(例如,在 BoxSphere 中实现方框和球体之间的交集?)

  • 为了避免使几何对象困惑,所有可以对几何进行的操作都很多(仅举几例:体素化、计算交点、应用构造性几何运算符...)。因此,在这里非常需要将逻辑与数据分开。

另一方面,我需要一个层次结构而不是模板,因为对于某些东西,特定的几何图形可以被抽象掉......(例如,将其存储在 std::vector 或 KD 树中,或……)。

你会如何解决这个问题?有没有适合这个的设计模式?我尝试查看一些库,但结果我更加困惑,因为我已经是...

最简单的方法(有时会使用)是使用 RTTI(或伪造它)和向下转换,但这并不是完全可维护的...(添加新几何意味着更改大量 switch 语句,尽管所有代码).

有什么想法吗?

非常感谢您。

最佳答案

我想到了另一个解决方案,如果您关心速度,这具有 O(1) 的复杂性,但您可能需要程序来自动生成模式几何类型的 C++ 代码。您可以创建交集函数数组(伪代码,我手边没有任何编译器):

enum GeometryType
{
    TypeMesh,
    TypeParamBox,
    TypeParamSphere,
    MaxType,
};

bool intersection( const Mesh*, const Mesh* );
bool intersection( const Mesh*, const Box* );
bool intersection( const Mesh*, const Sphere* );

bool intersection( const Box*, const Mesh* );
bool intersection( const Box*, const Box* );
bool intersection( const Box*, const Sphere* );

bool intersection( const Sphere*, const Mesh* );
bool intersection( const Sphere*, const Box* );
bool intersection( const Sphere*, const Sphere* );

template<class T1,class T2>
bool t_intersection( const Geometry* first, const Geometry* second )
{
    return intersection( static_cast<const T1*>( first ), static_cast<const T1*>( second ) );
}

typedef bool (*uni_intersect)( const Geometry*, const Geometry* );

const uni_intersect IntersectionArray[] = // 2D array all possible combinations
{
    t_intersection<Mesh,Mesh>,
    t_intersection<Mesh,Box>,
    t_intersection<Mesh,Sphere>,

    t_intersection<Box,Mesh>,
    t_intersection<Box,Box>,
    t_intersection<Box,Sphere>,

    t_intersection<Sphere,Mesh>,
    t_intersection<Sphere,Box>,
    t_intersection<Sphere,Sphere>,
};

bool main_intersection( const Geometry* first, const Geometry* second )
{
    const unsigned index = (unsigned)(first->Type) * (unsigned)MaxType + (unsigned)(second->Type);
    return IntersectionArray[ index ]( first, second );
}

或者选择:

const uni_intersect IntersectionArray[] = // 2D array all possible combinations
{
    t_intersection<Mesh,Mesh>,
    t_intersection<Mesh,Box>,
    t_intersection<Mesh,Sphere>,

    nullptr, // skip mirrored functions
    t_intersection<Box,Box>,
    t_intersection<Box,Sphere>,

    nullptr,
    nullptr,
    t_intersection<Sphere,Sphere>,
};

bool main_intersection( const Geometry* first, const Geometry* second )
{
    const unsigned Type1 = unsigned(first->Type);
    const unsigned Type2 = unsigned(second->Type);
    unsigned index;
    if( Type1 < Type2 )
        index = Type1 * (unsigned)MaxType + Type2;
    else
        index = Type1 + Type2 * (unsigned)MaxType;

    return IntersectionArray[ index ]( first, second );
}

关于c++ - 几何库中的算法和数据分离(需要三重调度?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12642561/

相关文章:

c++ - 向上转换和向下转换对象时出现无效的初始化错误

C++ double dispatch 观察者通知

具有镜像层次结构的 C++ 双重分派(dispatch)

c++ - Arduino:如何向任何文本框或记事本显示 Serial.print 值

c++ - 使用opencv时未定义对各种函数的引用

c++ - 在 Android 上编译 OpenSSL

c++ - 我们在 C++ 中需要双重调度/访问者到底发生了什么

c++ - 输出错误。可能的 strncpy 问题?

java - 为什么向下转换在 C++ 中是一种不好的做法,而不是在另一种语言中?

c++ - 在 C++ 中,是否可以将 CRTP 与私有(private)基一起使用?