Commit f0203616 authored by Mark Meredith's avatar Mark Meredith
Browse files

Merge branch 'dr/csg_linear_rotate_extrudes' into 'master'

Dr/csg linear rotate extrudes

See merge request exa/mfix-parser!15
parents 15002ec2 9110ff69
Loading
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -5,7 +5,8 @@ add_library(csg)

target_sources(csg PRIVATE
  src/csg/impl/parser.cpp
  src/csg/impl/levelset.cpp
  src/csg/impl/levelset_3d.cpp
  src/csg/impl/levelset_2d.cpp
  src/csg/impl/csg.cpp
  )

+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ class CsgIF::Impl {
public:
  double call_signed_distance(const std::shared_ptr<Tree> &a_tree, double xx,
                              double yy, double zz) const {
    return signed_distance(a_tree->top, xx, yy, zz);
    return signed_distance_3d(a_tree->top, xx, yy, zz);
  }
};

+75 −17
Original line number Diff line number Diff line
@@ -9,6 +9,15 @@

namespace csg {

struct Circle {
  double radius;
};

struct Square {
  std::tuple<double, double> size;
  bool center;
};

struct Sphere {
  double radius;
};
@@ -31,38 +40,87 @@ struct Cone {
  bool center;
};

struct Mulmatrix;
struct Union;
struct Intersection;
struct Difference;
enum Dimension { D2, D3 };

template <Dimension dim> struct Mulmatrix;
template <Dimension dim> struct Union;
template <Dimension dim> struct Intersection;
template <Dimension dim> struct Difference;
struct LinearExtrude;
struct RotateExtrude;

using Type = std::variant<Sphere, Cube, Cylinder, Cone, Union, Intersection,
                          Difference, Mulmatrix>;
template <Dimension dim> struct TypeHelper;

struct Union {
  std::vector<Type> objs;
template <> struct TypeHelper<Dimension::D2> {
  using Type =
      std::variant<Circle, Square, Union<Dimension::D2>,
                   Intersection<Dimension::D2>, Difference<Dimension::D2>,
                   Mulmatrix<Dimension::D2>>;
};

struct Intersection {
  std::vector<Type> objs;
template <> struct TypeHelper<Dimension::D3> {
  using Type =
      std::variant<Sphere, Cube, Cylinder, Cone, Union<Dimension::D3>,
                   Intersection<Dimension::D3>, Difference<Dimension::D3>,
                   Mulmatrix<Dimension::D3>, LinearExtrude, RotateExtrude>;
};

struct Difference {
  std::shared_ptr<Type> first_obj;
  Union next_objs;
template <Dimension dim> struct Union {
  std::vector<typename TypeHelper<dim>::Type> objs;
};

struct Mulmatrix {
template <Dimension dim> struct Intersection {
  std::vector<typename TypeHelper<dim>::Type> objs;
};

template <Dimension dim> struct Difference {
  std::shared_ptr<typename TypeHelper<dim>::Type> first_obj;
  Union<dim> next_objs;
};

template <> struct Mulmatrix<Dimension::D3> {
  std::array<std::array<double, 3>, 3> rotation;
  std::array<double, 3> translation;
  Union group;
  Union<Dimension::D3> group;
};

template <> struct Mulmatrix<Dimension::D2> {
  std::array<std::array<double, 2>, 2> rotation;
  std::array<double, 2> translation;
  Union<Dimension::D2> group;
};

struct LinearExtrude {
  double height;
  bool center;
  double twist;
  Union<Dimension::D2> group;
};

struct RotateExtrude {
  double angle;
  Union<Dimension::D2> group;
};

struct Tree {
  Union top;
  Union<Dimension::D3> top;
};

double signed_distance(const Union &, double, double, double);
const double EXTERNAL_FLOW = -1.0;

double signed_distance_3d(const Union<Dimension::D3> &, double, double, double);

// defining some useful aliases
using Mulmatrix3D = Mulmatrix<Dimension::D3>;
using Mulmatrix2D = Mulmatrix<Dimension::D2>;
using Union3D = Union<Dimension::D3>;
using Union2D = Union<Dimension::D2>;
using Intersection3D = Intersection<Dimension::D3>;
using Intersection2D = Intersection<Dimension::D2>;
using Difference3D = Difference<Dimension::D3>;
using Difference2D = Difference<Dimension::D2>;
using Type2D = TypeHelper<Dimension::D2>::Type;
using Type3D = TypeHelper<Dimension::D3>::Type;

} // namespace csg

+98 −0
Original line number Diff line number Diff line
#include "csg_types.hpp"

#include <algorithm>
#include <cmath>
#include <iostream>
#include <limits>

namespace {

template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template <class... Ts>
// clang-format off
overloaded(Ts...) -> overloaded<Ts...>; // not needed as of C++20
// clang-format on

} // namespace

namespace csg {

double signed_distance_2d(const Square &, double, double);
double signed_distance_2d(const Circle &, double, double);
double signed_distance_2d(const Type2D &, double, double);
double signed_distance_2d(const Difference2D &, double, double);
double signed_distance_2d(const Intersection2D &, double, double);
double signed_distance_2d(const Mulmatrix2D &, double, double);
double signed_distance_2d(const Union2D &, double, double);

double signed_distance_2d(const Union2D &group, double xx, double yy) {
  auto sdist = -std::numeric_limits<double>::max();
  for (const auto &member : group.objs) {
    auto sd = signed_distance_2d(member, xx, yy);
    sdist = std::max(sdist, sd);
  };

  return sdist;
}

double signed_distance_2d(const Intersection2D &group, double xx, double yy) {
  auto sdist = std::numeric_limits<double>::max();
  for (const auto &member : group.objs) {
    auto sd = signed_distance_2d(member, xx, yy);
    sdist = std::min(sdist, sd);
  };
  return sdist;
}

double signed_distance_2d(const Difference2D &group, double xx, double yy) {
  auto sdist = signed_distance_2d(*group.first_obj, xx, yy);

  for (const auto &member : group.next_objs.objs) {
    auto sd = signed_distance_2d(member, xx, yy);
    sdist = std::min(sdist, -sd);
  };
  return sdist;
}

double signed_distance_2d(const Mulmatrix2D &mm, double xx, double yy) {
  // TODO: Invert non-orthogonal matrices
  auto XX = xx - mm.translation[0];
  auto YY = yy - mm.translation[1];
  return signed_distance_2d(mm.group,
                            mm.rotation[0][0] * XX + mm.rotation[1][0] * YY,
                            mm.rotation[0][1] * XX + mm.rotation[1][1] * YY);
}

double signed_distance_2d(const Square &sq, double xx, double yy) {

  auto [Lx, Ly] = sq.size;
  auto XX = sq.center ? xx + Lx / 2 : xx;
  double sign_x = (XX >= 0 && XX <= Lx) ? -1.0 : 1.0;
  auto dist_x = std::min(std::fabs(XX), std::fabs(XX - Lx));

  auto YY = sq.center ? yy + Ly / 2 : yy;
  double sign_y = (YY >= 0 && YY <= Ly) ? -1.0 : 1.0;
  auto dist_y = std::min(std::fabs(YY), std::fabs(YY - Ly));

  return EXTERNAL_FLOW * std::max(sign_x * dist_x, sign_y * dist_y);
}

double signed_distance_2d(const Circle &cir, double xx, double yy) {

  auto delta = xx * xx + yy * yy - cir.radius * cir.radius;
  double sign = delta <= 0 ? -1.0 : 1.0;
  auto dist = std::fabs(delta);

  return EXTERNAL_FLOW * sign * dist;
}

double signed_distance_2d(const Type2D &obj, double xx, double yy) {

  return std::visit(
      overloaded{
          [xx, yy](auto &&arg) { return signed_distance_2d(arg, xx, yy); },
      },
      obj);
}

} // namespace csg
+46 −25
Original line number Diff line number Diff line
@@ -7,8 +7,6 @@

namespace {

const double EXTERNAL_FLOW = -1.0;

template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template <class... Ts>
// clang-format off
@@ -19,59 +17,65 @@ overloaded(Ts...) -> overloaded<Ts...>; // not needed as of C++20

namespace csg {

double signed_distance(const Cone &, double, double, double);
double signed_distance(const Cube &, double, double, double);
double signed_distance(const Cylinder &, double, double, double);
double signed_distance(const Difference &, double, double, double);
double signed_distance(const Intersection &, double, double, double);
double signed_distance(const Mulmatrix &, double, double, double);
double signed_distance(const Sphere &, double, double, double);
double signed_distance(const Type &, double, double, double);
double signed_distance_3d(const Cone &, double, double, double);
double signed_distance_3d(const Cube &, double, double, double);
double signed_distance_3d(const Cylinder &, double, double, double);
double signed_distance_3d(const Difference3D &, double, double, double);
double signed_distance_3d(const Intersection3D &, double, double, double);
double signed_distance_3d(const Mulmatrix3D &, double, double, double);
double signed_distance_3d(const Sphere &, double, double, double);
double signed_distance_3d(const Type3D &, double, double, double);
double signed_distance_3d(const LinearExtrude &, double, double, double);
double signed_distance_3d(const RotateExtrude &, double, double, double);

double signed_distance_2d(const Union2D &, double, double);

double signed_distance(const Union &group, double xx, double yy, double zz) {
double signed_distance_3d(const Union3D &group, double xx, double yy,
                          double zz) {
  auto sdist = -std::numeric_limits<double>::max();
  for (const auto &member : group.objs) {
    auto sd = signed_distance(member, xx, yy, zz);
    auto sd = signed_distance_3d(member, xx, yy, zz);
    sdist = std::max(sdist, sd);
  };

  return sdist;
}

double signed_distance(const Intersection &group, double xx, double yy,
double signed_distance_3d(const Intersection3D &group, double xx, double yy,
                          double zz) {
  auto sdist = std::numeric_limits<double>::max();
  for (const auto &member : group.objs) {
    auto sd = signed_distance(member, xx, yy, zz);
    auto sd = signed_distance_3d(member, xx, yy, zz);
    sdist = std::min(sdist, sd);
  };
  return sdist;
}

double signed_distance(const Difference &group, double xx, double yy,
double signed_distance_3d(const Difference3D &group, double xx, double yy,
                          double zz) {
  auto sdist = signed_distance(*group.first_obj, xx, yy, zz);
  auto sdist = signed_distance_3d(*group.first_obj, xx, yy, zz);

  for (const auto &member : group.next_objs.objs) {
    auto sd = signed_distance(member, xx, yy, zz);
    auto sd = signed_distance_3d(member, xx, yy, zz);
    sdist = std::min(sdist, -sd);
  };
  return sdist;
}

double signed_distance(const Mulmatrix &mm, double xx, double yy, double zz) {
double signed_distance_3d(const Mulmatrix3D &mm, double xx, double yy,
                          double zz) {
  // TODO: Invert non-orthogonal matrices
  auto XX = xx - mm.translation[0];
  auto YY = yy - mm.translation[1];
  auto ZZ = zz - mm.translation[2];
  return signed_distance(
  return signed_distance_3d(
      mm.group,
      mm.rotation[0][0] * XX + mm.rotation[1][0] * YY + mm.rotation[2][0] * ZZ,
      mm.rotation[0][1] * XX + mm.rotation[1][1] * YY + mm.rotation[2][1] * ZZ,
      mm.rotation[0][2] * XX + mm.rotation[1][2] * YY + mm.rotation[2][2] * ZZ);
}

double signed_distance(const Cone &cone, double xx, double yy, double zz) {
double signed_distance_3d(const Cone &cone, double xx, double yy, double zz) {
  double ZZ = cone.center ? zz + cone.height / 2 : zz;
  double sign_z = (ZZ >= 0 && ZZ <= cone.height) ? -1.0 : 1.0;
  auto dist_z = std::min(std::fabs(ZZ), std::fabs(ZZ - cone.height));
@@ -84,7 +88,7 @@ double signed_distance(const Cone &cone, double xx, double yy, double zz) {
  return EXTERNAL_FLOW * std::max(sign_z * dist_z, sign_r * dist_r);
}

double signed_distance(const Cube &cube, double xx, double yy, double zz) {
double signed_distance_3d(const Cube &cube, double xx, double yy, double zz) {

  auto [Lx, Ly, Lz] = cube.size;
  auto XX = cube.center ? xx + Lx / 2 : xx;
@@ -103,14 +107,15 @@ double signed_distance(const Cube &cube, double xx, double yy, double zz) {
         std::max({sign_x * dist_x, sign_y * dist_y, sign_z * dist_z});
}

double signed_distance(const Sphere &sph, double xx, double yy, double zz) {
double signed_distance_3d(const Sphere &sph, double xx, double yy, double zz) {
  auto delta_r = xx * xx + yy * yy + zz * zz - sph.radius * sph.radius;
  double sign = delta_r <= 0 ? -1.0 : 1.0;
  auto dist = std::fabs(delta_r);
  return EXTERNAL_FLOW * sign * dist;
}

double signed_distance(const Cylinder &cyl, double xx, double yy, double zz) {
double signed_distance_3d(const Cylinder &cyl, double xx, double yy,
                          double zz) {
  auto ZZ = cyl.center ? zz + cyl.height / 2 : zz;
  double sign_z = (ZZ >= 0 && ZZ <= cyl.height) ? -1.0 : 1.0;
  auto dist_z = std::min(std::fabs(ZZ), std::fabs(ZZ - cyl.height));
@@ -123,11 +128,27 @@ double signed_distance(const Cylinder &cyl, double xx, double yy, double zz) {
  return EXTERNAL_FLOW * std::max(sign_z * dist_z, sign_r * dist_r);
}

double signed_distance(const Type &obj, double xx, double yy, double zz) {
double signed_distance_3d(const LinearExtrude &lin_ext, double xx, double yy,
                          double zz) {
  // TODO: support height, center and twist
  return signed_distance_2d(lin_ext.group, xx, yy);
}

double signed_distance_3d(const RotateExtrude &rot_ext, double xx, double yy,
                          double zz) {
  // TODO: support angle
  auto XX = std::hypot(xx, yy);
  auto YY = zz;
  return signed_distance_2d(rot_ext.group, XX, YY);
}

double signed_distance_3d(const Type3D &obj, double xx, double yy, double zz) {

  return std::visit(
      overloaded{
          [xx, yy, zz](auto &&arg) { return signed_distance(arg, xx, yy, zz); },
          [xx, yy, zz](auto &&arg) {
            return signed_distance_3d(arg, xx, yy, zz);
          },
      },
      obj);
}
Loading