不能郁郁喔 发表于 2026-4-2 16:22:45

NXOpen如何实现自动范围选择

有个需求要求无UI根据一条曲线自动计算范围进行自动选择目前没有什么头绪

jesson3264 发表于 2026-4-15 14:26:17

// AutoSelectByCurveSkeleton.cpp
// NX Open C++ / UFUN skeleton: no UI, auto-select bodies by one curve range.

#include <uf.h>
#include <uf_obj.h>
#include <uf_modl.h>
#include <uf_part.h>
#include <uf_ui.h>
#include <uf_group.h>

#include <algorithm>
#include <array>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <string>
#include <vector>

namespace
{
    struct Config
    {
      double k = 0.02;
      double rMin = 2.0;
      double tol = 0.01;
      std::string groupName = "AUTO_SELECT_BY_CURVE";
    };

    static void Log(const std::string &msg)
    {
      UF_UI_open_listing_window();
      UF_UI_write_listing_window(msg.c_str());
      UF_UI_write_listing_window("\n");
    }

    static bool ParseTagFromEnv(const char *key, tag_t &tag)
    {
      const char *v = std::getenv(key);
      if (!v || std::strlen(v) == 0)
            return false;

      char *end = nullptr;
      unsigned long long raw = std::strtoull(v, &end, 10);
      if (end == v)
            return false;

      tag = static_cast<tag_t>(raw);
      return (tag != NULL_TAG);
    }

    static bool AskBoundingBox(tag_t obj, std::array<double, 6> &bbox)
    {
      double b = {0.0};
      int rc = UF_MODL_ask_bounding_box(obj, b);
      if (rc != 0)
            return false;

      for (int i = 0; i < 6; ++i)
            bbox = b;
      return true;
    }

    static double BboxDiagonal(const std::array<double, 6> &bb)
    {
      const double dx = bb - bb;
      const double dy = bb - bb;
      const double dz = bb - bb;
      return std::sqrt(dx * dx + dy * dy + dz * dz);
    }

    static std::array<double, 6> ExpandBbox(const std::array<double, 6> &bb, double r)
    {
      return {bb - r, bb - r, bb - r, bb + r, bb + r, bb + r};
    }

    static bool BboxIntersects(const std::array<double, 6> &a, const std::array<double, 6> &b)
    {
      bool sep = a < b || a > b ||
                   a < b || a > b ||
                   a < b || a > b;
      return !sep;
    }

    static bool AskMinDistance(tag_t obj1, tag_t obj2, double &dist)
    {
      double pt1 = {0.0}, pt2 = {0.0};
      int rc = UF_MODL_ask_minimum_dist(obj1, obj2, 0, nullptr, 0, nullptr, &dist, pt1, pt2);
      return rc == 0;
    }

    static std::vector<tag_t> CollectSolidBodiesInWorkPart()
    {
      std::vector<tag_t> bodies;
      tag_t part = UF_PART_ask_display_part();
      if (part == NULL_TAG)
            return bodies;

      tag_t obj = NULL_TAG;
      while (UF_OBJ_cycle_objs_in_part(part, UF_solid_type, &obj) == 0 && obj != NULL_TAG)
      {
            int type = 0;
            int subtype = 0;
            UF_OBJ_ask_type_and_subtype(obj, &type, &subtype);
            if (subtype == UF_solid_body_subtype)
                bodies.push_back(obj);
      }

      return bodies;
    }

    static tag_t FindCurveFromEnvOrFail()
    {
      tag_t curve = NULL_TAG;
      if (!ParseTagFromEnv("NX_CURVE_TAG", curve))
      {
            Log(" Missing env NX_CURVE_TAG. Example: set NX_CURVE_TAG=123456");
            return NULL_TAG;
      }

      int type = 0, subtype = 0;
      if (UF_OBJ_ask_type_and_subtype(curve, &type, &subtype) != 0)
      {
            Log(" Invalid curve tag.");
            return NULL_TAG;
      }

      if (type != UF_line_type && type != UF_circle_type && type != UF_conic_type && type != UF_spline_type && type != UF_curve_type)
      {
            Log(" Tag is not a supported curve object.");
            return NULL_TAG;
      }

      return curve;
    }

    static tag_t CreateGroupWithMembers(const std::string &name, const std::vector<tag_t> &members)
    {
      if (members.empty())
            return NULL_TAG;

      tag_t groupTag = NULL_TAG;
      int rc = UF_GROUP_create(name.c_str(), static_cast<int>(members.size()), const_cast<tag_t *>(members.data()), &groupTag);
      if (rc != 0)
            return NULL_TAG;

      return groupTag;
    }

    static int Run(const Config &cfg)
    {
      tag_t curve = FindCurveFromEnvOrFail();
      if (curve == NULL_TAG)
            return 1;

      std::array<double, 6> curveBb{};
      if (!AskBoundingBox(curve, curveBb))
      {
            Log(" Failed to query curve bounding box.");
            return 2;
      }

      const double curveScale = BboxDiagonal(curveBb);
      const double R = std::max(curveScale * cfg.k, cfg.rMin);
      const auto expanded = ExpandBbox(curveBb, R);

      auto allBodies = CollectSolidBodiesInWorkPart();
      std::vector<tag_t> coarse;
      coarse.reserve(allBodies.size());

      for (tag_t b : allBodies)
      {
            std::array<double, 6> bb{};
            if (!AskBoundingBox(b, bb))
                continue;
            if (BboxIntersects(expanded, bb))
                coarse.push_back(b);
      }

      std::vector<tag_t> selected;
      selected.reserve(coarse.size());

      for (tag_t b : coarse)
      {
            double d = std::numeric_limits<double>::max();
            if (!AskMinDistance(curve, b, d))
                continue;
            if (d <= R + cfg.tol)
                selected.push_back(b);
      }

      tag_t group = CreateGroupWithMembers(cfg.groupName, selected);

      Log(" Auto select by curve done.");
      Log("curve tag: " + std::to_string(static_cast<unsigned long long>(curve)));
      Log("curve scale (bbox diagonal): " + std::to_string(curveScale));
      Log("radius R: " + std::to_string(R));
      Log("total bodies: " + std::to_string(allBodies.size()));
      Log("coarse candidates: " + std::to_string(coarse.size()));
      Log("selected: " + std::to_string(selected.size()));
      Log("group tag: " + std::to_string(static_cast<unsigned long long>(group)));

      return 0;
    }
}

extern "C" DllExport void ufusr(char *param, int *returnCode, int rlen)
{
    UF_initialize();

    Config cfg;
    int rc = Run(cfg);
    if (returnCode)
      *returnCode = rc;

    UF_terminate();
}

extern "C" DllExport int ufusr_ask_unload(void)
{
    return UF_UNLOAD_IMMEDIATELY;
}

风雪冥殇 发表于 2026-4-16 11:00:48

jesson3264 发表于 2026-4-15 14:26


虽然看不懂   但666
页: [1]
查看完整版本: NXOpen如何实现自动范围选择