CreoPluging9.0/Shrinkwrap90Manager.cpp

165 lines
5.6 KiB
C++

#include "pch.h"
#include "Shrinkwrap90Manager.h"
#include "Creo90Manager.h"
#include "CreoOtk.h"
#include <filesystem>
#include <sstream>
#include <stdexcept>
#include <thread>
#include <chrono>
namespace {
std::string EnsurePrtExtension(std::string path) {
std::filesystem::path p(path);
if (!p.has_extension()) {
p.replace_extension(".prt");
}
return p.string();
}
} // namespace
ShrinkwrapShellResult Shrinkwrap90Manager::ExportShell(const ShrinkwrapShellRequest& req) {
if (req.output_file_path.empty()) {
throw std::runtime_error("output_file_path is required");
}
if (req.quality < 1 || req.quality > 10) {
throw std::runtime_error("quality must be in [1,10]");
}
if (req.small_surface_percentage < 0.0) {
throw std::runtime_error("small_surface_percentage must be >= 0");
}
Creo90Manager creo;
pfcSession_ptr session = creo.GetSession();
if (!session) {
throw std::runtime_error("Creo session not available");
}
pfcSolid_ptr source = creo.GetCurrentSolid();
if (!source) {
throw std::runtime_error("current model is not a solid (part/assembly) or no model is active");
}
std::string outPathS = EnsurePrtExtension(req.output_file_path);
std::filesystem::path outPath(outPathS);
std::string stem = outPath.stem().string();
std::string modelName = SanitizeCreoModelName(stem);
if (modelName.empty()) modelName = "shrinkwrap";
pfcPart_ptr outputPart = session->CreatePart(modelName.c_str());
pfcModel_ptr outputModel = pfcModel::cast(outputPart);
pfcShrinkwrapModelExportInstructions_ptr modelInstr;
if (req.method == 1) {
// Faceted Solid
// Note: Faceted Solid export is handled via pfcShrinkwrapFacetedPartInstructions
// But user wants "Faceted Solid" creation which usually creates a new model (like Merged Solid).
// However, OTK distinguishes between "Export to file" (STL/VRML/FacetedPart) and "Create feature/model".
// pfcShrinkwrapMergedSolidInstructions creates a new model.
// pfcShrinkwrapSurfaceSubsetInstructions creates a new model.
// pfcShrinkwrapFacetedPartInstructions exports to a file directly OR creates a model?
// Let's check pfcShrinkwrapFacetedPartInstructions::Create signature.
// Create(pfcModel_ptr OutputModel, xbool Lightweight)
// So it exports to 'OutputModel'.
pfcShrinkwrapFacetedPartInstructions_ptr fInstr = pfcShrinkwrapFacetedPartInstructions::Create(outputModel, xfalse);
modelInstr = pfcShrinkwrapModelExportInstructions::cast(fInstr);
} else if (req.method == 2) {
// Merged Solid
pfcShrinkwrapMergedSolidInstructions_ptr mInstr = pfcShrinkwrapMergedSolidInstructions::Create(outputModel);
modelInstr = pfcShrinkwrapModelExportInstructions::cast(mInstr);
} else {
// Surface Subset (Default = 0)
pfcShrinkwrapSurfaceSubsetInstructions_ptr sInstr = pfcShrinkwrapSurfaceSubsetInstructions::Create(outputModel);
modelInstr = pfcShrinkwrapModelExportInstructions::cast(sInstr);
}
// Common options
modelInstr->SetQuality(req.quality);
modelInstr->SetAutoHoleFilling(req.fill_holes ? xtrue : xfalse);
modelInstr->SetIgnoreSmallSurfaces(req.ignore_small_surfaces ? xtrue : xfalse);
if (req.ignore_small_surfaces) {
modelInstr->SetSmallSurfPercentage(req.small_surface_percentage);
}
modelInstr->SetIgnoreQuilts(req.ignore_quilts ? xtrue : xfalse);
modelInstr->SetIgnoreSkeleton(req.ignore_skeleton ? xtrue : xfalse);
modelInstr->SetAssignMassProperties(req.assign_mass_properties ? xtrue : xfalse);
pfcShrinkwrapExportInstructions_ptr exportInstr = pfcShrinkwrapExportInstructions::cast(modelInstr);
source->ExportShrinkwrap(exportInstr);
std::string dir = outPath.parent_path().string();
pfcModelDescriptor_ptr descr = pfcModelDescriptor::Create(pfcMDL_PART, modelName.c_str(), nullptr);
descr->SetPath(dir.c_str());
outputPart->Backup(descr);
std::filesystem::path actualOutPath = outPath.parent_path() / (modelName + ".prt");
// Ensure file is written
std::this_thread::sleep_for(std::chrono::milliseconds(200));
ShrinkwrapShellResult res;
res.output_path = actualOutPath.string();
std::error_code ec;
uintmax_t bytes = std::filesystem::file_size(actualOutPath, ec);
if (ec || bytes == 0) {
// Retry
std::this_thread::sleep_for(std::chrono::milliseconds(500));
bytes = std::filesystem::file_size(actualOutPath, ec);
}
if (ec) bytes = 0;
res.file_size = FormatFileSize(bytes);
res.execution_time = ""; // 由上层填充
return res;
}
std::string Shrinkwrap90Manager::SanitizeCreoModelName(const std::string& fileStem) {
std::string out;
out.reserve(fileStem.size());
for (unsigned char uc : fileStem) {
char c = static_cast<char>(uc);
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-') {
out.push_back(c);
} else if (c == ' ') {
out.push_back('_');
}
}
if (!out.empty() && (out[0] >= '0' && out[0] <= '9')) {
out.insert(out.begin(), '_');
}
if (out.size() > 31) {
out.resize(31);
}
return out;
}
std::string Shrinkwrap90Manager::FormatFileSize(uintmax_t bytes) {
std::ostringstream oss;
double mb = static_cast<double>(bytes) / (1024.0 * 1024.0);
oss.setf(std::ios::fixed);
oss.precision(1);
oss << mb << " MB";
return oss.str();
}
std::string Shrinkwrap90Manager::FormatHhMmSs(long long totalSeconds) {
if (totalSeconds < 0) totalSeconds = 0;
long long h = totalSeconds / 3600;
long long m = (totalSeconds % 3600) / 60;
long long s = totalSeconds % 60;
char buf[32];
sprintf_s(buf, "%02lld:%02lld:%02lld", h, m, s);
return std::string(buf);
}