feat: 添加 HTTP 服务器模式和低精度默认配置
新增功能: - 添加 HTTP 服务器模式,支持通过 API 转换 STEP 文件 - 实现文件上传和转换接口 POST /convert - 添加健康检查接口 GET /health - 支持服务器端输出目录配置 (默认 ./output) - 调整默认精度为 Low 级别以提升转换速度 技术实现: - 集成 cpp-httplib 作为 HTTP 服务器 - 扩展 ServerConfig 配置结构 - 实现临时文件自动清理机制 - 返回 JSON 格式响应,包含输出文件路径 使用方式: - CLI 模式: STP2GLB.exe --stp input.stp --glb output.glb - 服务器模式: STP2GLB.exe --server --port 8080 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
commit
bc9165803b
137
CMakeLists.txt
Normal file
137
CMakeLists.txt
Normal file
@ -0,0 +1,137 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(stp2glb LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
OPTION(CONDA_LOCAL_DEV "Install into activate local development conda env." OFF)
|
||||
|
||||
if (CONDA_LOCAL_DEV)
|
||||
message(STATUS "Building for local development conda env.")
|
||||
set(EXE_BIN_DIR ${CMAKE_INSTALL_PREFIX}/bin)
|
||||
endif ()
|
||||
|
||||
include(cmake/pre_checks.cmake)
|
||||
|
||||
# Create a empty list to hold all the linked libs
|
||||
set(ADA_CPP_LINK_LIBS)
|
||||
# Add dependencies
|
||||
|
||||
include(cmake/deps_occ.cmake)
|
||||
|
||||
# Add an option to enable static builds
|
||||
OPTION(BUILD_STATIC "Build STP2GLB as a static executable." OFF)
|
||||
|
||||
if (BUILD_STATIC)
|
||||
message(STATUS "Building STP2GLB as a static executable.")
|
||||
|
||||
# Force static linking
|
||||
set(BUILD_SHARED_LIBS OFF) # Disable shared libraries
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".a") # Prefer static libraries
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
|
||||
|
||||
# For MSVC, ensure the static runtime is used
|
||||
if (MSVC)
|
||||
foreach (flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
set(${flag_var} "${${flag_var}} /MT")
|
||||
endforeach ()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MT")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MT")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
|
||||
|
||||
# Force dependencies to link statically
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) # Prefer CMake config files
|
||||
foreach (lib ${ADA_CPP_LINK_LIBS})
|
||||
if (TARGET ${lib})
|
||||
set_target_properties(${lib} PROPERTIES
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
LINK_SEARCH_START_STATIC TRUE
|
||||
LINK_SEARCH_END_STATIC TRUE
|
||||
)
|
||||
endif ()
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
else ()
|
||||
include(cmake/deps_ifc.cmake)
|
||||
include(cmake/deps_stepcode.cmake)
|
||||
include(cmake/deps_cgal.cmake)
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-DNOMINMAX)
|
||||
endif ()
|
||||
|
||||
|
||||
# Install the C++ executable
|
||||
set(SOURCES
|
||||
src/main.cpp
|
||||
src/config_utils.cpp
|
||||
src/http_server.cpp
|
||||
src/geom/Color.cpp
|
||||
src/cadit/occt/step_tree.cpp
|
||||
src/cadit/occt/debug.cpp
|
||||
src/cadit/occt/gltf_writer.cpp
|
||||
src/cadit/occt/convert.cpp
|
||||
src/cadit/occt/step_helpers.cpp
|
||||
src/cadit/occt/bsplinesurf.cpp
|
||||
src/cadit/occt/helpers.cpp
|
||||
src/cadit/occt/step_writer.cpp
|
||||
src/cadit/occt/custom_progress.cpp
|
||||
)
|
||||
set(HEADERS
|
||||
src/config_utils.h
|
||||
src/config_structs.h
|
||||
src/http_server.h
|
||||
src/geom/Color.h
|
||||
src/cadit/occt/step_tree.h
|
||||
src/cadit/occt/convert.h
|
||||
src/cadit/occt/debug.h
|
||||
src/cadit/occt/step_helpers.h
|
||||
src/cadit/occt/gltf_writer.h
|
||||
src/cadit/occt/bsplinesurf.h
|
||||
src/cadit/occt/helpers.h
|
||||
src/cadit/occt/step_writer.h
|
||||
src/cadit/occt/geometry_iterator.h
|
||||
src/cadit/occt/custom_progress.h
|
||||
)
|
||||
|
||||
add_executable(STP2GLB ${SOURCES} ${HEADERS})
|
||||
|
||||
if (NOT BUILD_STATIC)
|
||||
set_target_properties(STP2GLB PROPERTIES
|
||||
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/bin")
|
||||
endif ()
|
||||
|
||||
message(STATUS "CLI11_DIR: ${CLI11_DIR}")
|
||||
if (BUILD_STATIC)
|
||||
target_include_directories(STP2GLB PRIVATE ${CLI11_DIR})
|
||||
|
||||
if (UNIX)
|
||||
message(STATUS "Setting static compilation rules for unix")
|
||||
target_link_libraries(STP2GLB PRIVATE ${ADA_CPP_LINK_LIBS} pthread -static)
|
||||
else ()
|
||||
target_link_libraries(STP2GLB ${ADA_CPP_LINK_LIBS} -static)
|
||||
set_property(TARGET STP2GLB PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
endif ()
|
||||
|
||||
else ()
|
||||
target_link_libraries(STP2GLB ${ADA_CPP_LINK_LIBS})
|
||||
endif ()
|
||||
|
||||
# install to executable into the bin dir
|
||||
message(STATUS "Installing executable to ${EXE_BIN_DIR}")
|
||||
install(TARGETS STP2GLB DESTINATION ${EXE_BIN_DIR})
|
||||
|
||||
# Include the tests directory
|
||||
OPTION(BUILD_TESTING "Build the testing tree." ON)
|
||||
if (BUILD_TESTING)
|
||||
message(STATUS "Building the testing tree.")
|
||||
enable_testing()
|
||||
include(tests/tests.cmake)
|
||||
endif (BUILD_TESTING)
|
||||
|
||||
49
src/config_structs.h
Normal file
49
src/config_structs.h
Normal file
@ -0,0 +1,49 @@
|
||||
//
|
||||
// Created by ofskrand on 07.01.2025.
|
||||
//
|
||||
|
||||
#ifndef CONFIG_STRUCTS_H
|
||||
#define CONFIG_STRUCTS_H
|
||||
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
||||
struct BuildConfig {
|
||||
bool build_bspline_surf;
|
||||
};
|
||||
|
||||
struct ServerConfig {
|
||||
bool enable_server = false;
|
||||
int port = 8080;
|
||||
std::string host = "0.0.0.0";
|
||||
size_t max_file_size_mb = 500;
|
||||
std::string temp_dir = "./temp";
|
||||
std::string output_dir = "./output";
|
||||
};
|
||||
|
||||
struct GlobalConfig {
|
||||
std::filesystem::path stpFile;
|
||||
std::filesystem::path glbFile;
|
||||
|
||||
// Conversion parameters
|
||||
bool debug_mode;
|
||||
|
||||
double linearDeflection;
|
||||
double angularDeflection;
|
||||
bool relativeDeflection;
|
||||
|
||||
// Debug parameters
|
||||
bool solidOnly;
|
||||
int max_geometry_num;
|
||||
int tessellation_timout;
|
||||
|
||||
std::vector<std::string> filter_names_include;
|
||||
std::vector<std::string> filter_names_exclude;
|
||||
|
||||
BuildConfig buildConfig;
|
||||
ServerConfig serverConfig;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //CONFIG_STRUCTS_H
|
||||
131
src/config_utils.cpp
Normal file
131
src/config_utils.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
//
|
||||
// Created by ofskrand on 13.01.2025.
|
||||
//
|
||||
|
||||
#include "config_utils.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config_structs.h"
|
||||
#include "cadit/occt/helpers.h"
|
||||
#include "CLI/App.hpp"
|
||||
|
||||
// Helper function to process filter names from input or file
|
||||
std::vector<std::string> process_filter_names(const std::string& input, const std::string& file_name)
|
||||
{
|
||||
std::vector<std::string> filter_names;
|
||||
|
||||
// Process input string
|
||||
if (!input.empty())
|
||||
{
|
||||
std::string stripped_input = strip_quotes(input);
|
||||
auto names = split(stripped_input, ',');
|
||||
filter_names.insert(filter_names.end(), names.begin(), names.end());
|
||||
}
|
||||
|
||||
// Process file
|
||||
if (!file_name.empty())
|
||||
{
|
||||
if (std::ifstream file(file_name); file.is_open())
|
||||
{
|
||||
std::string line;
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (!line.empty())
|
||||
{
|
||||
filter_names.push_back(line);
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Error: Could not open file: " + file_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return filter_names;
|
||||
}
|
||||
|
||||
// Helper function to check if a string ends with a specific suffix (case insensitive)
|
||||
bool endsWithCaseInsensitive(const std::string& str, const std::string& suffix) {
|
||||
if (str.size() < suffix.size()) {
|
||||
return false;
|
||||
}
|
||||
auto strIt = str.end() - suffix.size();
|
||||
auto suffixIt = suffix.begin();
|
||||
while (suffixIt != suffix.end()) {
|
||||
if (tolower(*strIt++) != tolower(*suffixIt++)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Main processing function
|
||||
GlobalConfig process_parameters(CLI::App& app)
|
||||
{
|
||||
const auto filter_names_include_input = app.get_option("--filter-names-include")->as<std::string>();
|
||||
const auto filter_names_file_include = app.get_option("--filter-names-file-include")->as<std::string>();
|
||||
|
||||
const auto filter_names_exclude_input = app.get_option("--filter-names-exclude")->as<std::string>();
|
||||
const auto filter_names_file_exclude = app.get_option("--filter-names-file-exclude")->as<std::string>();
|
||||
|
||||
// Process include and exclude filter names
|
||||
const auto filter_names_include = process_filter_names(filter_names_include_input, filter_names_file_include);
|
||||
const auto filter_names_exclude = process_filter_names(filter_names_exclude_input, filter_names_file_exclude);
|
||||
|
||||
const std::string stpFilename = app.get_option("--stp")->results()[0];
|
||||
const std::string glbFilename = app.get_option("--glb")->results()[0];
|
||||
|
||||
// Validate extensions
|
||||
const bool isStpValid = endsWithCaseInsensitive(stpFilename, ".stp") || endsWithCaseInsensitive(stpFilename, ".step");
|
||||
const bool isGlbValid = endsWithCaseInsensitive(glbFilename, ".glb");
|
||||
auto stpFilePath = std::filesystem::path(stpFilename);
|
||||
auto glbFilePath = std::filesystem::path(glbFilename);
|
||||
|
||||
// check if file paths exists
|
||||
if (!exists(stpFilePath)) {
|
||||
throw std::invalid_argument("Invalid --stp filename \"" + stpFilename + "\". File does not exist.");
|
||||
}
|
||||
if (exists(glbFilePath)) {
|
||||
std::cout << "Warning: --glb filename \"" << glbFilename << "\" already exists and will be overwritten.\n";
|
||||
}
|
||||
|
||||
if (!isStpValid) {
|
||||
throw std::invalid_argument("Invalid --stp filename. It must end with .stp or .step.");
|
||||
}
|
||||
|
||||
if (!isGlbValid) {
|
||||
throw std::invalid_argument("Invalid --glb filename. It must end with .glb.");
|
||||
}
|
||||
|
||||
// Create configuration
|
||||
return {
|
||||
.stpFile = stpFilename,
|
||||
.glbFile = glbFilename,
|
||||
.debug_mode = app.get_option("--debug")->as<bool>(),
|
||||
.linearDeflection = app.get_option("--lin-defl")->as<double>(),
|
||||
.angularDeflection = app.get_option("--ang-defl")->as<double>(),
|
||||
.relativeDeflection = app.get_option("--rel-defl")->as<bool>(),
|
||||
.solidOnly = app.get_option("--solid-only")->as<bool>(),
|
||||
.max_geometry_num = app.get_option("--max-geometry-num")->as<int>(),
|
||||
.tessellation_timout = app.get_option("--tessellation-timeout")->as<int>(),
|
||||
.filter_names_include = filter_names_include,
|
||||
.filter_names_exclude = filter_names_exclude,
|
||||
.buildConfig = {
|
||||
.build_bspline_surf = false
|
||||
},
|
||||
.serverConfig = {
|
||||
.enable_server = app.get_option("--server")->as<bool>(),
|
||||
.port = app.get_option("--port")->as<int>(),
|
||||
.host = app.get_option("--host")->as<std::string>(),
|
||||
.max_file_size_mb = app.get_option("--max-file-size")->as<size_t>(),
|
||||
.temp_dir = "./temp"
|
||||
}
|
||||
};
|
||||
}
|
||||
137
src/http_server.cpp
Normal file
137
src/http_server.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
#include "http_server.h"
|
||||
#include "third_party/httplib.h"
|
||||
#include "cadit/occt/convert.h"
|
||||
#include "cadit/occt/debug.h"
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::string generate_unique_filename(const std::string& extension) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> dis(1000, 9999);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << timestamp << "_" << dis(gen) << extension;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void start_http_server(const GlobalConfig& base_config) {
|
||||
httplib::Server svr;
|
||||
|
||||
fs::create_directories(base_config.serverConfig.temp_dir);
|
||||
fs::create_directories(base_config.serverConfig.output_dir);
|
||||
|
||||
std::cout << "STP2GLB HTTP Server" << "\n";
|
||||
std::cout << "===================" << "\n";
|
||||
std::cout << "Host: " << base_config.serverConfig.host << "\n";
|
||||
std::cout << "Port: " << base_config.serverConfig.port << "\n";
|
||||
std::cout << "Temp Dir: " << base_config.serverConfig.temp_dir << "\n";
|
||||
std::cout << "Output Dir: " << base_config.serverConfig.output_dir << "\n";
|
||||
std::cout << "Max File Size: " << base_config.serverConfig.max_file_size_mb << " MB" << "\n\n";
|
||||
|
||||
svr.set_payload_max_length(base_config.serverConfig.max_file_size_mb * 1024 * 1024);
|
||||
|
||||
svr.Get("/health", [](const httplib::Request& req, httplib::Response& res) {
|
||||
res.set_content("{\"status\":\"ok\",\"service\":\"STP2GLB\"}", "application/json");
|
||||
});
|
||||
|
||||
svr.Post("/convert", [&base_config](const httplib::Request& req, httplib::Response& res) {
|
||||
std::cout << "Received conversion request" << "\n";
|
||||
|
||||
if (!req.is_multipart_form_data() || !req.form.has_file("file")) {
|
||||
res.status = 400;
|
||||
res.set_content("{\"error\":\"No file uploaded. Use 'file' field.\"}", "application/json");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& file = req.form.get_file("file", 0);
|
||||
|
||||
GlobalConfig config = base_config;
|
||||
|
||||
if (req.form.has_field("linearDeflection")) {
|
||||
config.linearDeflection = std::stod(req.form.get_field("linearDeflection"));
|
||||
}
|
||||
if (req.form.has_field("angularDeflection")) {
|
||||
config.angularDeflection = std::stod(req.form.get_field("angularDeflection"));
|
||||
}
|
||||
if (req.form.has_field("relativeDeflection")) {
|
||||
config.relativeDeflection = req.form.get_field("relativeDeflection") == "true";
|
||||
}
|
||||
if (req.form.has_field("debug")) {
|
||||
config.debug_mode = req.form.get_field("debug") == "true";
|
||||
}
|
||||
if (req.form.has_field("solidOnly")) {
|
||||
config.solidOnly = req.form.get_field("solidOnly") == "true";
|
||||
}
|
||||
if (req.form.has_field("maxGeometryNum")) {
|
||||
config.max_geometry_num = std::stoi(req.form.get_field("maxGeometryNum"));
|
||||
}
|
||||
|
||||
std::string base_filename = generate_unique_filename("");
|
||||
std::string stp_filename = base_filename + ".stp";
|
||||
std::string glb_filename = base_filename + ".glb";
|
||||
|
||||
fs::path stp_path = fs::path(config.serverConfig.temp_dir) / stp_filename;
|
||||
fs::path glb_path = fs::path(config.serverConfig.output_dir) / glb_filename;
|
||||
|
||||
try {
|
||||
std::ofstream ofs(stp_path, std::ios::binary);
|
||||
ofs.write(file.content.c_str(), file.content.size());
|
||||
ofs.close();
|
||||
|
||||
config.stpFile = stp_path;
|
||||
config.glbFile = glb_path;
|
||||
|
||||
std::cout << "Converting: " << stp_filename << " -> " << glb_filename << "\n";
|
||||
std::cout << " Linear Deflection: " << config.linearDeflection << "\n";
|
||||
std::cout << " Angular Deflection: " << config.angularDeflection << "\n";
|
||||
std::cout << " Debug Mode: " << config.debug_mode << "\n";
|
||||
|
||||
const auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
if (config.debug_mode) {
|
||||
debug_stp_to_glb(config);
|
||||
} else {
|
||||
convert_stp_to_glb(config);
|
||||
}
|
||||
|
||||
const auto stop = std::chrono::high_resolution_clock::now();
|
||||
const auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
|
||||
const double seconds = static_cast<double>(duration.count()) / 1e6;
|
||||
|
||||
std::cout << "Conversion completed in " << std::fixed << std::setprecision(2) << seconds << " seconds" << "\n";
|
||||
std::cout << "Output saved: " << glb_path << "\n";
|
||||
|
||||
fs::remove(stp_path);
|
||||
|
||||
std::string response = "{\"success\":true,\"output_file\":\"" + glb_filename + "\",\"output_path\":\"" + glb_path.string() + "\",\"conversion_time\":" + std::to_string(seconds) + "}";
|
||||
res.set_content(response, "application/json");
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << "\n";
|
||||
|
||||
if (fs::exists(stp_path)) fs::remove(stp_path);
|
||||
if (fs::exists(glb_path)) fs::remove(glb_path);
|
||||
|
||||
res.status = 500;
|
||||
std::string error_msg = "{\"success\":false,\"error\":\"" + std::string(ex.what()) + "\"}";
|
||||
res.set_content(error_msg, "application/json");
|
||||
}
|
||||
});
|
||||
|
||||
std::cout << "Server starting..." << "\n";
|
||||
std::cout << "Listening on http://" << base_config.serverConfig.host << ":" << base_config.serverConfig.port << "\n";
|
||||
std::cout << "Press Ctrl+C to stop" << "\n\n";
|
||||
|
||||
svr.listen(base_config.serverConfig.host, base_config.serverConfig.port);
|
||||
}
|
||||
8
src/http_server.h
Normal file
8
src/http_server.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef HTTP_SERVER_H
|
||||
#define HTTP_SERVER_H
|
||||
|
||||
#include "config_structs.h"
|
||||
|
||||
void start_http_server(const GlobalConfig& config);
|
||||
|
||||
#endif //HTTP_SERVER_H
|
||||
144
src/main.cpp
Normal file
144
src/main.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
// Check if the platform is Unix-based
|
||||
#if defined(__unix__) || defined(__unix)
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#endif // Unix platform check
|
||||
|
||||
#include <filesystem>
|
||||
#include "CLI/CLI.hpp"
|
||||
#include "config_structs.h"
|
||||
#include <chrono>
|
||||
#include "cadit/occt/debug.h"
|
||||
#include "cadit/occt/convert.h"
|
||||
#include "cadit/occt/bsplinesurf.h"
|
||||
#include "cadit/occt/helpers.h"
|
||||
#include "config_utils.h"
|
||||
#include "http_server.h"
|
||||
|
||||
void print_status(const GlobalConfig& config) {
|
||||
std::cout << "STP2GLB Converter" << "\n";
|
||||
std::cout << "STP File: " << config.stpFile << "\n";
|
||||
std::cout << "GLB File: " << config.glbFile << "\n\n";
|
||||
std::cout << "Tessellation Parameters: " << "\n";
|
||||
std::cout << "Linear Deflection: " << config.linearDeflection << "\n";
|
||||
std::cout << "Angular Deflection: " << config.angularDeflection << "\n";
|
||||
std::cout << "Relative Deflection: " << config.relativeDeflection << "\n\n";
|
||||
std::cout << "Debug Parameters: " << "\n";
|
||||
std::cout << "Debug Mode: " << config.debug_mode << "\n";
|
||||
std::cout << "Solid Only: " << config.solidOnly << "\n";
|
||||
std::cout << "Max Geometry Num: " << config.max_geometry_num << "\n";
|
||||
std::cout << "Tessellation Timeout: " << config.tessellation_timout << "\n\n";
|
||||
|
||||
// Debug output
|
||||
if (!config.filter_names_include.empty())
|
||||
{
|
||||
std::cout << "Included Filter Names:" << std::endl;
|
||||
for (const auto& name : config.filter_names_include)
|
||||
{
|
||||
std::cout << name << std::endl;
|
||||
}
|
||||
}
|
||||
if (!config.filter_names_exclude.empty())
|
||||
{
|
||||
std::cout << "Excluded Filter Names:" << std::endl;
|
||||
for (const auto& name : config.filter_names_exclude)
|
||||
{
|
||||
std::cout << name << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CLI::App app{"STEP to GLB converter"};
|
||||
|
||||
app.add_flag("--server", "Run as HTTP server");
|
||||
app.add_option("--port", "Server port")->default_val(8080);
|
||||
app.add_option("--host", "Server host")->default_val("0.0.0.0");
|
||||
app.add_option("--max-file-size", "Maximum file size in MB")->default_val(500);
|
||||
|
||||
app.add_option("--stp", "STEP filepath");
|
||||
app.add_option("--glb", "GLB filepath");
|
||||
|
||||
app.add_option("--lin-defl", "Linear deflection")->default_val(0.5)->check(CLI::Range(0.0, 1.0));
|
||||
app.add_option("--ang-defl", "Angular deflection")->default_val(0.8)->check(CLI::Range(0.0, 1.0));
|
||||
app.add_flag("--rel-defl", "Relative deflection");
|
||||
|
||||
app.add_flag("--debug", "Debug mode. Slower (and experimental), but provides more information about which STEP entities that failed to convert");
|
||||
app.add_flag("--solid-only", "Solid only");
|
||||
app.add_option("--max-geometry-num", "Maximum number of geometries to convert")->default_val(0);
|
||||
app.add_option("--filter-names-include", "Include Filter name. Command separated list")->default_val("");
|
||||
app.add_option("--filter-names-file-include", "Include Filter name file")->default_val("");
|
||||
app.add_option("--filter-names-exclude", "Exclude Filter name. Command separated list")->default_val("");
|
||||
app.add_option("--filter-names-file-exclude", "Exclude Filter name file")->default_val("");
|
||||
app.add_option("--tessellation-timeout", "Tessellation timeout")->default_val(30);
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
const bool server_mode = app.get_option("--server")->as<bool>();
|
||||
|
||||
if (server_mode) {
|
||||
GlobalConfig config;
|
||||
config.linearDeflection = app.get_option("--lin-defl")->as<double>();
|
||||
config.angularDeflection = app.get_option("--ang-defl")->as<double>();
|
||||
config.relativeDeflection = app.get_option("--rel-defl")->as<bool>();
|
||||
config.debug_mode = false;
|
||||
config.solidOnly = false;
|
||||
config.max_geometry_num = 0;
|
||||
config.tessellation_timout = app.get_option("--tessellation-timeout")->as<int>();
|
||||
|
||||
config.serverConfig.enable_server = true;
|
||||
config.serverConfig.port = app.get_option("--port")->as<int>();
|
||||
config.serverConfig.host = app.get_option("--host")->as<std::string>();
|
||||
config.serverConfig.max_file_size_mb = app.get_option("--max-file-size")->as<size_t>();
|
||||
config.serverConfig.temp_dir = "./temp";
|
||||
config.serverConfig.output_dir = "./output";
|
||||
|
||||
try {
|
||||
start_http_server(config);
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Server error: " << ex.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
app.get_option("--stp")->required();
|
||||
app.get_option("--glb")->required();
|
||||
|
||||
GlobalConfig config;
|
||||
try {
|
||||
config = process_parameters(app);
|
||||
} catch (const std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
print_status(config);
|
||||
std::cout << "\n";
|
||||
std::cout << "Starting conversion..." << "\n";
|
||||
|
||||
const auto start = std::chrono::high_resolution_clock::now();
|
||||
try {
|
||||
if (config.buildConfig.build_bspline_surf)
|
||||
make_a_bspline_surf(config);
|
||||
|
||||
if (config.debug_mode == 1)
|
||||
debug_stp_to_glb(config);
|
||||
else
|
||||
{
|
||||
convert_stp_to_glb(config);
|
||||
}
|
||||
} catch (std::exception& ex) {
|
||||
std::cerr << "Error: " << ex.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
const auto stop = std::chrono::high_resolution_clock::now();
|
||||
const auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
|
||||
const double seconds = static_cast<double>(duration.count()) / 1e6;
|
||||
std::cout << "STP converted in: " << std::fixed << std::setprecision(2) << seconds << " seconds" << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
11911
src/third_party/httplib.h
vendored
Normal file
11911
src/third_party/httplib.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user