mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-26 18:21:18 -06:00
Merge remote-tracking branch 'origin/master' into lm_wiping_dialog_colors
This commit is contained in:
commit
6b4f6f43dd
1421 changed files with 33462 additions and 21845 deletions
|
|
@ -1,5 +1,6 @@
|
|||
project(PrusaSlicer-native)
|
||||
|
||||
add_subdirectory(build-utils)
|
||||
add_subdirectory(admesh)
|
||||
add_subdirectory(avrdude)
|
||||
# boost/nowide
|
||||
|
|
@ -12,14 +13,12 @@ add_subdirectory(poly2tri)
|
|||
add_subdirectory(qhull)
|
||||
add_subdirectory(Shiny)
|
||||
add_subdirectory(semver)
|
||||
add_subdirectory(libigl)
|
||||
|
||||
# Adding libnest2d project for bin packing...
|
||||
set(LIBNEST2D_UNITTESTS ON CACHE BOOL "Force generating unittests for libnest2d")
|
||||
add_subdirectory(libnest2d)
|
||||
|
||||
include_directories(${LIBDIR}/qhull/src)
|
||||
#message(STATUS ${LIBDIR}/qhull/src)
|
||||
|
||||
add_subdirectory(libslic3r)
|
||||
|
||||
if (SLIC3R_GUI)
|
||||
|
|
@ -49,7 +48,7 @@ if (SLIC3R_GUI)
|
|||
endif ()
|
||||
endif ()
|
||||
else ()
|
||||
find_package(wxWidgets 3.1 REQUIRED COMPONENTS base core adv html gl)
|
||||
find_package(wxWidgets 3.1 REQUIRED COMPONENTS html adv gl core base)
|
||||
endif ()
|
||||
|
||||
if(UNIX)
|
||||
|
|
@ -58,6 +57,9 @@ if (SLIC3R_GUI)
|
|||
|
||||
include(${wxWidgets_USE_FILE})
|
||||
|
||||
# list(REMOVE_ITEM wxWidgets_LIBRARIES oleacc)
|
||||
message(STATUS "wx libs: ${wxWidgets_LIBRARIES}")
|
||||
|
||||
add_subdirectory(slic3r)
|
||||
endif()
|
||||
|
||||
|
|
@ -67,17 +69,23 @@ endif()
|
|||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/PrusaSlicer.rc.in ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.rc @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/PrusaSlicer.manifest.in ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.manifest @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/osx/Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/Info.plist @ONLY)
|
||||
if (MSVC)
|
||||
if (WIN32)
|
||||
add_library(PrusaSlicer SHARED PrusaSlicer.cpp PrusaSlicer.hpp)
|
||||
else ()
|
||||
add_executable(PrusaSlicer PrusaSlicer.cpp PrusaSlicer.hpp)
|
||||
endif ()
|
||||
if (NOT MSVC)
|
||||
|
||||
if (MINGW)
|
||||
target_link_options(PrusaSlicer PUBLIC "-Wl,-allow-multiple-definition")
|
||||
set_target_properties(PrusaSlicer PROPERTIES PREFIX "")
|
||||
endif (MINGW)
|
||||
|
||||
if (NOT WIN32)
|
||||
# Binary name on unix like systems (OSX, Linux)
|
||||
set_target_properties(PrusaSlicer PROPERTIES OUTPUT_NAME "prusa-slicer")
|
||||
endif ()
|
||||
|
||||
target_link_libraries(PrusaSlicer libslic3r)
|
||||
target_link_libraries(PrusaSlicer libslic3r cereal)
|
||||
if (APPLE)
|
||||
# add_compile_options(-stdlib=libc++)
|
||||
# add_definitions(-DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE)
|
||||
|
|
@ -93,11 +101,12 @@ endif ()
|
|||
|
||||
# Add the Slic3r GUI library, libcurl, OpenGL and GLU libraries.
|
||||
if (SLIC3R_GUI)
|
||||
target_link_libraries(PrusaSlicer libslic3r_gui ${wxWidgets_LIBRARIES})
|
||||
# target_link_libraries(PrusaSlicer ws2_32 uxtheme setupapi libslic3r_gui ${wxWidgets_LIBRARIES})
|
||||
target_link_libraries(PrusaSlicer libslic3r_gui ${wxWidgets_LIBRARIES})
|
||||
|
||||
# Configure libcurl and its dependencies OpenSSL & zlib
|
||||
find_package(CURL REQUIRED)
|
||||
if (NOT MSVC)
|
||||
if (NOT WIN32)
|
||||
# Required by libcurl
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif()
|
||||
|
|
@ -125,7 +134,7 @@ if (SLIC3R_GUI)
|
|||
target_link_options(PrusaSlicer PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")
|
||||
target_link_libraries(PrusaSlicer user32.lib Setupapi.lib OpenGL32.Lib GlU32.Lib)
|
||||
elseif (MINGW)
|
||||
target_link_libraries(PrusaSlicer -lopengl32)
|
||||
target_link_libraries(PrusaSlicer opengl32 ws2_32 uxtheme setupapi)
|
||||
elseif (APPLE)
|
||||
target_link_libraries(PrusaSlicer "-framework OpenGL")
|
||||
else ()
|
||||
|
|
@ -135,26 +144,34 @@ endif ()
|
|||
|
||||
# On Windows, a shim application is required to produce a console / non console version of the Slic3r application.
|
||||
# Also the shim may load the Mesa software OpenGL renderer if the default renderer does not support OpenGL 2.0 and higher.
|
||||
if (MSVC)
|
||||
if (WIN32)
|
||||
if (MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode")
|
||||
endif()
|
||||
|
||||
add_executable(PrusaSlicer_app_gui WIN32 PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.rc)
|
||||
# Generate debug symbols even in release mode.
|
||||
target_link_options(PrusaSlicer_app_gui PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")
|
||||
if(MSVC)
|
||||
target_link_options(PrusaSlicer_app_gui PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")
|
||||
endif()
|
||||
target_compile_definitions(PrusaSlicer_app_gui PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE)
|
||||
add_dependencies(PrusaSlicer_app_gui PrusaSlicer)
|
||||
set_target_properties(PrusaSlicer_app_gui PROPERTIES OUTPUT_NAME "prusa-slicer")
|
||||
target_include_directories(PrusaSlicer_app_gui SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(PrusaSlicer_app_gui PRIVATE boost_headeronly)
|
||||
|
||||
add_executable(PrusaSlicer_app_console PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.rc)
|
||||
# Generate debug symbols even in release mode.
|
||||
if (MSVC)
|
||||
target_link_options(PrusaSlicer_app_console PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")
|
||||
endif ()
|
||||
target_compile_definitions(PrusaSlicer_app_console PRIVATE -DSLIC3R_WRAPPER_CONSOLE)
|
||||
add_dependencies(PrusaSlicer_app_console PrusaSlicer)
|
||||
set_target_properties(PrusaSlicer_app_console PROPERTIES OUTPUT_NAME "prusa-slicer-console")
|
||||
target_include_directories(PrusaSlicer_app_console SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(PrusaSlicer_app_console PRIVATE boost_headeronly)
|
||||
endif ()
|
||||
|
||||
# Link the resources dir to where Slic3r GUI expects it
|
||||
if (MSVC)
|
||||
if (WIN32)
|
||||
if (CMAKE_CONFIGURATION_TYPES)
|
||||
foreach (CONF ${CMAKE_CONFIGURATION_TYPES})
|
||||
file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CONF}" WIN_CONF_OUTPUT_DIR)
|
||||
|
|
|
|||
|
|
@ -7,10 +7,13 @@
|
|||
#include <Windows.h>
|
||||
#include <wchar.h>
|
||||
#ifdef SLIC3R_GUI
|
||||
extern "C"
|
||||
{
|
||||
// Let the NVIDIA and AMD know we want to use their graphics card
|
||||
// on a dual graphics card system.
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||
}
|
||||
#endif /* SLIC3R_GUI */
|
||||
#endif /* WIN32 */
|
||||
|
||||
|
|
@ -23,6 +26,7 @@
|
|||
#include <boost/nowide/args.hpp>
|
||||
#include <boost/nowide/cenv.hpp>
|
||||
#include <boost/nowide/iostream.hpp>
|
||||
#include <boost/nowide/integration/filesystem.hpp>
|
||||
|
||||
#include "unix/fhs.hpp" // Generated by CMake from ../platform/unix/fhs.hpp.in
|
||||
|
||||
|
|
@ -44,18 +48,39 @@
|
|||
#ifdef SLIC3R_GUI
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/3DScene.hpp"
|
||||
#endif /* SLIC3R_GUI */
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
PrinterTechnology get_printer_technology(const DynamicConfig &config)
|
||||
{
|
||||
const ConfigOptionEnum<PrinterTechnology> *opt = config.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology");
|
||||
const ConfigOptionEnum<PrinterTechnology> *opt = config.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology");
|
||||
return (opt == nullptr) ? ptUnknown : opt->value;
|
||||
}
|
||||
|
||||
int CLI::run(int argc, char **argv)
|
||||
int CLI::run(int argc, char **argv)
|
||||
{
|
||||
// Switch boost::filesystem to utf8.
|
||||
try {
|
||||
boost::nowide::nowide_filesystem();
|
||||
} catch (const std::runtime_error& ex) {
|
||||
std::string caption = std::string(SLIC3R_APP_NAME) + " Error";
|
||||
std::string text = std::string("An error occured while setting up locale.\n") + (
|
||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||
// likely some linux system
|
||||
"You may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n"
|
||||
#endif
|
||||
SLIC3R_APP_NAME " will now terminate.\n\n") + ex.what();
|
||||
#if defined(_WIN32) && defined(SLIC3R_GUI)
|
||||
if (m_actions.empty())
|
||||
// Empty actions means Slicer is executed in the GUI mode. Show a GUI message.
|
||||
MessageBoxA(NULL, text.c_str(), caption.c_str(), MB_OK | MB_ICONERROR);
|
||||
#endif
|
||||
boost::nowide::cerr << text.c_str() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (! this->setup(argc, argv))
|
||||
return 1;
|
||||
|
||||
|
|
@ -64,14 +89,14 @@ int CLI::run(int argc, char **argv)
|
|||
|
||||
bool start_gui = m_actions.empty() &&
|
||||
// cutting transformations are setting an "export" action.
|
||||
std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() &&
|
||||
std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() &&
|
||||
std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end();
|
||||
std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() &&
|
||||
std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() &&
|
||||
std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end();
|
||||
PrinterTechnology printer_technology = get_printer_technology(m_extra_config);
|
||||
const std::vector<std::string> &load_configs = m_config.option<ConfigOptionStrings>("load", true)->values;
|
||||
|
||||
const std::vector<std::string> &load_configs = m_config.option<ConfigOptionStrings>("load", true)->values;
|
||||
|
||||
// load config files supplied via --load
|
||||
for (auto const &file : load_configs) {
|
||||
for (auto const &file : load_configs) {
|
||||
if (! boost::filesystem::exists(file)) {
|
||||
if (m_config.opt_bool("ignore_nonexistent_config")) {
|
||||
continue;
|
||||
|
|
@ -91,13 +116,13 @@ int CLI::run(int argc, char **argv)
|
|||
PrinterTechnology other_printer_technology = get_printer_technology(config);
|
||||
if (printer_technology == ptUnknown) {
|
||||
printer_technology = other_printer_technology;
|
||||
} else if (printer_technology != other_printer_technology) {
|
||||
} else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) {
|
||||
boost::nowide::cerr << "Mixing configurations for FFF and SLA technologies" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
m_print_config.apply(config);
|
||||
}
|
||||
|
||||
|
||||
// Read input file(s) if any.
|
||||
for (const std::string &file : m_input_files) {
|
||||
if (! boost::filesystem::exists(file)) {
|
||||
|
|
@ -111,7 +136,7 @@ int CLI::run(int argc, char **argv)
|
|||
PrinterTechnology other_printer_technology = get_printer_technology(m_print_config);
|
||||
if (printer_technology == ptUnknown) {
|
||||
printer_technology = other_printer_technology;
|
||||
} else if (printer_technology != other_printer_technology) {
|
||||
} else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) {
|
||||
boost::nowide::cerr << "Mixing configurations for FFF and SLA technologies" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -133,21 +158,21 @@ int CLI::run(int argc, char **argv)
|
|||
m_print_config.normalize();
|
||||
|
||||
if (printer_technology == ptUnknown)
|
||||
printer_technology = std::find(m_actions.begin(), m_actions.end(), "export_sla") == m_actions.end() ? ptFFF : ptSLA;
|
||||
printer_technology = std::find(m_actions.begin(), m_actions.end(), "export_sla") == m_actions.end() ? ptFFF : ptSLA;
|
||||
|
||||
// Initialize full print configs for both the FFF and SLA technologies.
|
||||
FullPrintConfig fff_print_config;
|
||||
// SLAFullPrintConfig sla_print_config;
|
||||
fff_print_config.apply(m_print_config, true);
|
||||
// sla_print_config.apply(m_print_config, true);
|
||||
|
||||
|
||||
// Loop through transform options.
|
||||
for (auto const &opt_key : m_transforms) {
|
||||
if (opt_key == "merge") {
|
||||
Model m;
|
||||
for (auto &model : m_models)
|
||||
for (ModelObject *o : model.objects)
|
||||
m.add_object(*o);
|
||||
for (ModelObject *o : model.objects)
|
||||
m.add_object(*o);
|
||||
// Rearrange instances unless --dont-arrange is supplied
|
||||
if (! m_config.opt_bool("dont_arrange")) {
|
||||
m.add_default_instances();
|
||||
|
|
@ -159,8 +184,8 @@ int CLI::run(int argc, char **argv)
|
|||
this->has_print_action() ? &bb : nullptr
|
||||
);
|
||||
}
|
||||
m_models.clear();
|
||||
m_models.emplace_back(std::move(m));
|
||||
m_models.clear();
|
||||
m_models.emplace_back(std::move(m));
|
||||
} else if (opt_key == "duplicate") {
|
||||
const BoundingBoxf &bb = fff_print_config.bed_shape.values;
|
||||
for (auto &model : m_models) {
|
||||
|
|
@ -189,11 +214,11 @@ int CLI::run(int argc, char **argv)
|
|||
// this affects instances:
|
||||
model.center_instances_around_point(m_config.option<ConfigOptionPoint>("center")->value);
|
||||
// this affects volumes:
|
||||
//FIXME Vojtech: Who knows why the complete model should be aligned with Z as a single rigid body?
|
||||
//FIXME Vojtech: Who knows why the complete model should be aligned with Z as a single rigid body?
|
||||
//model.align_to_ground();
|
||||
BoundingBoxf3 bbox;
|
||||
for (ModelObject *model_object : model.objects)
|
||||
// We are interested into the Z span only, therefore it is sufficient to measure the bounding box of the 1st instance only.
|
||||
// We are interested into the Z span only, therefore it is sufficient to measure the bounding box of the 1st instance only.
|
||||
bbox.merge(model_object->instance_bounding_box(0, false));
|
||||
for (ModelObject *model_object : model.objects)
|
||||
for (ModelInstance *model_instance : model_object->instances)
|
||||
|
|
@ -204,7 +229,7 @@ int CLI::run(int argc, char **argv)
|
|||
for (auto &model : m_models) {
|
||||
BoundingBoxf3 bb = model.bounding_box();
|
||||
// this affects volumes:
|
||||
model.translate(-(bb.min.x() - p.x()), -(bb.min.y() - p.y()), -bb.min.z());
|
||||
model.translate(-(bb.min.x() - p.x()), -(bb.min.y() - p.y()), -bb.min.z());
|
||||
}
|
||||
} else if (opt_key == "dont_arrange") {
|
||||
// do nothing - this option alters other transform options
|
||||
|
|
@ -241,10 +266,9 @@ int CLI::run(int argc, char **argv)
|
|||
} else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") {
|
||||
std::vector<Model> new_models;
|
||||
for (auto &model : m_models) {
|
||||
model.repair();
|
||||
model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0
|
||||
size_t num_objects = model.objects.size();
|
||||
for (size_t i = 0; i < num_objects; ++ i) {
|
||||
model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0
|
||||
size_t num_objects = model.objects.size();
|
||||
for (size_t i = 0; i < num_objects; ++ i) {
|
||||
|
||||
#if 0
|
||||
if (opt_key == "cut_x") {
|
||||
|
|
@ -255,15 +279,15 @@ int CLI::run(int argc, char **argv)
|
|||
o->cut(Z, m_config.opt_float("cut"), &out);
|
||||
}
|
||||
#else
|
||||
model.objects.front()->cut(0, m_config.opt_float("cut"), true, true, true);
|
||||
model.objects.front()->cut(0, m_config.opt_float("cut"), true, true, true);
|
||||
#endif
|
||||
model.delete_object(size_t(0));
|
||||
model.delete_object(size_t(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: copy less stuff around using pointers
|
||||
m_models = new_models;
|
||||
|
||||
|
||||
if (m_actions.empty())
|
||||
m_actions.push_back("export_stl");
|
||||
}
|
||||
|
|
@ -273,7 +297,7 @@ int CLI::run(int argc, char **argv)
|
|||
for (auto &model : m_models) {
|
||||
TriangleMesh mesh = model.mesh();
|
||||
mesh.repair();
|
||||
|
||||
|
||||
TriangleMeshPtrs meshes = mesh.cut_by_grid(m_config.option<ConfigOptionPoint>("cut_grid")->value);
|
||||
size_t i = 0;
|
||||
for (TriangleMesh* m : meshes) {
|
||||
|
|
@ -284,10 +308,10 @@ int CLI::run(int argc, char **argv)
|
|||
delete m;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: copy less stuff around using pointers
|
||||
m_models = new_models;
|
||||
|
||||
|
||||
if (m_actions.empty())
|
||||
m_actions.push_back("export_stl");
|
||||
}
|
||||
|
|
@ -301,14 +325,15 @@ int CLI::run(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
} else if (opt_key == "repair") {
|
||||
for (auto &model : m_models)
|
||||
model.repair();
|
||||
// Models are repaired by default.
|
||||
//for (auto &model : m_models)
|
||||
// model.repair();
|
||||
} else {
|
||||
boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// loop through action options
|
||||
for (auto const &opt_key : m_actions) {
|
||||
if (opt_key == "help") {
|
||||
|
|
@ -351,14 +376,14 @@ int CLI::run(int argc, char **argv)
|
|||
boost::nowide::cerr << "error: cannot export SLA slices for a SLA configuration" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
// Make a copy of the model if the current action is not the last action, as the model may be
|
||||
// modified by the centering and such.
|
||||
Model model_copy;
|
||||
bool make_copy = &opt_key != &m_actions.back();
|
||||
// Make a copy of the model if the current action is not the last action, as the model may be
|
||||
// modified by the centering and such.
|
||||
Model model_copy;
|
||||
bool make_copy = &opt_key != &m_actions.back();
|
||||
for (Model &model_in : m_models) {
|
||||
if (make_copy)
|
||||
model_copy = model_in;
|
||||
Model &model = make_copy ? model_copy : model_in;
|
||||
if (make_copy)
|
||||
model_copy = model_in;
|
||||
Model &model = make_copy ? model_copy : model_in;
|
||||
// If all objects have defined instances, their relative positions will be
|
||||
// honored when printing (they will be only centered, unless --dont-arrange
|
||||
// is supplied); if any object has no instances, it will get a default one
|
||||
|
|
@ -378,7 +403,7 @@ int CLI::run(int argc, char **argv)
|
|||
if (! m_config.opt_bool("dont_arrange")) {
|
||||
//FIXME make the min_object_distance configurable.
|
||||
model.arrange_objects(fff_print.config().min_object_distance());
|
||||
model.center_instances_around_point(m_config.option<ConfigOptionPoint>("center")->value);
|
||||
model.center_instances_around_point(m_config.option<ConfigOptionPoint>("center")->value);
|
||||
}
|
||||
if (printer_technology == ptFFF) {
|
||||
for (auto* mo : model.objects)
|
||||
|
|
@ -392,40 +417,40 @@ int CLI::run(int argc, char **argv)
|
|||
}
|
||||
if (print->empty())
|
||||
boost::nowide::cout << "Nothing to print for " << outfile << " . Either the print is empty or no object is fully inside the print volume." << std::endl;
|
||||
else
|
||||
else
|
||||
try {
|
||||
std::string outfile_final;
|
||||
print->process();
|
||||
print->process();
|
||||
if (printer_technology == ptFFF) {
|
||||
// The outfile is processed by a PlaceholderParser.
|
||||
outfile = fff_print.export_gcode(outfile, nullptr);
|
||||
outfile_final = fff_print.print_statistics().finalize_output_path(outfile);
|
||||
} else {
|
||||
outfile = sla_print.output_filepath(outfile);
|
||||
outfile = sla_print.output_filepath(outfile);
|
||||
// We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata
|
||||
outfile_final = sla_print.print_statistics().finalize_output_path(outfile);
|
||||
sla_print.export_raster(outfile_final);
|
||||
sla_print.export_raster(outfile_final);
|
||||
}
|
||||
if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final) != 0) {
|
||||
boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl;
|
||||
if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final)) {
|
||||
boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
boost::nowide::cout << "Slicing result exported to " << outfile << std::endl;
|
||||
} catch (const std::exception &ex) {
|
||||
boost::nowide::cerr << ex.what() << std::endl;
|
||||
return 1;
|
||||
boost::nowide::cerr << ex.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
print.center = ! m_config.has("center")
|
||||
&& ! m_config.has("align_xy")
|
||||
&& ! m_config.opt_bool("dont_arrange");
|
||||
print.set_model(model);
|
||||
|
||||
|
||||
// start chronometer
|
||||
typedef std::chrono::high_resolution_clock clock_;
|
||||
typedef std::chrono::duration<double, std::ratio<1> > second_;
|
||||
std::chrono::time_point<clock_> t0{ clock_::now() };
|
||||
|
||||
|
||||
const std::string outfile = this->output_filepath(model, IO::Gcode);
|
||||
try {
|
||||
print.export_gcode(outfile);
|
||||
|
|
@ -434,7 +459,7 @@ int CLI::run(int argc, char **argv)
|
|||
return 1;
|
||||
}
|
||||
boost::nowide::cout << "G-code exported to " << outfile << std::endl;
|
||||
|
||||
|
||||
// output some statistics
|
||||
double duration { std::chrono::duration_cast<second_>(clock_::now() - t0).count() };
|
||||
boost::nowide::cout << std::fixed << std::setprecision(0)
|
||||
|
|
@ -451,51 +476,55 @@ int CLI::run(int argc, char **argv)
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (start_gui) {
|
||||
|
||||
if (start_gui) {
|
||||
#ifdef SLIC3R_GUI
|
||||
// #ifdef USE_WX
|
||||
GUI::GUI_App *gui = new GUI::GUI_App();
|
||||
GUI::GUI_App *gui = new GUI::GUI_App();
|
||||
// gui->autosave = m_config.opt_string("autosave");
|
||||
GUI::GUI_App::SetInstance(gui);
|
||||
gui->CallAfter([gui, this, &load_configs] {
|
||||
if (!gui->initialized()) {
|
||||
return;
|
||||
}
|
||||
GUI::GUI_App::SetInstance(gui);
|
||||
gui->CallAfter([gui, this, &load_configs] {
|
||||
if (!gui->initialized()) {
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
// Load the cummulative config over the currently active profiles.
|
||||
//FIXME if multiple configs are loaded, only the last one will have an effect.
|
||||
// We need to decide what to do about loading of separate presets (just print preset, just filament preset etc).
|
||||
// As of now only the full configs are supported here.
|
||||
if (!m_print_config.empty())
|
||||
gui->mainframe->load_config(m_print_config);
|
||||
// Load the cummulative config over the currently active profiles.
|
||||
//FIXME if multiple configs are loaded, only the last one will have an effect.
|
||||
// We need to decide what to do about loading of separate presets (just print preset, just filament preset etc).
|
||||
// As of now only the full configs are supported here.
|
||||
if (!m_print_config.empty())
|
||||
gui->mainframe->load_config(m_print_config);
|
||||
#endif
|
||||
if (! load_configs.empty())
|
||||
// Load the last config to give it a name at the UI. The name of the preset may be later
|
||||
// changed by loading an AMF or 3MF.
|
||||
//FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config.
|
||||
gui->mainframe->load_config_file(load_configs.back());
|
||||
// If loading a 3MF file, the config is loaded from the last one.
|
||||
if (! m_input_files.empty())
|
||||
gui->plater()->load_files(m_input_files, true, true);
|
||||
if (! m_extra_config.empty())
|
||||
gui->mainframe->load_config(m_extra_config);
|
||||
});
|
||||
return wxEntry(argc, argv);
|
||||
if (! load_configs.empty())
|
||||
// Load the last config to give it a name at the UI. The name of the preset may be later
|
||||
// changed by loading an AMF or 3MF.
|
||||
//FIXME this is not strictly correct, as one may pass a print/filament/printer profile here instead of a full config.
|
||||
gui->mainframe->load_config_file(load_configs.back());
|
||||
// If loading a 3MF file, the config is loaded from the last one.
|
||||
if (! m_input_files.empty())
|
||||
gui->plater()->load_files(m_input_files, true, true);
|
||||
if (! m_extra_config.empty())
|
||||
gui->mainframe->load_config(m_extra_config);
|
||||
});
|
||||
int result = wxEntry(argc, argv);
|
||||
//FIXME this is a workaround for the PrusaSlicer 2.1 release.
|
||||
_3DScene::destroy();
|
||||
return result;
|
||||
#else /* SLIC3R_GUI */
|
||||
// No GUI support. Just print out a help.
|
||||
this->print_help(false);
|
||||
// If started without a parameter, consider it to be OK, otherwise report an error code (no action etc).
|
||||
return (argc == 0) ? 0 : 1;
|
||||
// No GUI support. Just print out a help.
|
||||
this->print_help(false);
|
||||
// If started without a parameter, consider it to be OK, otherwise report an error code (no action etc).
|
||||
return (argc == 0) ? 0 : 1;
|
||||
#endif /* SLIC3R_GUI */
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CLI::setup(int argc, char **argv)
|
||||
{
|
||||
{
|
||||
Slic3r::set_logging_level(1);
|
||||
const char *loglevel = boost::nowide::getenv("SLIC3R_LOGLEVEL");
|
||||
if (loglevel != nullptr) {
|
||||
if (loglevel[0] >= '0' && loglevel[0] <= '9' && loglevel[1] == 0)
|
||||
|
|
@ -536,18 +565,18 @@ bool CLI::setup(int argc, char **argv)
|
|||
// If any option is unsupported, print usage and abort immediately.
|
||||
t_config_option_keys opt_order;
|
||||
if (! m_config.read_cli(argc, argv, &m_input_files, &opt_order)) {
|
||||
// Separate error message reported by the CLI parser from the help.
|
||||
boost::nowide::cerr << std::endl;
|
||||
// Separate error message reported by the CLI parser from the help.
|
||||
boost::nowide::cerr << std::endl;
|
||||
this->print_help();
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
// Parse actions and transform options.
|
||||
for (auto const &opt_key : opt_order) {
|
||||
if (cli_actions_config_def.has(opt_key))
|
||||
m_actions.emplace_back(opt_key);
|
||||
else if (cli_transform_config_def.has(opt_key))
|
||||
m_transforms.emplace_back(opt_key);
|
||||
}
|
||||
// Parse actions and transform options.
|
||||
for (auto const &opt_key : opt_order) {
|
||||
if (cli_actions_config_def.has(opt_key))
|
||||
m_actions.emplace_back(opt_key);
|
||||
else if (cli_transform_config_def.has(opt_key))
|
||||
m_transforms.emplace_back(opt_key);
|
||||
}
|
||||
|
||||
{
|
||||
const ConfigOptionInt *opt_loglevel = m_config.opt<ConfigOptionInt>("loglevel");
|
||||
|
|
@ -560,15 +589,15 @@ bool CLI::setup(int argc, char **argv)
|
|||
for (const std::pair<t_config_option_key, ConfigOptionDef> &optdef : *options)
|
||||
m_config.optptr(optdef.first, true);
|
||||
|
||||
set_data_dir(m_config.opt_string("datadir"));
|
||||
set_data_dir(m_config.opt_string("datadir"));
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const
|
||||
void CLI::print_help(bool include_print_options, PrinterTechnology printer_technology) const
|
||||
{
|
||||
boost::nowide::cout
|
||||
<< SLIC3R_BUILD_ID << " " << "based on Slic3r"
|
||||
<< SLIC3R_BUILD_ID << " " << "based on Slic3r"
|
||||
#ifdef SLIC3R_GUI
|
||||
<< " (with GUI support)"
|
||||
#else /* SLIC3R_GUI */
|
||||
|
|
@ -576,24 +605,24 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn
|
|||
#endif /* SLIC3R_GUI */
|
||||
<< std::endl
|
||||
<< "https://github.com/prusa3d/PrusaSlicer" << std::endl << std::endl
|
||||
<< "Usage: slic3r [ ACTIONS ] [ TRANSFORM ] [ OPTIONS ] [ file.stl ... ]" << std::endl
|
||||
<< "Usage: prusa-slicer [ ACTIONS ] [ TRANSFORM ] [ OPTIONS ] [ file.stl ... ]" << std::endl
|
||||
<< std::endl
|
||||
<< "Actions:" << std::endl;
|
||||
cli_actions_config_def.print_cli_help(boost::nowide::cout, false);
|
||||
|
||||
|
||||
boost::nowide::cout
|
||||
<< std::endl
|
||||
<< "Transform options:" << std::endl;
|
||||
cli_transform_config_def.print_cli_help(boost::nowide::cout, false);
|
||||
|
||||
|
||||
boost::nowide::cout
|
||||
<< std::endl
|
||||
<< "Other options:" << std::endl;
|
||||
cli_misc_config_def.print_cli_help(boost::nowide::cout, false);
|
||||
|
||||
|
||||
if (include_print_options) {
|
||||
boost::nowide::cout << std::endl;
|
||||
print_config_def.print_cli_help(boost::nowide::cout, true, [printer_technology](const ConfigOptionDef &def)
|
||||
print_config_def.print_cli_help(boost::nowide::cout, true, [printer_technology](const ConfigOptionDef &def)
|
||||
{ return printer_technology == ptAny || def.printer_technology == ptAny || printer_technology == def.printer_technology; });
|
||||
} else {
|
||||
boost::nowide::cout
|
||||
|
|
@ -610,14 +639,14 @@ bool CLI::export_models(IO::ExportFormat format)
|
|||
switch (format) {
|
||||
case IO::AMF: success = Slic3r::store_amf(path.c_str(), &model, nullptr); break;
|
||||
case IO::OBJ: success = Slic3r::store_obj(path.c_str(), &model); break;
|
||||
case IO::STL: success = Slic3r::store_stl(path.c_str(), &model, true); break;
|
||||
case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr); break;
|
||||
case IO::STL: success = Slic3r::store_stl(path.c_str(), &model, true); break;
|
||||
case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr); break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
if (success)
|
||||
std::cout << "File exported to " << path << std::endl;
|
||||
std::cout << "File exported to " << path << std::endl;
|
||||
else {
|
||||
std::cerr << "File export to " << path << " failed" << std::endl;
|
||||
std::cerr << "File export to " << path << " failed" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -631,12 +660,12 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co
|
|||
case IO::AMF: ext = ".zip.amf"; break;
|
||||
case IO::OBJ: ext = ".obj"; break;
|
||||
case IO::STL: ext = ".stl"; break;
|
||||
case IO::TMF: ext = ".3mf"; break;
|
||||
case IO::TMF: ext = ".3mf"; break;
|
||||
default: assert(false); break;
|
||||
};
|
||||
auto proposed_path = boost::filesystem::path(model.propose_export_file_name_and_path(ext));
|
||||
// use --output when available
|
||||
std::string cmdline_param = m_config.opt_string("output");
|
||||
std::string cmdline_param = m_config.opt_string("output");
|
||||
if (! cmdline_param.empty()) {
|
||||
// if we were supplied a directory, use it and append our automatically generated filename
|
||||
boost::filesystem::path cmdline_path(cmdline_param);
|
||||
|
|
@ -648,20 +677,20 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co
|
|||
return proposed_path.string();
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
extern "C" {
|
||||
__declspec(dllexport) int __stdcall slic3r_main(int argc, wchar_t **argv)
|
||||
{
|
||||
// Convert wchar_t arguments to UTF8.
|
||||
std::vector<std::string> argv_narrow;
|
||||
std::vector<char*> argv_ptrs(argc + 1, nullptr);
|
||||
for (size_t i = 0; i < argc; ++ i)
|
||||
argv_narrow.emplace_back(boost::nowide::narrow(argv[i]));
|
||||
for (size_t i = 0; i < argc; ++ i)
|
||||
argv_ptrs[i] = const_cast<char*>(argv_narrow[i].data());
|
||||
// Call the UTF8 main.
|
||||
return CLI().run(argc, argv_ptrs.data());
|
||||
}
|
||||
__declspec(dllexport) int __stdcall slic3r_main(int argc, wchar_t **argv)
|
||||
{
|
||||
// Convert wchar_t arguments to UTF8.
|
||||
std::vector<std::string> argv_narrow;
|
||||
std::vector<char*> argv_ptrs(argc + 1, nullptr);
|
||||
for (size_t i = 0; i < argc; ++ i)
|
||||
argv_narrow.emplace_back(boost::nowide::narrow(argv[i]));
|
||||
for (size_t i = 0; i < argc; ++ i)
|
||||
argv_ptrs[i] = const_cast<char*>(argv_narrow[i].data());
|
||||
// Call the UTF8 main.
|
||||
return CLI().run(argc, argv_ptrs.data());
|
||||
}
|
||||
}
|
||||
#else /* _MSC_VER */
|
||||
int main(int argc, char **argv)
|
||||
|
|
|
|||
|
|
@ -8,17 +8,20 @@
|
|||
#include <wchar.h>
|
||||
|
||||
#ifdef SLIC3R_GUI
|
||||
// Let the NVIDIA and AMD know we want to use their graphics card
|
||||
// on a dual graphics card system.
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||
extern "C"
|
||||
{
|
||||
// Let the NVIDIA and AMD know we want to use their graphics card
|
||||
// on a dual graphics card system.
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||
}
|
||||
#endif /* SLIC3R_GUI */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef SLIC3R_GUI
|
||||
#include <GL/GL.h>
|
||||
#include <GL/GL.h>
|
||||
#endif /* SLIC3R_GUI */
|
||||
|
||||
#include <string>
|
||||
|
|
@ -33,97 +36,97 @@
|
|||
class OpenGLVersionCheck
|
||||
{
|
||||
public:
|
||||
std::string version;
|
||||
std::string glsl_version;
|
||||
std::string vendor;
|
||||
std::string renderer;
|
||||
std::string version;
|
||||
std::string glsl_version;
|
||||
std::string vendor;
|
||||
std::string renderer;
|
||||
|
||||
HINSTANCE hOpenGL = nullptr;
|
||||
bool success = false;
|
||||
HINSTANCE hOpenGL = nullptr;
|
||||
bool success = false;
|
||||
|
||||
bool load_opengl_dll()
|
||||
{
|
||||
MSG msg = {0};
|
||||
WNDCLASS wc = {0};
|
||||
wc.lpfnWndProc = OpenGLVersionCheck::supports_opengl2_wndproc;
|
||||
wc.hInstance = (HINSTANCE)GetModuleHandle(nullptr);
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
|
||||
wc.lpszClassName = L"PrusaSlicer_opengl_version_check";
|
||||
wc.style = CS_OWNDC;
|
||||
if (RegisterClass(&wc)) {
|
||||
HWND hwnd = CreateWindowW(wc.lpszClassName, L"PrusaSlicer_opengl_version_check", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, wc.hInstance, (LPVOID)this);
|
||||
if (hwnd) {
|
||||
message_pump_exit = false;
|
||||
while (GetMessage(&msg, NULL, 0, 0 ) > 0 && ! message_pump_exit)
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
return this->success;
|
||||
}
|
||||
bool load_opengl_dll()
|
||||
{
|
||||
MSG msg = {0};
|
||||
WNDCLASS wc = {0};
|
||||
wc.lpfnWndProc = OpenGLVersionCheck::supports_opengl2_wndproc;
|
||||
wc.hInstance = (HINSTANCE)GetModuleHandle(nullptr);
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
|
||||
wc.lpszClassName = L"PrusaSlicer_opengl_version_check";
|
||||
wc.style = CS_OWNDC;
|
||||
if (RegisterClass(&wc)) {
|
||||
HWND hwnd = CreateWindowW(wc.lpszClassName, L"PrusaSlicer_opengl_version_check", WS_OVERLAPPEDWINDOW, 0, 0, 640, 480, 0, 0, wc.hInstance, (LPVOID)this);
|
||||
if (hwnd) {
|
||||
message_pump_exit = false;
|
||||
while (GetMessage(&msg, NULL, 0, 0 ) > 0 && ! message_pump_exit)
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
return this->success;
|
||||
}
|
||||
|
||||
void unload_opengl_dll()
|
||||
{
|
||||
if (this->hOpenGL) {
|
||||
BOOL released = FreeLibrary(this->hOpenGL);
|
||||
if (released)
|
||||
printf("System OpenGL library released\n");
|
||||
else
|
||||
printf("System OpenGL library NOT released\n");
|
||||
this->hOpenGL = nullptr;
|
||||
}
|
||||
}
|
||||
void unload_opengl_dll()
|
||||
{
|
||||
if (this->hOpenGL) {
|
||||
BOOL released = FreeLibrary(this->hOpenGL);
|
||||
if (released)
|
||||
printf("System OpenGL library released\n");
|
||||
else
|
||||
printf("System OpenGL library NOT released\n");
|
||||
this->hOpenGL = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const
|
||||
{
|
||||
// printf("is_version_greater_or_equal_to, version: %s\n", version.c_str());
|
||||
std::vector<std::string> tokens;
|
||||
boost::split(tokens, version, boost::is_any_of(" "), boost::token_compress_on);
|
||||
if (tokens.empty())
|
||||
return false;
|
||||
bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const
|
||||
{
|
||||
// printf("is_version_greater_or_equal_to, version: %s\n", version.c_str());
|
||||
std::vector<std::string> tokens;
|
||||
boost::split(tokens, version, boost::is_any_of(" "), boost::token_compress_on);
|
||||
if (tokens.empty())
|
||||
return false;
|
||||
|
||||
std::vector<std::string> numbers;
|
||||
boost::split(numbers, tokens[0], boost::is_any_of("."), boost::token_compress_on);
|
||||
std::vector<std::string> numbers;
|
||||
boost::split(numbers, tokens[0], boost::is_any_of("."), boost::token_compress_on);
|
||||
|
||||
unsigned int gl_major = 0;
|
||||
unsigned int gl_minor = 0;
|
||||
if (numbers.size() > 0)
|
||||
gl_major = ::atoi(numbers[0].c_str());
|
||||
if (numbers.size() > 1)
|
||||
gl_minor = ::atoi(numbers[1].c_str());
|
||||
// printf("Major: %d, minor: %d\n", gl_major, gl_minor);
|
||||
if (gl_major < major)
|
||||
return false;
|
||||
else if (gl_major > major)
|
||||
return true;
|
||||
else
|
||||
return gl_minor >= minor;
|
||||
}
|
||||
unsigned int gl_major = 0;
|
||||
unsigned int gl_minor = 0;
|
||||
if (numbers.size() > 0)
|
||||
gl_major = ::atoi(numbers[0].c_str());
|
||||
if (numbers.size() > 1)
|
||||
gl_minor = ::atoi(numbers[1].c_str());
|
||||
// printf("Major: %d, minor: %d\n", gl_major, gl_minor);
|
||||
if (gl_major < major)
|
||||
return false;
|
||||
else if (gl_major > major)
|
||||
return true;
|
||||
else
|
||||
return gl_minor >= minor;
|
||||
}
|
||||
|
||||
protected:
|
||||
static bool message_pump_exit;
|
||||
static bool message_pump_exit;
|
||||
|
||||
void check(HWND hWnd)
|
||||
{
|
||||
hOpenGL = LoadLibraryExW(L"opengl32.dll", nullptr, 0);
|
||||
if (hOpenGL == nullptr) {
|
||||
printf("Failed loading the system opengl32.dll\n");
|
||||
return;
|
||||
}
|
||||
void check(HWND hWnd)
|
||||
{
|
||||
hOpenGL = LoadLibraryExW(L"opengl32.dll", nullptr, 0);
|
||||
if (hOpenGL == nullptr) {
|
||||
printf("Failed loading the system opengl32.dll\n");
|
||||
return;
|
||||
}
|
||||
|
||||
typedef HGLRC (WINAPI *Func_wglCreateContext)(HDC);
|
||||
typedef BOOL (WINAPI *Func_wglMakeCurrent )(HDC, HGLRC);
|
||||
typedef BOOL (WINAPI *Func_wglDeleteContext)(HGLRC);
|
||||
typedef GLubyte* (WINAPI *Func_glGetString )(GLenum);
|
||||
typedef HGLRC (WINAPI *Func_wglCreateContext)(HDC);
|
||||
typedef BOOL (WINAPI *Func_wglMakeCurrent )(HDC, HGLRC);
|
||||
typedef BOOL (WINAPI *Func_wglDeleteContext)(HGLRC);
|
||||
typedef GLubyte* (WINAPI *Func_glGetString )(GLenum);
|
||||
|
||||
Func_wglCreateContext wglCreateContext = (Func_wglCreateContext)GetProcAddress(hOpenGL, "wglCreateContext");
|
||||
Func_wglMakeCurrent wglMakeCurrent = (Func_wglMakeCurrent) GetProcAddress(hOpenGL, "wglMakeCurrent");
|
||||
Func_wglDeleteContext wglDeleteContext = (Func_wglDeleteContext)GetProcAddress(hOpenGL, "wglDeleteContext");
|
||||
Func_glGetString glGetString = (Func_glGetString) GetProcAddress(hOpenGL, "glGetString");
|
||||
Func_wglCreateContext wglCreateContext = (Func_wglCreateContext)GetProcAddress(hOpenGL, "wglCreateContext");
|
||||
Func_wglMakeCurrent wglMakeCurrent = (Func_wglMakeCurrent) GetProcAddress(hOpenGL, "wglMakeCurrent");
|
||||
Func_wglDeleteContext wglDeleteContext = (Func_wglDeleteContext)GetProcAddress(hOpenGL, "wglDeleteContext");
|
||||
Func_glGetString glGetString = (Func_glGetString) GetProcAddress(hOpenGL, "glGetString");
|
||||
|
||||
if (wglCreateContext == nullptr || wglMakeCurrent == nullptr || wglDeleteContext == nullptr || glGetString == nullptr) {
|
||||
printf("Failed loading the system opengl32.dll: The library is invalid.\n");
|
||||
return;
|
||||
}
|
||||
if (wglCreateContext == nullptr || wglMakeCurrent == nullptr || wglDeleteContext == nullptr || glGetString == nullptr) {
|
||||
printf("Failed loading the system opengl32.dll: The library is invalid.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd =
|
||||
{
|
||||
|
|
@ -146,152 +149,155 @@ protected:
|
|||
};
|
||||
|
||||
HDC ourWindowHandleToDeviceContext = ::GetDC(hWnd);
|
||||
// Gdi32.dll
|
||||
int letWindowsChooseThisPixelFormat = ::ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd);
|
||||
// Gdi32.dll
|
||||
// Gdi32.dll
|
||||
int letWindowsChooseThisPixelFormat = ::ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd);
|
||||
// Gdi32.dll
|
||||
SetPixelFormat(ourWindowHandleToDeviceContext, letWindowsChooseThisPixelFormat, &pfd);
|
||||
// Opengl32.dll
|
||||
// Opengl32.dll
|
||||
HGLRC glcontext = wglCreateContext(ourWindowHandleToDeviceContext);
|
||||
wglMakeCurrent(ourWindowHandleToDeviceContext, glcontext);
|
||||
// Opengl32.dll
|
||||
const char *data = (const char*)glGetString(GL_VERSION);
|
||||
if (data != nullptr)
|
||||
this->version = data;
|
||||
// printf("check -version: %s\n", version.c_str());
|
||||
data = (const char*)glGetString(0x8B8C); // GL_SHADING_LANGUAGE_VERSION
|
||||
if (data != nullptr)
|
||||
this->glsl_version = data;
|
||||
data = (const char*)glGetString(GL_VENDOR);
|
||||
if (data != nullptr)
|
||||
this->vendor = data;
|
||||
data = (const char*)glGetString(GL_RENDERER);
|
||||
if (data != nullptr)
|
||||
this->renderer = data;
|
||||
const char *data = (const char*)glGetString(GL_VERSION);
|
||||
if (data != nullptr)
|
||||
this->version = data;
|
||||
// printf("check -version: %s\n", version.c_str());
|
||||
data = (const char*)glGetString(0x8B8C); // GL_SHADING_LANGUAGE_VERSION
|
||||
if (data != nullptr)
|
||||
this->glsl_version = data;
|
||||
data = (const char*)glGetString(GL_VENDOR);
|
||||
if (data != nullptr)
|
||||
this->vendor = data;
|
||||
data = (const char*)glGetString(GL_RENDERER);
|
||||
if (data != nullptr)
|
||||
this->renderer = data;
|
||||
// Opengl32.dll
|
||||
wglDeleteContext(glcontext);
|
||||
::ReleaseDC(hWnd, ourWindowHandleToDeviceContext);
|
||||
::ReleaseDC(hWnd, ourWindowHandleToDeviceContext);
|
||||
this->success = true;
|
||||
}
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK supports_opengl2_wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch(message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
{
|
||||
CREATESTRUCT *pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||
OpenGLVersionCheck *ogl_data = reinterpret_cast<OpenGLVersionCheck*>(pCreate->lpCreateParams);
|
||||
ogl_data->check(hWnd);
|
||||
DestroyWindow(hWnd);
|
||||
return 0;
|
||||
}
|
||||
case WM_NCDESTROY:
|
||||
message_pump_exit = true;
|
||||
return 0;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
static LRESULT CALLBACK supports_opengl2_wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch(message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
{
|
||||
CREATESTRUCT *pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||
OpenGLVersionCheck *ogl_data = reinterpret_cast<OpenGLVersionCheck*>(pCreate->lpCreateParams);
|
||||
ogl_data->check(hWnd);
|
||||
DestroyWindow(hWnd);
|
||||
return 0;
|
||||
}
|
||||
case WM_NCDESTROY:
|
||||
message_pump_exit = true;
|
||||
return 0;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool OpenGLVersionCheck::message_pump_exit = false;
|
||||
#endif /* SLIC3R_GUI */
|
||||
|
||||
extern "C" {
|
||||
typedef int (__stdcall *Slic3rMainFunc)(int argc, wchar_t **argv);
|
||||
Slic3rMainFunc slic3r_main = nullptr;
|
||||
typedef int (__stdcall *Slic3rMainFunc)(int argc, wchar_t **argv);
|
||||
Slic3rMainFunc slic3r_main = nullptr;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
#ifdef SLIC3R_WRAPPER_NOCONSOLE
|
||||
int APIENTRY wWinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, PWSTR /* lpCmdLine */, int /* nCmdShow */)
|
||||
{
|
||||
int argc;
|
||||
wchar_t **argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||
int argc;
|
||||
wchar_t **argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
||||
#else
|
||||
int wmain(int argc, wchar_t **argv)
|
||||
{
|
||||
#endif
|
||||
|
||||
std::vector<wchar_t*> argv_extended;
|
||||
argv_extended.emplace_back(argv[0]);
|
||||
std::vector<wchar_t*> argv_extended;
|
||||
argv_extended.emplace_back(argv[0]);
|
||||
|
||||
#ifdef SLIC3R_GUI
|
||||
// Here one may push some additional parameters based on the wrapper type.
|
||||
bool force_mesa = false;
|
||||
// Here one may push some additional parameters based on the wrapper type.
|
||||
bool force_mesa = false;
|
||||
#endif /* SLIC3R_GUI */
|
||||
for (int i = 1; i < argc; ++ i) {
|
||||
for (int i = 1; i < argc; ++ i) {
|
||||
#ifdef SLIC3R_GUI
|
||||
if (wcscmp(argv[i], L"--sw-renderer") == 0)
|
||||
force_mesa = true;
|
||||
else if (wcscmp(argv[i], L"--no-sw-renderer") == 0)
|
||||
force_mesa = false;
|
||||
if (wcscmp(argv[i], L"--sw-renderer") == 0)
|
||||
force_mesa = true;
|
||||
else if (wcscmp(argv[i], L"--no-sw-renderer") == 0)
|
||||
force_mesa = false;
|
||||
#endif /* SLIC3R_GUI */
|
||||
argv_extended.emplace_back(argv[i]);
|
||||
}
|
||||
argv_extended.emplace_back(nullptr);
|
||||
argv_extended.emplace_back(argv[i]);
|
||||
}
|
||||
argv_extended.emplace_back(nullptr);
|
||||
|
||||
#ifdef SLIC3R_GUI
|
||||
OpenGLVersionCheck opengl_version_check;
|
||||
bool load_mesa =
|
||||
// Forced from the command line.
|
||||
force_mesa ||
|
||||
// Running over a rempote desktop, and the RemoteFX is not enabled, therefore Windows will only provide SW OpenGL 1.1 context.
|
||||
// In that case, use Mesa.
|
||||
::GetSystemMetrics(SM_REMOTESESSION) ||
|
||||
// Try to load the default OpenGL driver and test its context version.
|
||||
! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0);
|
||||
OpenGLVersionCheck opengl_version_check;
|
||||
bool load_mesa =
|
||||
// Forced from the command line.
|
||||
force_mesa ||
|
||||
// Running over a rempote desktop, and the RemoteFX is not enabled, therefore Windows will only provide SW OpenGL 1.1 context.
|
||||
// In that case, use Mesa.
|
||||
::GetSystemMetrics(SM_REMOTESESSION) ||
|
||||
// Try to load the default OpenGL driver and test its context version.
|
||||
! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0);
|
||||
#endif /* SLIC3R_GUI */
|
||||
|
||||
wchar_t path_to_exe[MAX_PATH + 1] = { 0 };
|
||||
::GetModuleFileNameW(nullptr, path_to_exe, MAX_PATH);
|
||||
wchar_t drive[_MAX_DRIVE];
|
||||
wchar_t dir[_MAX_DIR];
|
||||
wchar_t fname[_MAX_FNAME];
|
||||
wchar_t ext[_MAX_EXT];
|
||||
_wsplitpath(path_to_exe, drive, dir, fname, ext);
|
||||
_wmakepath(path_to_exe, drive, dir, nullptr, nullptr);
|
||||
wchar_t path_to_exe[MAX_PATH + 1] = { 0 };
|
||||
::GetModuleFileNameW(nullptr, path_to_exe, MAX_PATH);
|
||||
wchar_t drive[_MAX_DRIVE];
|
||||
wchar_t dir[_MAX_DIR];
|
||||
wchar_t fname[_MAX_FNAME];
|
||||
wchar_t ext[_MAX_EXT];
|
||||
_wsplitpath(path_to_exe, drive, dir, fname, ext);
|
||||
_wmakepath(path_to_exe, drive, dir, nullptr, nullptr);
|
||||
|
||||
#ifdef SLIC3R_GUI
|
||||
// https://wiki.qt.io/Cross_compiling_Mesa_for_Windows
|
||||
// http://download.qt.io/development_releases/prebuilt/llvmpipe/windows/
|
||||
if (load_mesa) {
|
||||
opengl_version_check.unload_opengl_dll();
|
||||
wchar_t path_to_mesa[MAX_PATH + 1] = { 0 };
|
||||
wcscpy(path_to_mesa, path_to_exe);
|
||||
wcscat(path_to_mesa, L"mesa\\opengl32.dll");
|
||||
printf("Loading MESA OpenGL library: %S\n", path_to_mesa);
|
||||
HINSTANCE hInstance_OpenGL = LoadLibraryExW(path_to_mesa, nullptr, 0);
|
||||
if (hInstance_OpenGL == nullptr) {
|
||||
printf("MESA OpenGL library was not loaded\n");
|
||||
} else
|
||||
printf("MESA OpenGL library was loaded sucessfully\n");
|
||||
}
|
||||
if (load_mesa) {
|
||||
opengl_version_check.unload_opengl_dll();
|
||||
wchar_t path_to_mesa[MAX_PATH + 1] = { 0 };
|
||||
wcscpy(path_to_mesa, path_to_exe);
|
||||
wcscat(path_to_mesa, L"mesa\\opengl32.dll");
|
||||
printf("Loading MESA OpenGL library: %S\n", path_to_mesa);
|
||||
HINSTANCE hInstance_OpenGL = LoadLibraryExW(path_to_mesa, nullptr, 0);
|
||||
if (hInstance_OpenGL == nullptr) {
|
||||
printf("MESA OpenGL library was not loaded\n");
|
||||
} else
|
||||
printf("MESA OpenGL library was loaded sucessfully\n");
|
||||
}
|
||||
#endif /* SLIC3R_GUI */
|
||||
|
||||
|
||||
wchar_t path_to_slic3r[MAX_PATH + 1] = { 0 };
|
||||
wcscpy(path_to_slic3r, path_to_exe);
|
||||
wcscat(path_to_slic3r, L"PrusaSlicer.dll");
|
||||
wchar_t path_to_slic3r[MAX_PATH + 1] = { 0 };
|
||||
wcscpy(path_to_slic3r, path_to_exe);
|
||||
wcscat(path_to_slic3r, L"PrusaSlicer.dll");
|
||||
// printf("Loading Slic3r library: %S\n", path_to_slic3r);
|
||||
HINSTANCE hInstance_Slic3r = LoadLibraryExW(path_to_slic3r, nullptr, 0);
|
||||
if (hInstance_Slic3r == nullptr) {
|
||||
printf("PrusaSlicer.dll was not loaded\n");
|
||||
return -1;
|
||||
}
|
||||
HINSTANCE hInstance_Slic3r = LoadLibraryExW(path_to_slic3r, nullptr, 0);
|
||||
if (hInstance_Slic3r == nullptr) {
|
||||
printf("PrusaSlicer.dll was not loaded\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// resolve function address here
|
||||
slic3r_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r,
|
||||
// resolve function address here
|
||||
slic3r_main = (Slic3rMainFunc)GetProcAddress(hInstance_Slic3r,
|
||||
#ifdef _WIN64
|
||||
// there is just a single calling conversion, therefore no mangling of the function name.
|
||||
"slic3r_main"
|
||||
// there is just a single calling conversion, therefore no mangling of the function name.
|
||||
"slic3r_main"
|
||||
#else // stdcall calling convention declaration
|
||||
"_slic3r_main@8"
|
||||
"_slic3r_main@8"
|
||||
#endif
|
||||
);
|
||||
if (slic3r_main == nullptr) {
|
||||
printf("could not locate the function slic3r_main in PrusaSlicer.dll\n");
|
||||
return -1;
|
||||
}
|
||||
// argc minus the trailing nullptr of the argv
|
||||
return slic3r_main((int)argv_extended.size() - 1, argv_extended.data());
|
||||
);
|
||||
if (slic3r_main == nullptr) {
|
||||
printf("could not locate the function slic3r_main in PrusaSlicer.dll\n");
|
||||
return -1;
|
||||
}
|
||||
// argc minus the trailing nullptr of the argv
|
||||
return slic3r_main((int)argv_extended.size() - 1, argv_extended.data());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ add_library(admesh STATIC
|
|||
util.cpp
|
||||
)
|
||||
|
||||
target_include_directories(admesh SYSTEM PRIVATE ${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(admesh PRIVATE boost_headeronly)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -25,271 +25,214 @@
|
|||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
// Boost pool: Don't use mutexes to synchronize memory allocation.
|
||||
#define BOOST_POOL_NO_MT
|
||||
#include <boost/pool/object_pool.hpp>
|
||||
|
||||
#include "stl.h"
|
||||
|
||||
static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag);
|
||||
static void reverse_facet(stl_file *stl, int facet_num)
|
||||
{
|
||||
++ stl->stats.facets_reversed;
|
||||
|
||||
static void
|
||||
stl_reverse_facet(stl_file *stl, int facet_num) {
|
||||
stl_vertex tmp_vertex;
|
||||
/* int tmp_neighbor;*/
|
||||
int neighbor[3];
|
||||
int vnot[3];
|
||||
int neighbor[3] = { stl->neighbors_start[facet_num].neighbor[0], stl->neighbors_start[facet_num].neighbor[1], stl->neighbors_start[facet_num].neighbor[2] };
|
||||
int vnot[3] = { stl->neighbors_start[facet_num].which_vertex_not[0], stl->neighbors_start[facet_num].which_vertex_not[1], stl->neighbors_start[facet_num].which_vertex_not[2] };
|
||||
|
||||
stl->stats.facets_reversed += 1;
|
||||
// reverse the facet
|
||||
stl_vertex tmp_vertex = stl->facet_start[facet_num].vertex[0];
|
||||
stl->facet_start[facet_num].vertex[0] = stl->facet_start[facet_num].vertex[1];
|
||||
stl->facet_start[facet_num].vertex[1] = tmp_vertex;
|
||||
|
||||
neighbor[0] = stl->neighbors_start[facet_num].neighbor[0];
|
||||
neighbor[1] = stl->neighbors_start[facet_num].neighbor[1];
|
||||
neighbor[2] = stl->neighbors_start[facet_num].neighbor[2];
|
||||
vnot[0] = stl->neighbors_start[facet_num].which_vertex_not[0];
|
||||
vnot[1] = stl->neighbors_start[facet_num].which_vertex_not[1];
|
||||
vnot[2] = stl->neighbors_start[facet_num].which_vertex_not[2];
|
||||
// fix the vnots of the neighboring facets
|
||||
if (neighbor[0] != -1)
|
||||
stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = (stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6;
|
||||
if (neighbor[1] != -1)
|
||||
stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = (stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6;
|
||||
if (neighbor[2] != -1)
|
||||
stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] = (stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6;
|
||||
|
||||
/* reverse the facet */
|
||||
tmp_vertex = stl->facet_start[facet_num].vertex[0];
|
||||
stl->facet_start[facet_num].vertex[0] =
|
||||
stl->facet_start[facet_num].vertex[1];
|
||||
stl->facet_start[facet_num].vertex[1] = tmp_vertex;
|
||||
// swap the neighbors of the facet that is being reversed
|
||||
stl->neighbors_start[facet_num].neighbor[1] = neighbor[2];
|
||||
stl->neighbors_start[facet_num].neighbor[2] = neighbor[1];
|
||||
|
||||
/* fix the vnots of the neighboring facets */
|
||||
if(neighbor[0] != -1)
|
||||
stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] =
|
||||
(stl->neighbors_start[neighbor[0]].
|
||||
which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6;
|
||||
if(neighbor[1] != -1)
|
||||
stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] =
|
||||
(stl->neighbors_start[neighbor[1]].
|
||||
which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6;
|
||||
if(neighbor[2] != -1)
|
||||
stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] =
|
||||
(stl->neighbors_start[neighbor[2]].
|
||||
which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6;
|
||||
// swap the vnots of the facet that is being reversed
|
||||
stl->neighbors_start[facet_num].which_vertex_not[1] = vnot[2];
|
||||
stl->neighbors_start[facet_num].which_vertex_not[2] = vnot[1];
|
||||
|
||||
/* swap the neighbors of the facet that is being reversed */
|
||||
stl->neighbors_start[facet_num].neighbor[1] = neighbor[2];
|
||||
stl->neighbors_start[facet_num].neighbor[2] = neighbor[1];
|
||||
|
||||
/* swap the vnots of the facet that is being reversed */
|
||||
stl->neighbors_start[facet_num].which_vertex_not[1] = vnot[2];
|
||||
stl->neighbors_start[facet_num].which_vertex_not[2] = vnot[1];
|
||||
|
||||
/* reverse the values of the vnots of the facet that is being reversed */
|
||||
stl->neighbors_start[facet_num].which_vertex_not[0] =
|
||||
(stl->neighbors_start[facet_num].which_vertex_not[0] + 3) % 6;
|
||||
stl->neighbors_start[facet_num].which_vertex_not[1] =
|
||||
(stl->neighbors_start[facet_num].which_vertex_not[1] + 3) % 6;
|
||||
stl->neighbors_start[facet_num].which_vertex_not[2] =
|
||||
(stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6;
|
||||
// reverse the values of the vnots of the facet that is being reversed
|
||||
stl->neighbors_start[facet_num].which_vertex_not[0] = (stl->neighbors_start[facet_num].which_vertex_not[0] + 3) % 6;
|
||||
stl->neighbors_start[facet_num].which_vertex_not[1] = (stl->neighbors_start[facet_num].which_vertex_not[1] + 3) % 6;
|
||||
stl->neighbors_start[facet_num].which_vertex_not[2] = (stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6;
|
||||
}
|
||||
|
||||
void
|
||||
stl_fix_normal_directions(stl_file *stl) {
|
||||
char *norm_sw;
|
||||
/* int edge_num;*/
|
||||
/* int vnot;*/
|
||||
int checked = 0;
|
||||
int facet_num;
|
||||
/* int next_facet;*/
|
||||
int i;
|
||||
int j;
|
||||
struct stl_normal {
|
||||
int facet_num;
|
||||
struct stl_normal *next;
|
||||
};
|
||||
struct stl_normal *head;
|
||||
struct stl_normal *tail;
|
||||
struct stl_normal *newn;
|
||||
struct stl_normal *temp;
|
||||
// Returns true if the normal was flipped.
|
||||
static bool check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
|
||||
{
|
||||
stl_facet *facet = &stl->facet_start[facet_num];
|
||||
|
||||
int* reversed_ids;
|
||||
int reversed_count = 0;
|
||||
int id;
|
||||
int force_exit = 0;
|
||||
stl_normal normal;
|
||||
stl_calculate_normal(normal, facet);
|
||||
stl_normalize_vector(normal);
|
||||
stl_normal normal_dif = (normal - facet->normal).cwiseAbs();
|
||||
|
||||
if (stl->error) return;
|
||||
const float eps = 0.001f;
|
||||
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
|
||||
// Normal is within tolerance. It is not really necessary to change the values here, but just for consistency, I will.
|
||||
facet->normal = normal;
|
||||
return false;
|
||||
}
|
||||
|
||||
// this may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209
|
||||
if (stl->stats.number_of_facets == 0) return;
|
||||
stl_normal test_norm = facet->normal;
|
||||
stl_normalize_vector(test_norm);
|
||||
normal_dif = (normal - test_norm).cwiseAbs();
|
||||
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
|
||||
// The normal is not within tolerance, but direction is OK.
|
||||
if (normal_fix_flag) {
|
||||
facet->normal = normal;
|
||||
++ stl->stats.normals_fixed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initialize linked list. */
|
||||
head = (struct stl_normal*)malloc(sizeof(struct stl_normal));
|
||||
if(head == NULL) perror("stl_fix_normal_directions");
|
||||
tail = (struct stl_normal*)malloc(sizeof(struct stl_normal));
|
||||
if(tail == NULL) perror("stl_fix_normal_directions");
|
||||
head->next = tail;
|
||||
tail->next = tail;
|
||||
|
||||
/* Initialize list that keeps track of already fixed facets. */
|
||||
norm_sw = (char*)calloc(stl->stats.number_of_facets, sizeof(char));
|
||||
if(norm_sw == NULL) perror("stl_fix_normal_directions");
|
||||
|
||||
/* Initialize list that keeps track of reversed facets. */
|
||||
reversed_ids = (int*)calloc(stl->stats.number_of_facets, sizeof(int));
|
||||
if (reversed_ids == NULL) perror("stl_fix_normal_directions reversed_ids");
|
||||
|
||||
facet_num = 0;
|
||||
/* If normal vector is not within tolerance and backwards:
|
||||
Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances
|
||||
of it being wrong randomly are low if most of the triangles are right: */
|
||||
if (stl_check_normal_vector(stl, 0, 0) == 2) {
|
||||
stl_reverse_facet(stl, 0);
|
||||
reversed_ids[reversed_count++] = 0;
|
||||
}
|
||||
|
||||
/* Say that we've fixed this facet: */
|
||||
norm_sw[facet_num] = 1;
|
||||
checked++;
|
||||
|
||||
for(;;) {
|
||||
/* Add neighbors_to_list.
|
||||
Add unconnected neighbors to the list:a */
|
||||
for(j = 0; j < 3; j++) {
|
||||
/* Reverse the neighboring facets if necessary. */
|
||||
if(stl->neighbors_start[facet_num].which_vertex_not[j] > 2) {
|
||||
/* If the facet has a neighbor that is -1, it means that edge isn't shared by another facet */
|
||||
if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
|
||||
if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) {
|
||||
/* trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206) */
|
||||
for (id = reversed_count - 1; id >= 0; --id) {
|
||||
stl_reverse_facet(stl, reversed_ids[id]);
|
||||
}
|
||||
force_exit = 1;
|
||||
break;
|
||||
} else {
|
||||
stl_reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
|
||||
reversed_ids[reversed_count++] = stl->neighbors_start[facet_num].neighbor[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If this edge of the facet is connected: */
|
||||
if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
|
||||
/* If we haven't fixed this facet yet, add it to the list: */
|
||||
if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
|
||||
/* Add node to beginning of list. */
|
||||
newn = (struct stl_normal*)malloc(sizeof(struct stl_normal));
|
||||
if(newn == NULL) perror("stl_fix_normal_directions");
|
||||
newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
|
||||
newn->next = head->next;
|
||||
head->next = newn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* an error occourred, quit the for loop and exit */
|
||||
if (force_exit) break;
|
||||
|
||||
/* Get next facet to fix from top of list. */
|
||||
if(head->next != tail) {
|
||||
facet_num = head->next->facet_num;
|
||||
if(norm_sw[facet_num] != 1) { /* If facet is in list mutiple times */
|
||||
norm_sw[facet_num] = 1; /* Record this one as being fixed. */
|
||||
checked++;
|
||||
}
|
||||
temp = head->next; /* Delete this facet from the list. */
|
||||
head->next = head->next->next;
|
||||
free(temp);
|
||||
} else { /* if we ran out of facets to fix: */
|
||||
/* All of the facets in this part have been fixed. */
|
||||
stl->stats.number_of_parts += 1;
|
||||
if(checked >= stl->stats.number_of_facets) {
|
||||
/* All of the facets have been checked. Bail out. */
|
||||
break;
|
||||
} else {
|
||||
/* There is another part here. Find it and continue. */
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
if(norm_sw[i] == 0) {
|
||||
/* This is the first facet of the next part. */
|
||||
facet_num = i;
|
||||
if(stl_check_normal_vector(stl, i, 0) == 2) {
|
||||
stl_reverse_facet(stl, i);
|
||||
reversed_ids[reversed_count++] = i;
|
||||
}
|
||||
|
||||
norm_sw[facet_num] = 1;
|
||||
checked++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(head);
|
||||
free(tail);
|
||||
free(reversed_ids);
|
||||
free(norm_sw);
|
||||
test_norm *= -1.f;
|
||||
normal_dif = (normal - test_norm).cwiseAbs();
|
||||
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
|
||||
// The normal is not within tolerance and backwards.
|
||||
if (normal_fix_flag) {
|
||||
facet->normal = normal;
|
||||
++ stl->stats.normals_fixed;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (normal_fix_flag) {
|
||||
facet->normal = normal;
|
||||
++ stl->stats.normals_fixed;
|
||||
}
|
||||
// Status is unknown.
|
||||
return false;
|
||||
}
|
||||
|
||||
static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) {
|
||||
/* Returns 0 if the normal is within tolerance */
|
||||
/* Returns 1 if the normal is not within tolerance, but direction is OK */
|
||||
/* Returns 2 if the normal is not within tolerance and backwards */
|
||||
/* Returns 4 if the status is unknown. */
|
||||
void stl_fix_normal_directions(stl_file *stl)
|
||||
{
|
||||
// This may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209
|
||||
if (stl->stats.number_of_facets == 0)
|
||||
return;
|
||||
|
||||
stl_facet *facet;
|
||||
struct stl_normal {
|
||||
int facet_num;
|
||||
stl_normal *next;
|
||||
};
|
||||
|
||||
facet = &stl->facet_start[facet_num];
|
||||
// Initialize linked list.
|
||||
boost::object_pool<stl_normal> pool;
|
||||
stl_normal *head = pool.construct();
|
||||
stl_normal *tail = pool.construct();
|
||||
head->next = tail;
|
||||
tail->next = tail;
|
||||
|
||||
stl_normal normal;
|
||||
stl_calculate_normal(normal, facet);
|
||||
stl_normalize_vector(normal);
|
||||
stl_normal normal_dif = (normal - facet->normal).cwiseAbs();
|
||||
// Initialize list that keeps track of already fixed facets.
|
||||
std::vector<char> norm_sw(stl->stats.number_of_facets, 0);
|
||||
// Initialize list that keeps track of reversed facets.
|
||||
std::vector<int> reversed_ids(stl->stats.number_of_facets, 0);
|
||||
|
||||
const float eps = 0.001f;
|
||||
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
|
||||
/* It is not really necessary to change the values here */
|
||||
/* but just for consistency, I will. */
|
||||
facet->normal = normal;
|
||||
return 0;
|
||||
}
|
||||
int facet_num = 0;
|
||||
int reversed_count = 0;
|
||||
// If normal vector is not within tolerance and backwards:
|
||||
// Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances
|
||||
// of it being wrong randomly are low if most of the triangles are right:
|
||||
if (check_normal_vector(stl, 0, 0)) {
|
||||
reverse_facet(stl, 0);
|
||||
reversed_ids[reversed_count ++] = 0;
|
||||
}
|
||||
|
||||
stl_normal test_norm = facet->normal;
|
||||
stl_normalize_vector(test_norm);
|
||||
normal_dif = (normal - test_norm).cwiseAbs();
|
||||
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
|
||||
if(normal_fix_flag) {
|
||||
facet->normal = normal;
|
||||
stl->stats.normals_fixed += 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// Say that we've fixed this facet:
|
||||
norm_sw[facet_num] = 1;
|
||||
int checked = 1;
|
||||
|
||||
test_norm *= -1.f;
|
||||
normal_dif = (normal - test_norm).cwiseAbs();
|
||||
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
|
||||
// Facet is backwards.
|
||||
if(normal_fix_flag) {
|
||||
facet->normal = normal;
|
||||
stl->stats.normals_fixed += 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
if(normal_fix_flag) {
|
||||
facet->normal = normal;
|
||||
stl->stats.normals_fixed += 1;
|
||||
}
|
||||
return 4;
|
||||
for (;;) {
|
||||
// Add neighbors_to_list. Add unconnected neighbors to the list.
|
||||
bool force_exit = false;
|
||||
for (int j = 0; j < 3; ++ j) {
|
||||
// Reverse the neighboring facets if necessary.
|
||||
if (stl->neighbors_start[facet_num].which_vertex_not[j] > 2) {
|
||||
// If the facet has a neighbor that is -1, it means that edge isn't shared by another facet
|
||||
if (stl->neighbors_start[facet_num].neighbor[j] != -1) {
|
||||
if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) {
|
||||
// trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206)
|
||||
for (int id = reversed_count - 1; id >= 0; -- id)
|
||||
reverse_facet(stl, reversed_ids[id]);
|
||||
force_exit = true;
|
||||
break;
|
||||
}
|
||||
reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
|
||||
reversed_ids[reversed_count ++] = stl->neighbors_start[facet_num].neighbor[j];
|
||||
}
|
||||
}
|
||||
// If this edge of the facet is connected:
|
||||
if (stl->neighbors_start[facet_num].neighbor[j] != -1) {
|
||||
// If we haven't fixed this facet yet, add it to the list:
|
||||
if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
|
||||
// Add node to beginning of list.
|
||||
stl_normal *newn = pool.construct();
|
||||
newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
|
||||
newn->next = head->next;
|
||||
head->next = newn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// an error occourred, quit the for loop and exit
|
||||
if (force_exit)
|
||||
break;
|
||||
|
||||
// Get next facet to fix from top of list.
|
||||
if (head->next != tail) {
|
||||
facet_num = head->next->facet_num;
|
||||
if (norm_sw[facet_num] != 1) { // If facet is in list mutiple times
|
||||
norm_sw[facet_num] = 1; // Record this one as being fixed.
|
||||
++ checked;
|
||||
}
|
||||
stl_normal *temp = head->next; // Delete this facet from the list.
|
||||
head->next = head->next->next;
|
||||
// pool.destroy(temp);
|
||||
} else { // If we ran out of facets to fix: All of the facets in this part have been fixed.
|
||||
++ stl->stats.number_of_parts;
|
||||
if (checked >= stl->stats.number_of_facets)
|
||||
// All of the facets have been checked. Bail out.
|
||||
break;
|
||||
// There is another part here. Find it and continue.
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
if (norm_sw[i] == 0) {
|
||||
// This is the first facet of the next part.
|
||||
facet_num = i;
|
||||
if (check_normal_vector(stl, i, 0)) {
|
||||
reverse_facet(stl, i);
|
||||
reversed_ids[reversed_count++] = i;
|
||||
}
|
||||
norm_sw[facet_num] = 1;
|
||||
++ checked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pool.destroy(head);
|
||||
// pool.destroy(tail);
|
||||
}
|
||||
|
||||
void stl_fix_normal_values(stl_file *stl) {
|
||||
int i;
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
stl_check_normal_vector(stl, i, 1);
|
||||
}
|
||||
void stl_fix_normal_values(stl_file *stl)
|
||||
{
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
check_normal_vector(stl, i, 1);
|
||||
}
|
||||
|
||||
void stl_reverse_all_facets(stl_file *stl)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
|
||||
stl_normal normal;
|
||||
for(int i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
stl_reverse_facet(stl, i);
|
||||
stl_calculate_normal(normal, &stl->facet_start[i]);
|
||||
stl_normalize_vector(normal);
|
||||
stl->facet_start[i].normal = normal;
|
||||
}
|
||||
stl_normal normal;
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
reverse_facet(stl, i);
|
||||
stl_calculate_normal(normal, &stl->facet_start[i]);
|
||||
stl_normalize_vector(normal);
|
||||
stl->facet_start[i].normal = normal;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,242 +23,237 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
|
||||
#include "stl.h"
|
||||
|
||||
void
|
||||
stl_invalidate_shared_vertices(stl_file *stl) {
|
||||
if (stl->error) return;
|
||||
void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its)
|
||||
{
|
||||
// 3 indices to vertex per face
|
||||
its.indices.assign(stl->stats.number_of_facets, stl_triangle_vertex_indices(-1, -1, -1));
|
||||
// Shared vertices (3D coordinates)
|
||||
its.vertices.clear();
|
||||
its.vertices.reserve(stl->stats.number_of_facets / 2);
|
||||
|
||||
if (stl->v_indices != NULL) {
|
||||
free(stl->v_indices);
|
||||
stl->v_indices = NULL;
|
||||
}
|
||||
if (stl->v_shared != NULL) {
|
||||
free(stl->v_shared);
|
||||
stl->v_shared = NULL;
|
||||
}
|
||||
// A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop
|
||||
// while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal
|
||||
// are marked with a unique fan_traversal_stamp.
|
||||
unsigned int fan_traversal_stamp = 0;
|
||||
std::vector<unsigned int> fan_traversal_facet_visited(stl->stats.number_of_facets, 0);
|
||||
|
||||
for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) {
|
||||
for (int j = 0; j < 3; ++ j) {
|
||||
if (its.indices[facet_idx][j] != -1)
|
||||
// Shared vertex was already assigned.
|
||||
continue;
|
||||
// Create a new shared vertex.
|
||||
its.vertices.emplace_back(stl->facet_start[facet_idx].vertex[j]);
|
||||
// Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan.
|
||||
int facet_in_fan_idx = facet_idx;
|
||||
bool edge_direction = false;
|
||||
bool traversal_reversed = false;
|
||||
int vnot = (j + 2) % 3;
|
||||
// Increase the
|
||||
++ fan_traversal_stamp;
|
||||
for (;;) {
|
||||
// Next edge on facet_in_fan_idx to be traversed. The edge is indexed by its starting vertex index.
|
||||
int next_edge = 0;
|
||||
// Vertex index in facet_in_fan_idx, which is being pivoted around, and which is being assigned a new shared vertex.
|
||||
int pivot_vertex = 0;
|
||||
if (vnot > 2) {
|
||||
// The edge of facet_in_fan_idx opposite to vnot is equally oriented, therefore
|
||||
// the neighboring facet is flipped.
|
||||
if (! edge_direction) {
|
||||
pivot_vertex = (vnot + 2) % 3;
|
||||
next_edge = pivot_vertex;
|
||||
} else {
|
||||
pivot_vertex = (vnot + 1) % 3;
|
||||
next_edge = vnot % 3;
|
||||
}
|
||||
edge_direction = ! edge_direction;
|
||||
} else {
|
||||
// The neighboring facet is correctly oriented.
|
||||
if (! edge_direction) {
|
||||
pivot_vertex = (vnot + 1) % 3;
|
||||
next_edge = vnot;
|
||||
} else {
|
||||
pivot_vertex = (vnot + 2) % 3;
|
||||
next_edge = pivot_vertex;
|
||||
}
|
||||
}
|
||||
its.indices[facet_in_fan_idx][pivot_vertex] = its.vertices.size() - 1;
|
||||
fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp;
|
||||
|
||||
// next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
|
||||
int next_facet = stl->neighbors_start[facet_in_fan_idx].neighbor[next_edge];
|
||||
if (next_facet == -1) {
|
||||
// No neighbor going in the current direction.
|
||||
if (traversal_reversed) {
|
||||
// Went to one limit, then turned back and reached the other limit. Quit the fan traversal.
|
||||
break;
|
||||
} else {
|
||||
// Reached the first limit. Now try to reverse and traverse up to the other limit.
|
||||
edge_direction = true;
|
||||
vnot = (j + 1) % 3;
|
||||
traversal_reversed = true;
|
||||
facet_in_fan_idx = facet_idx;
|
||||
}
|
||||
} else if (next_facet == facet_idx) {
|
||||
// Traversed a closed fan all around.
|
||||
// assert(! traversal_reversed);
|
||||
break;
|
||||
} else if (next_facet >= (int)stl->stats.number_of_facets) {
|
||||
// The mesh is not valid!
|
||||
// assert(false);
|
||||
break;
|
||||
} else if (fan_traversal_facet_visited[next_facet] == fan_traversal_stamp) {
|
||||
// Traversed a closed fan all around, but did not reach the starting face.
|
||||
// This indicates an invalid geometry (non-manifold).
|
||||
//assert(false);
|
||||
break;
|
||||
} else {
|
||||
// Continue traversal.
|
||||
// next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
|
||||
vnot = stl->neighbors_start[facet_in_fan_idx].which_vertex_not[next_edge];
|
||||
facet_in_fan_idx = next_facet;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
stl_generate_shared_vertices(stl_file *stl) {
|
||||
int i;
|
||||
int j;
|
||||
int first_facet;
|
||||
int direction;
|
||||
int facet_num;
|
||||
int vnot;
|
||||
int next_edge;
|
||||
int pivot_vertex;
|
||||
int next_facet;
|
||||
int reversed;
|
||||
bool its_write_off(const indexed_triangle_set &its, const char *file)
|
||||
{
|
||||
/* Open the file */
|
||||
FILE *fp = boost::nowide::fopen(file, "w");
|
||||
if (fp == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stl->error) return;
|
||||
fprintf(fp, "OFF\n");
|
||||
fprintf(fp, "%d %d 0\n", (int)its.vertices.size(), (int)its.indices.size());
|
||||
for (int i = 0; i < its.vertices.size(); ++ i)
|
||||
fprintf(fp, "\t%f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
|
||||
for (uint32_t i = 0; i < its.indices.size(); ++ i)
|
||||
fprintf(fp, "\t3 %d %d %d\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* make sure this function is idempotent and does not leak memory */
|
||||
stl_invalidate_shared_vertices(stl);
|
||||
bool its_write_vrml(const indexed_triangle_set &its, const char *file)
|
||||
{
|
||||
/* Open the file */
|
||||
FILE *fp = boost::nowide::fopen(file, "w");
|
||||
if (fp == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_write_vrml: Couldn't open " << file << " for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
stl->v_indices = (v_indices_struct*)
|
||||
calloc(stl->stats.number_of_facets, sizeof(v_indices_struct));
|
||||
if(stl->v_indices == NULL) perror("stl_generate_shared_vertices");
|
||||
stl->v_shared = (stl_vertex*)
|
||||
calloc((stl->stats.number_of_facets / 2), sizeof(stl_vertex));
|
||||
if(stl->v_shared == NULL) perror("stl_generate_shared_vertices");
|
||||
stl->stats.shared_malloced = stl->stats.number_of_facets / 2;
|
||||
stl->stats.shared_vertices = 0;
|
||||
fprintf(fp, "#VRML V1.0 ascii\n\n");
|
||||
fprintf(fp, "Separator {\n");
|
||||
fprintf(fp, "\tDEF STLShape ShapeHints {\n");
|
||||
fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n");
|
||||
fprintf(fp, "\t\tfaceType CONVEX\n");
|
||||
fprintf(fp, "\t\tshapeType SOLID\n");
|
||||
fprintf(fp, "\t\tcreaseAngle 0.0\n");
|
||||
fprintf(fp, "\t}\n");
|
||||
fprintf(fp, "\tDEF STLModel Separator {\n");
|
||||
fprintf(fp, "\t\tDEF STLColor Material {\n");
|
||||
fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n");
|
||||
fprintf(fp, "\t\t}\n");
|
||||
fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n");
|
||||
fprintf(fp, "\t\t\tpoint [\n");
|
||||
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
stl->v_indices[i].vertex[0] = -1;
|
||||
stl->v_indices[i].vertex[1] = -1;
|
||||
stl->v_indices[i].vertex[2] = -1;
|
||||
}
|
||||
int i = 0;
|
||||
for (; i + 1 < its.vertices.size(); ++ i)
|
||||
fprintf(fp, "\t\t\t\t%f %f %f,\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
|
||||
fprintf(fp, "\t\t\t\t%f %f %f]\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
|
||||
fprintf(fp, "\t\t}\n");
|
||||
fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
|
||||
fprintf(fp, "\t\t\tcoordIndex [\n");
|
||||
|
||||
for (size_t i = 0; i + 1 < its.indices.size(); ++ i)
|
||||
fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
|
||||
fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
|
||||
fprintf(fp, "\t\t}\n");
|
||||
fprintf(fp, "\t}\n");
|
||||
fprintf(fp, "}\n");
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool its_write_obj(const indexed_triangle_set &its, const char *file)
|
||||
{
|
||||
|
||||
FILE *fp = boost::nowide::fopen(file, "w");
|
||||
if (fp == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << file << " for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < its.vertices.size(); ++ i)
|
||||
fprintf(fp, "v %f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
|
||||
for (size_t i = 0; i < its.indices.size(); ++ i)
|
||||
fprintf(fp, "f %d %d %d\n", its.indices[i][0]+1, its.indices[i][1]+1, its.indices[i][2]+1);
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
first_facet = i;
|
||||
for(j = 0; j < 3; j++) {
|
||||
if(stl->v_indices[i].vertex[j] != -1) {
|
||||
continue;
|
||||
}
|
||||
if(stl->stats.shared_vertices == stl->stats.shared_malloced) {
|
||||
stl->stats.shared_malloced += 1024;
|
||||
stl->v_shared = (stl_vertex*)realloc(stl->v_shared,
|
||||
stl->stats.shared_malloced * sizeof(stl_vertex));
|
||||
if(stl->v_shared == NULL) perror("stl_generate_shared_vertices");
|
||||
}
|
||||
// Check validity of the mesh, assert on error.
|
||||
bool stl_validate(const stl_file *stl, const indexed_triangle_set &its)
|
||||
{
|
||||
assert(! stl->facet_start.empty());
|
||||
assert(stl->facet_start.size() == stl->stats.number_of_facets);
|
||||
assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
|
||||
assert(stl->facet_start.size() == stl->neighbors_start.size());
|
||||
assert(! stl->neighbors_start.empty());
|
||||
assert((its.indices.empty()) == (its.vertices.empty()));
|
||||
assert(stl->stats.number_of_facets > 0);
|
||||
assert(its.vertices.empty() || its.indices.size() == stl->stats.number_of_facets);
|
||||
|
||||
stl->v_shared[stl->stats.shared_vertices] =
|
||||
stl->facet_start[i].vertex[j];
|
||||
|
||||
direction = 0;
|
||||
reversed = 0;
|
||||
facet_num = i;
|
||||
vnot = (j + 2) % 3;
|
||||
|
||||
for(;;) {
|
||||
if(vnot > 2) {
|
||||
if(direction == 0) {
|
||||
pivot_vertex = (vnot + 2) % 3;
|
||||
next_edge = pivot_vertex;
|
||||
direction = 1;
|
||||
} else {
|
||||
pivot_vertex = (vnot + 1) % 3;
|
||||
next_edge = vnot % 3;
|
||||
direction = 0;
|
||||
}
|
||||
} else {
|
||||
if(direction == 0) {
|
||||
pivot_vertex = (vnot + 1) % 3;
|
||||
next_edge = vnot;
|
||||
} else {
|
||||
pivot_vertex = (vnot + 2) % 3;
|
||||
next_edge = pivot_vertex;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
// Verify validity of neighborship data.
|
||||
for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) {
|
||||
const stl_neighbors &nbr = stl->neighbors_start[facet_idx];
|
||||
const int *vertices = its.indices.empty() ? nullptr : its.indices[facet_idx].data();
|
||||
for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) {
|
||||
int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx];
|
||||
assert(nbr_face < (int)stl->stats.number_of_facets);
|
||||
if (nbr_face != -1) {
|
||||
int nbr_vnot = nbr.which_vertex_not[nbr_idx];
|
||||
assert(nbr_vnot >= 0 && nbr_vnot < 6);
|
||||
// Neighbor of the neighbor is the original face.
|
||||
assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx);
|
||||
int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3];
|
||||
assert(vnot_back >= 0 && vnot_back < 6);
|
||||
assert((nbr_vnot < 3) == (vnot_back < 3));
|
||||
assert(vnot_back % 3 == (nbr_idx + 2) % 3);
|
||||
if (vertices != nullptr) {
|
||||
// Has shared vertices.
|
||||
if (nbr_vnot < 3) {
|
||||
// Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented.
|
||||
assert((its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[nbr_idx]));
|
||||
} else {
|
||||
// Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped.
|
||||
assert((its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[nbr_idx]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stl->v_indices[facet_num].vertex[pivot_vertex] =
|
||||
stl->stats.shared_vertices;
|
||||
|
||||
next_facet = stl->neighbors_start[facet_num].neighbor[next_edge];
|
||||
if(next_facet == -1) {
|
||||
if(reversed) {
|
||||
break;
|
||||
} else {
|
||||
direction = 1;
|
||||
vnot = (j + 1) % 3;
|
||||
reversed = 1;
|
||||
facet_num = first_facet;
|
||||
}
|
||||
} else if(next_facet != first_facet) {
|
||||
vnot = stl->neighbors_start[facet_num].
|
||||
which_vertex_not[next_edge];
|
||||
facet_num = next_facet;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
stl->stats.shared_vertices += 1;
|
||||
}
|
||||
}
|
||||
#endif /* _DEBUG */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_off(stl_file *stl, const char *file) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
char *error_msg;
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = boost::nowide::fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "OFF\n");
|
||||
fprintf(fp, "%d %d 0\n",
|
||||
stl->stats.shared_vertices, stl->stats.number_of_facets);
|
||||
|
||||
for(i = 0; i < stl->stats.shared_vertices; i++) {
|
||||
fprintf(fp, "\t%f %f %f\n",
|
||||
stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
|
||||
}
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0],
|
||||
stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_vrml(stl_file *stl, const char *file) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
char *error_msg;
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = boost::nowide::fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "#VRML V1.0 ascii\n\n");
|
||||
fprintf(fp, "Separator {\n");
|
||||
fprintf(fp, "\tDEF STLShape ShapeHints {\n");
|
||||
fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n");
|
||||
fprintf(fp, "\t\tfaceType CONVEX\n");
|
||||
fprintf(fp, "\t\tshapeType SOLID\n");
|
||||
fprintf(fp, "\t\tcreaseAngle 0.0\n");
|
||||
fprintf(fp, "\t}\n");
|
||||
fprintf(fp, "\tDEF STLModel Separator {\n");
|
||||
fprintf(fp, "\t\tDEF STLColor Material {\n");
|
||||
fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n");
|
||||
fprintf(fp, "\t\t}\n");
|
||||
fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n");
|
||||
fprintf(fp, "\t\t\tpoint [\n");
|
||||
|
||||
for(i = 0; i < (stl->stats.shared_vertices - 1); i++) {
|
||||
fprintf(fp, "\t\t\t\t%f %f %f,\n",
|
||||
stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
|
||||
}
|
||||
fprintf(fp, "\t\t\t\t%f %f %f]\n",
|
||||
stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
|
||||
fprintf(fp, "\t\t}\n");
|
||||
fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
|
||||
fprintf(fp, "\t\t\tcoordIndex [\n");
|
||||
|
||||
for(i = 0; i < (stl->stats.number_of_facets - 1); i++) {
|
||||
fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", stl->v_indices[i].vertex[0],
|
||||
stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
|
||||
}
|
||||
fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", stl->v_indices[i].vertex[0],
|
||||
stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
|
||||
fprintf(fp, "\t\t}\n");
|
||||
fprintf(fp, "\t}\n");
|
||||
fprintf(fp, "}\n");
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void stl_write_obj (stl_file *stl, const char *file) {
|
||||
int i;
|
||||
FILE* fp;
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = boost::nowide::fopen(file, "w");
|
||||
if (fp == NULL) {
|
||||
char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < stl->stats.shared_vertices; i++) {
|
||||
fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
|
||||
}
|
||||
for (i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
// Check validity of the mesh, assert on error.
|
||||
bool stl_validate(const stl_file *stl)
|
||||
{
|
||||
indexed_triangle_set its;
|
||||
return stl_validate(stl, its);
|
||||
}
|
||||
|
|
|
|||
295
src/admesh/stl.h
295
src/admesh/stl.h
|
|
@ -27,6 +27,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <vector>
|
||||
#include <Eigen/Geometry>
|
||||
|
||||
// Size of the binary STL header, free form.
|
||||
|
|
@ -40,22 +41,23 @@
|
|||
|
||||
typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_vertex;
|
||||
typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_normal;
|
||||
typedef Eigen::Matrix<int, 3, 1, Eigen::DontAlign> stl_triangle_vertex_indices;
|
||||
static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
|
||||
static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
|
||||
|
||||
struct stl_facet {
|
||||
stl_normal normal;
|
||||
stl_vertex vertex[3];
|
||||
char extra[2];
|
||||
stl_normal normal;
|
||||
stl_vertex vertex[3];
|
||||
char extra[2];
|
||||
|
||||
stl_facet rotated(const Eigen::Quaternion<float, Eigen::DontAlign> &rot) {
|
||||
stl_facet out;
|
||||
out.normal = rot * this->normal;
|
||||
out.vertex[0] = rot * this->vertex[0];
|
||||
out.vertex[1] = rot * this->vertex[1];
|
||||
out.vertex[2] = rot * this->vertex[2];
|
||||
return out;
|
||||
}
|
||||
stl_facet rotated(const Eigen::Quaternion<float, Eigen::DontAlign> &rot) const {
|
||||
stl_facet out;
|
||||
out.normal = rot * this->normal;
|
||||
out.vertex[0] = rot * this->vertex[0];
|
||||
out.vertex[1] = rot * this->vertex[1];
|
||||
out.vertex[2] = rot * this->vertex[2];
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
#define SIZEOF_STL_FACET 50
|
||||
|
|
@ -67,104 +69,102 @@ static_assert(sizeof(stl_facet) >= SIZEOF_STL_FACET, "size of stl_facet incorrec
|
|||
|
||||
typedef enum {binary, ascii, inmemory} stl_type;
|
||||
|
||||
typedef struct {
|
||||
stl_vertex p1;
|
||||
stl_vertex p2;
|
||||
int facet_number;
|
||||
} stl_edge;
|
||||
struct stl_neighbors {
|
||||
stl_neighbors() { reset(); }
|
||||
void reset() {
|
||||
neighbor[0] = -1;
|
||||
neighbor[1] = -1;
|
||||
neighbor[2] = -1;
|
||||
which_vertex_not[0] = -1;
|
||||
which_vertex_not[1] = -1;
|
||||
which_vertex_not[2] = -1;
|
||||
}
|
||||
int num_neighbors_missing() const { return (this->neighbor[0] == -1) + (this->neighbor[1] == -1) + (this->neighbor[2] == -1); }
|
||||
int num_neighbors() const { return 3 - this->num_neighbors_missing(); }
|
||||
|
||||
typedef struct stl_hash_edge {
|
||||
// Key of a hash edge: sorted vertices of the edge.
|
||||
uint32_t key[6];
|
||||
// Compare two keys.
|
||||
bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; }
|
||||
bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); }
|
||||
int hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11 + key[4] / 7 + key[5] / 3)) % M; }
|
||||
// Index of a facet owning this edge.
|
||||
int facet_number;
|
||||
// Index of this edge inside the facet with an index of facet_number.
|
||||
// If this edge is stored backwards, which_edge is increased by 3.
|
||||
int which_edge;
|
||||
struct stl_hash_edge *next;
|
||||
} stl_hash_edge;
|
||||
// Index of a neighbor facet.
|
||||
int neighbor[3];
|
||||
// Index of an opposite vertex at the neighbor face.
|
||||
char which_vertex_not[3];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
// Index of a neighbor facet.
|
||||
int neighbor[3];
|
||||
// Index of an opposite vertex at the neighbor face.
|
||||
char which_vertex_not[3];
|
||||
} stl_neighbors;
|
||||
struct stl_stats {
|
||||
stl_stats() { this->reset(); }
|
||||
void reset() { memset(this, 0, sizeof(stl_stats)); this->volume = -1.0; }
|
||||
char header[81];
|
||||
stl_type type;
|
||||
uint32_t number_of_facets;
|
||||
stl_vertex max;
|
||||
stl_vertex min;
|
||||
stl_vertex size;
|
||||
float bounding_diameter;
|
||||
float shortest_edge;
|
||||
float volume;
|
||||
int connected_edges;
|
||||
int connected_facets_1_edge;
|
||||
int connected_facets_2_edge;
|
||||
int connected_facets_3_edge;
|
||||
int facets_w_1_bad_edge;
|
||||
int facets_w_2_bad_edge;
|
||||
int facets_w_3_bad_edge;
|
||||
int original_num_facets;
|
||||
int edges_fixed;
|
||||
int degenerate_facets;
|
||||
int facets_removed;
|
||||
int facets_added;
|
||||
int facets_reversed;
|
||||
int backwards_edges;
|
||||
int normals_fixed;
|
||||
int number_of_parts;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int vertex[3];
|
||||
} v_indices_struct;
|
||||
struct stl_file {
|
||||
stl_file() {}
|
||||
|
||||
typedef struct {
|
||||
char header[81];
|
||||
stl_type type;
|
||||
uint32_t number_of_facets;
|
||||
stl_vertex max;
|
||||
stl_vertex min;
|
||||
stl_vertex size;
|
||||
float bounding_diameter;
|
||||
float shortest_edge;
|
||||
float volume;
|
||||
unsigned number_of_blocks;
|
||||
int connected_edges;
|
||||
int connected_facets_1_edge;
|
||||
int connected_facets_2_edge;
|
||||
int connected_facets_3_edge;
|
||||
int facets_w_1_bad_edge;
|
||||
int facets_w_2_bad_edge;
|
||||
int facets_w_3_bad_edge;
|
||||
int original_num_facets;
|
||||
int edges_fixed;
|
||||
int degenerate_facets;
|
||||
int facets_removed;
|
||||
int facets_added;
|
||||
int facets_reversed;
|
||||
int backwards_edges;
|
||||
int normals_fixed;
|
||||
int number_of_parts;
|
||||
int malloced;
|
||||
int freed;
|
||||
int facets_malloced;
|
||||
int collisions;
|
||||
int shared_vertices;
|
||||
int shared_malloced;
|
||||
} stl_stats;
|
||||
void clear() {
|
||||
this->facet_start.clear();
|
||||
this->neighbors_start.clear();
|
||||
this->stats.reset();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
FILE *fp;
|
||||
stl_facet *facet_start;
|
||||
stl_hash_edge **heads;
|
||||
stl_hash_edge *tail;
|
||||
int M;
|
||||
stl_neighbors *neighbors_start;
|
||||
v_indices_struct *v_indices;
|
||||
stl_vertex *v_shared;
|
||||
stl_stats stats;
|
||||
char error;
|
||||
} stl_file;
|
||||
size_t memsize() const {
|
||||
return sizeof(*this) + sizeof(stl_facet) * facet_start.size() + sizeof(stl_neighbors) * neighbors_start.size();
|
||||
}
|
||||
|
||||
std::vector<stl_facet> facet_start;
|
||||
std::vector<stl_neighbors> neighbors_start;
|
||||
// Statistics
|
||||
stl_stats stats;
|
||||
};
|
||||
|
||||
extern void stl_open(stl_file *stl, const char *file);
|
||||
extern void stl_close(stl_file *stl);
|
||||
struct indexed_triangle_set
|
||||
{
|
||||
indexed_triangle_set() {}
|
||||
|
||||
void clear() { indices.clear(); vertices.clear(); }
|
||||
|
||||
size_t memsize() const {
|
||||
return sizeof(*this) + sizeof(stl_triangle_vertex_indices) * indices.size() + sizeof(stl_vertex) * vertices.size();
|
||||
}
|
||||
|
||||
std::vector<stl_triangle_vertex_indices> indices;
|
||||
std::vector<stl_vertex> vertices;
|
||||
//FIXME add normals once we get rid of the stl_file from TriangleMesh completely.
|
||||
//std::vector<stl_normal> normals
|
||||
};
|
||||
|
||||
extern bool stl_open(stl_file *stl, const char *file);
|
||||
extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file);
|
||||
extern void stl_print_neighbors(stl_file *stl, char *file);
|
||||
extern void stl_put_little_int(FILE *fp, int value_in);
|
||||
extern void stl_put_little_float(FILE *fp, float value_in);
|
||||
extern void stl_write_ascii(stl_file *stl, const char *file, const char *label);
|
||||
extern void stl_write_binary(stl_file *stl, const char *file, const char *label);
|
||||
extern void stl_write_binary_block(stl_file *stl, FILE *fp);
|
||||
extern bool stl_print_neighbors(stl_file *stl, char *file);
|
||||
extern bool stl_write_ascii(stl_file *stl, const char *file, const char *label);
|
||||
extern bool stl_write_binary(stl_file *stl, const char *file, const char *label);
|
||||
extern void stl_check_facets_exact(stl_file *stl);
|
||||
extern void stl_check_facets_nearby(stl_file *stl, float tolerance);
|
||||
extern void stl_remove_unconnected_facets(stl_file *stl);
|
||||
extern void stl_write_vertex(stl_file *stl, int facet, int vertex);
|
||||
extern void stl_write_facet(stl_file *stl, char *label, int facet);
|
||||
extern void stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge);
|
||||
extern void stl_write_neighbor(stl_file *stl, int facet);
|
||||
extern void stl_write_quad_object(stl_file *stl, char *file);
|
||||
extern bool stl_write_quad_object(stl_file *stl, char *file);
|
||||
extern void stl_verify_neighbors(stl_file *stl);
|
||||
extern void stl_fill_holes(stl_file *stl);
|
||||
extern void stl_fix_normal_directions(stl_file *stl);
|
||||
|
|
@ -186,36 +186,30 @@ extern void stl_get_size(stl_file *stl);
|
|||
template<typename T>
|
||||
extern void stl_transform(stl_file *stl, T *trafo3x4)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) {
|
||||
stl_facet &face = stl->facet_start[i_face];
|
||||
for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) {
|
||||
stl_vertex &v_dst = face.vertex[i_vertex];
|
||||
stl_vertex v_src = v_dst;
|
||||
v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]);
|
||||
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]);
|
||||
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
|
||||
}
|
||||
stl_vertex &v_dst = face.normal;
|
||||
stl_vertex v_src = v_dst;
|
||||
v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2));
|
||||
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2));
|
||||
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2));
|
||||
}
|
||||
|
||||
for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) {
|
||||
stl_facet &face = stl->facet_start[i_face];
|
||||
for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) {
|
||||
stl_vertex &v_dst = face.vertex[i_vertex];
|
||||
stl_vertex v_src = v_dst;
|
||||
v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]);
|
||||
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]);
|
||||
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
|
||||
}
|
||||
stl_vertex &v_dst = face.normal;
|
||||
stl_vertex v_src = v_dst;
|
||||
v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2));
|
||||
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2));
|
||||
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2));
|
||||
}
|
||||
|
||||
stl_get_size(stl);
|
||||
stl_get_size(stl);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
|
||||
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
|
||||
for (size_t i = 0; i < stl->stats.number_of_facets; ++i) {
|
||||
for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
stl_facet &f = stl->facet_start[i];
|
||||
for (size_t j = 0; j < 3; ++j)
|
||||
f.vertex[j] = (t * f.vertex[j].template cast<T>()).template cast<float>().eval();
|
||||
|
|
@ -228,10 +222,7 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Aff
|
|||
template<typename T>
|
||||
inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < stl->stats.number_of_facets; ++i) {
|
||||
for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
stl_facet &f = stl->facet_start[i];
|
||||
for (size_t j = 0; j < 3; ++j)
|
||||
f.vertex[j] = (m * f.vertex[j].template cast<T>()).template cast<float>().eval();
|
||||
|
|
@ -241,13 +232,43 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::Don
|
|||
stl_get_size(stl);
|
||||
}
|
||||
|
||||
extern void stl_open_merge(stl_file *stl, char *file);
|
||||
extern void stl_invalidate_shared_vertices(stl_file *stl);
|
||||
extern void stl_generate_shared_vertices(stl_file *stl);
|
||||
extern void stl_write_obj(stl_file *stl, const char *file);
|
||||
extern void stl_write_off(stl_file *stl, const char *file);
|
||||
extern void stl_write_dxf(stl_file *stl, const char *file, char *label);
|
||||
extern void stl_write_vrml(stl_file *stl, const char *file);
|
||||
|
||||
template<typename T>
|
||||
extern void its_transform(indexed_triangle_set &its, T *trafo3x4)
|
||||
{
|
||||
for (stl_vertex &v_dst : its.vertices) {
|
||||
stl_vertex v_src = v_dst;
|
||||
v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]);
|
||||
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]);
|
||||
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void its_transform(indexed_triangle_set &its, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
|
||||
{
|
||||
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
|
||||
for (stl_vertex &v : its.vertices)
|
||||
v = (t * v.template cast<T>()).template cast<float>().eval();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void its_transform(indexed_triangle_set &its, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m)
|
||||
{
|
||||
for (stl_vertex &v : its.vertices)
|
||||
v = (m * v.template cast<T>()).template cast<float>().eval();
|
||||
}
|
||||
|
||||
extern void its_rotate_x(indexed_triangle_set &its, float angle);
|
||||
extern void its_rotate_y(indexed_triangle_set &its, float angle);
|
||||
extern void its_rotate_z(indexed_triangle_set &its, float angle);
|
||||
|
||||
extern void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its);
|
||||
extern bool its_write_obj(const indexed_triangle_set &its, const char *file);
|
||||
extern bool its_write_off(const indexed_triangle_set &its, const char *file);
|
||||
extern bool its_write_vrml(const indexed_triangle_set &its, const char *file);
|
||||
|
||||
extern bool stl_write_dxf(stl_file *stl, const char *file, char *label);
|
||||
inline void stl_calculate_normal(stl_normal &normal, stl_facet *facet) {
|
||||
normal = (facet->vertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]);
|
||||
}
|
||||
|
|
@ -258,24 +279,18 @@ inline void stl_normalize_vector(stl_normal &normal) {
|
|||
else
|
||||
normal *= float(1.0 / length);
|
||||
}
|
||||
inline bool stl_vertex_lower(const stl_vertex &a, const stl_vertex &b) {
|
||||
return (a(0) != b(0)) ? (a(0) < b(0)) :
|
||||
((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2)));
|
||||
}
|
||||
extern void stl_calculate_volume(stl_file *stl);
|
||||
|
||||
extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag);
|
||||
extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag);
|
||||
|
||||
extern void stl_initialize(stl_file *stl);
|
||||
extern void stl_count_facets(stl_file *stl, const char *file);
|
||||
extern void stl_allocate(stl_file *stl);
|
||||
extern void stl_read(stl_file *stl, int first_facet, bool first);
|
||||
extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first);
|
||||
extern void stl_reallocate(stl_file *stl);
|
||||
extern void stl_add_facet(stl_file *stl, stl_facet *new_facet);
|
||||
extern void stl_add_facet(stl_file *stl, const stl_facet *new_facet);
|
||||
|
||||
extern void stl_clear_error(stl_file *stl);
|
||||
extern int stl_get_error(stl_file *stl);
|
||||
extern void stl_exit_on_error(stl_file *stl);
|
||||
// Validate the mesh, assert on error.
|
||||
extern bool stl_validate(const stl_file *stl);
|
||||
extern bool stl_validate(const stl_file *stl, const indexed_triangle_set &its);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -22,159 +22,86 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/predef/other/endian.h>
|
||||
|
||||
#include "stl.h"
|
||||
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/detail/endian.hpp>
|
||||
|
||||
#if !defined(SEEK_SET)
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
#endif
|
||||
|
||||
void
|
||||
stl_stats_out(stl_file *stl, FILE *file, char *input_file) {
|
||||
if (stl->error) return;
|
||||
|
||||
/* this is here for Slic3r, without our config.h
|
||||
it won't use this part of the code anyway */
|
||||
void stl_stats_out(stl_file *stl, FILE *file, char *input_file)
|
||||
{
|
||||
// This is here for Slic3r, without our config.h it won't use this part of the code anyway.
|
||||
#ifndef VERSION
|
||||
#define VERSION "unknown"
|
||||
#endif
|
||||
fprintf(file, "\n\
|
||||
================= Results produced by ADMesh version " VERSION " ================\n");
|
||||
fprintf(file, "\
|
||||
Input file : %s\n", input_file);
|
||||
if(stl->stats.type == binary) {
|
||||
fprintf(file, "\
|
||||
File type : Binary STL file\n");
|
||||
} else {
|
||||
fprintf(file, "\
|
||||
File type : ASCII STL file\n");
|
||||
}
|
||||
fprintf(file, "\
|
||||
Header : %s\n", stl->stats.header);
|
||||
fprintf(file, "============== Size ==============\n");
|
||||
fprintf(file, "Min X = % f, Max X = % f\n",
|
||||
stl->stats.min(0), stl->stats.max(0));
|
||||
fprintf(file, "Min Y = % f, Max Y = % f\n",
|
||||
stl->stats.min(1), stl->stats.max(1));
|
||||
fprintf(file, "Min Z = % f, Max Z = % f\n",
|
||||
stl->stats.min(2), stl->stats.max(2));
|
||||
|
||||
fprintf(file, "\
|
||||
========= Facet Status ========== Original ============ Final ====\n");
|
||||
fprintf(file, "\
|
||||
Number of facets : %5d %5d\n",
|
||||
stl->stats.original_num_facets, stl->stats.number_of_facets);
|
||||
fprintf(file, "\
|
||||
Facets with 1 disconnected edge : %5d %5d\n",
|
||||
stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge -
|
||||
stl->stats.connected_facets_3_edge);
|
||||
fprintf(file, "\
|
||||
Facets with 2 disconnected edges : %5d %5d\n",
|
||||
stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge -
|
||||
stl->stats.connected_facets_2_edge);
|
||||
fprintf(file, "\
|
||||
Facets with 3 disconnected edges : %5d %5d\n",
|
||||
stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets -
|
||||
stl->stats.connected_facets_1_edge);
|
||||
fprintf(file, "\
|
||||
Total disconnected facets : %5d %5d\n",
|
||||
stl->stats.facets_w_1_bad_edge + stl->stats.facets_w_2_bad_edge +
|
||||
stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets -
|
||||
stl->stats.connected_facets_3_edge);
|
||||
|
||||
fprintf(file,
|
||||
"=== Processing Statistics === ===== Other Statistics =====\n");
|
||||
fprintf(file, "\
|
||||
Number of parts : %5d Volume : % f\n",
|
||||
stl->stats.number_of_parts, stl->stats.volume);
|
||||
fprintf(file, "\
|
||||
Degenerate facets : %5d\n", stl->stats.degenerate_facets);
|
||||
fprintf(file, "\
|
||||
Edges fixed : %5d\n", stl->stats.edges_fixed);
|
||||
fprintf(file, "\
|
||||
Facets removed : %5d\n", stl->stats.facets_removed);
|
||||
fprintf(file, "\
|
||||
Facets added : %5d\n", stl->stats.facets_added);
|
||||
fprintf(file, "\
|
||||
Facets reversed : %5d\n", stl->stats.facets_reversed);
|
||||
fprintf(file, "\
|
||||
Backwards edges : %5d\n", stl->stats.backwards_edges);
|
||||
fprintf(file, "\
|
||||
Normals fixed : %5d\n", stl->stats.normals_fixed);
|
||||
fprintf(file, "\n================= Results produced by ADMesh version " VERSION " ================\n");
|
||||
fprintf(file, "Input file : %s\n", input_file);
|
||||
if (stl->stats.type == binary)
|
||||
fprintf(file, "File type : Binary STL file\n");
|
||||
else
|
||||
fprintf(file, "File type : ASCII STL file\n");
|
||||
fprintf(file, "Header : %s\n", stl->stats.header);
|
||||
fprintf(file, "============== Size ==============\n");
|
||||
fprintf(file, "Min X = % f, Max X = % f\n", stl->stats.min(0), stl->stats.max(0));
|
||||
fprintf(file, "Min Y = % f, Max Y = % f\n", stl->stats.min(1), stl->stats.max(1));
|
||||
fprintf(file, "Min Z = % f, Max Z = % f\n", stl->stats.min(2), stl->stats.max(2));
|
||||
fprintf(file, "========= Facet Status ========== Original ============ Final ====\n");
|
||||
fprintf(file, "Number of facets : %5d %5d\n", stl->stats.original_num_facets, stl->stats.number_of_facets);
|
||||
fprintf(file, "Facets with 1 disconnected edge : %5d %5d\n",
|
||||
stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge);
|
||||
fprintf(file, "Facets with 2 disconnected edges : %5d %5d\n",
|
||||
stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge);
|
||||
fprintf(file, "Facets with 3 disconnected edges : %5d %5d\n",
|
||||
stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_1_edge);
|
||||
fprintf(file, "Total disconnected facets : %5d %5d\n",
|
||||
stl->stats.facets_w_1_bad_edge + stl->stats.facets_w_2_bad_edge + stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_3_edge);
|
||||
fprintf(file, "=== Processing Statistics === ===== Other Statistics =====\n");
|
||||
fprintf(file, "Number of parts : %5d Volume : %f\n", stl->stats.number_of_parts, stl->stats.volume);
|
||||
fprintf(file, "Degenerate facets : %5d\n", stl->stats.degenerate_facets);
|
||||
fprintf(file, "Edges fixed : %5d\n", stl->stats.edges_fixed);
|
||||
fprintf(file, "Facets removed : %5d\n", stl->stats.facets_removed);
|
||||
fprintf(file, "Facets added : %5d\n", stl->stats.facets_added);
|
||||
fprintf(file, "Facets reversed : %5d\n", stl->stats.facets_reversed);
|
||||
fprintf(file, "Backwards edges : %5d\n", stl->stats.backwards_edges);
|
||||
fprintf(file, "Normals fixed : %5d\n", stl->stats.normals_fixed);
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_ascii(stl_file *stl, const char *file, const char *label) {
|
||||
int i;
|
||||
char *error_msg;
|
||||
bool stl_write_ascii(stl_file *stl, const char *file, const char *label)
|
||||
{
|
||||
FILE *fp = boost::nowide::fopen(file, "w");
|
||||
if (fp == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stl->error) return;
|
||||
fprintf(fp, "solid %s\n", label);
|
||||
|
||||
/* Open the file */
|
||||
FILE *fp = boost::nowide::fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
fprintf(fp, " facet normal % .8E % .8E % .8E\n", stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), stl->facet_start[i].normal(2));
|
||||
fprintf(fp, " outer loop\n");
|
||||
fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2));
|
||||
fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2));
|
||||
fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
|
||||
fprintf(fp, " endloop\n");
|
||||
fprintf(fp, " endfacet\n");
|
||||
}
|
||||
|
||||
fprintf(fp, "solid %s\n", label);
|
||||
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
fprintf(fp, " facet normal % .8E % .8E % .8E\n",
|
||||
stl->facet_start[i].normal(0), stl->facet_start[i].normal(1),
|
||||
stl->facet_start[i].normal(2));
|
||||
fprintf(fp, " outer loop\n");
|
||||
fprintf(fp, " vertex % .8E % .8E % .8E\n",
|
||||
stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
|
||||
stl->facet_start[i].vertex[0](2));
|
||||
fprintf(fp, " vertex % .8E % .8E % .8E\n",
|
||||
stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
|
||||
stl->facet_start[i].vertex[1](2));
|
||||
fprintf(fp, " vertex % .8E % .8E % .8E\n",
|
||||
stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
|
||||
stl->facet_start[i].vertex[2](2));
|
||||
fprintf(fp, " endloop\n");
|
||||
fprintf(fp, " endfacet\n");
|
||||
}
|
||||
|
||||
fprintf(fp, "endsolid %s\n", label);
|
||||
|
||||
fclose(fp);
|
||||
fprintf(fp, "endsolid %s\n", label);
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
stl_print_neighbors(stl_file *stl, char *file) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
char *error_msg;
|
||||
bool stl_print_neighbors(stl_file *stl, char *file)
|
||||
{
|
||||
FILE *fp = boost::nowide::fopen(file, "w");
|
||||
if (fp == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_print_neighbors: Couldn't open " << file << " for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = boost::nowide::fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_print_neighbors: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n",
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n",
|
||||
i,
|
||||
stl->neighbors_start[i].neighbor[0],
|
||||
(int)stl->neighbors_start[i].which_vertex_not[0],
|
||||
|
|
@ -182,234 +109,142 @@ stl_print_neighbors(stl_file *stl, char *file) {
|
|||
(int)stl->neighbors_start[i].which_vertex_not[1],
|
||||
stl->neighbors_start[i].neighbor[2],
|
||||
(int)stl->neighbors_start[i].which_vertex_not[2]);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef BOOST_LITTLE_ENDIAN
|
||||
#if BOOST_ENDIAN_BIG_BYTE
|
||||
// Swap a buffer of 32bit data from little endian to big endian and vice versa.
|
||||
void stl_internal_reverse_quads(char *buf, size_t cnt)
|
||||
{
|
||||
for (size_t i = 0; i < cnt; i += 4) {
|
||||
std::swap(buf[i], buf[i+3]);
|
||||
std::swap(buf[i+1], buf[i+2]);
|
||||
}
|
||||
for (size_t i = 0; i < cnt; i += 4) {
|
||||
std::swap(buf[i], buf[i+3]);
|
||||
std::swap(buf[i+1], buf[i+2]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
stl_write_binary(stl_file *stl, const char *file, const char *label) {
|
||||
FILE *fp;
|
||||
int i;
|
||||
char *error_msg;
|
||||
bool stl_write_binary(stl_file *stl, const char *file, const char *label)
|
||||
{
|
||||
FILE *fp = boost::nowide::fopen(file, "wb");
|
||||
if (fp == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_write_binary: Couldn't open " << file << " for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stl->error) return;
|
||||
fprintf(fp, "%s", label);
|
||||
for (size_t i = strlen(label); i < LABEL_SIZE; ++ i)
|
||||
putc(0, fp);
|
||||
|
||||
/* Open the file */
|
||||
fp = boost::nowide::fopen(file, "wb");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_binary: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "%s", label);
|
||||
for(i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp);
|
||||
|
||||
fseek(fp, LABEL_SIZE, SEEK_SET);
|
||||
#ifdef BOOST_LITTLE_ENDIAN
|
||||
fwrite(&stl->stats.number_of_facets, 4, 1, fp);
|
||||
for (i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
fwrite(stl->facet_start + i, SIZEOF_STL_FACET, 1, fp);
|
||||
#else /* BOOST_LITTLE_ENDIAN */
|
||||
char buffer[50];
|
||||
// Convert the number of facets to little endian.
|
||||
memcpy(buffer, &stl->stats.number_of_facets, 4);
|
||||
stl_internal_reverse_quads(buffer, 4);
|
||||
fwrite(buffer, 4, 1, fp);
|
||||
for (i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
memcpy(buffer, stl->facet_start + i, 50);
|
||||
// Convert to little endian.
|
||||
stl_internal_reverse_quads(buffer, 48);
|
||||
fwrite(buffer, SIZEOF_STL_FACET, 1, fp);
|
||||
}
|
||||
#endif /* BOOST_LITTLE_ENDIAN */
|
||||
fclose(fp);
|
||||
#if !defined(SEEK_SET)
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
fseek(fp, LABEL_SIZE, SEEK_SET);
|
||||
#if BOOST_ENDIAN_LITTLE_BYTE
|
||||
fwrite(&stl->stats.number_of_facets, 4, 1, fp);
|
||||
for (const stl_facet &facet : stl->facet_start)
|
||||
fwrite(&facet, SIZEOF_STL_FACET, 1, fp);
|
||||
#else /* BOOST_ENDIAN_LITTLE_BYTE */
|
||||
char buffer[50];
|
||||
// Convert the number of facets to little endian.
|
||||
memcpy(buffer, &stl->stats.number_of_facets, 4);
|
||||
stl_internal_reverse_quads(buffer, 4);
|
||||
fwrite(buffer, 4, 1, fp);
|
||||
for (i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
memcpy(buffer, stl->facet_start + i, 50);
|
||||
// Convert to little endian.
|
||||
stl_internal_reverse_quads(buffer, 48);
|
||||
fwrite(buffer, SIZEOF_STL_FACET, 1, fp);
|
||||
}
|
||||
#endif /* BOOST_ENDIAN_LITTLE_BYTE */
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_vertex(stl_file *stl, int facet, int vertex) {
|
||||
if (stl->error) return;
|
||||
printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
|
||||
void stl_write_vertex(stl_file *stl, int facet, int vertex)
|
||||
{
|
||||
printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
|
||||
stl->facet_start[facet].vertex[vertex](0),
|
||||
stl->facet_start[facet].vertex[vertex](1),
|
||||
stl->facet_start[facet].vertex[vertex](2));
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_facet(stl_file *stl, char *label, int facet) {
|
||||
if (stl->error) return;
|
||||
printf("facet (%d)/ %s\n", facet, label);
|
||||
stl_write_vertex(stl, facet, 0);
|
||||
stl_write_vertex(stl, facet, 1);
|
||||
stl_write_vertex(stl, facet, 2);
|
||||
void stl_write_facet(stl_file *stl, char *label, int facet)
|
||||
{
|
||||
printf("facet (%d)/ %s\n", facet, label);
|
||||
stl_write_vertex(stl, facet, 0);
|
||||
stl_write_vertex(stl, facet, 1);
|
||||
stl_write_vertex(stl, facet, 2);
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge) {
|
||||
if (stl->error) return;
|
||||
printf("edge (%d)/(%d) %s\n", edge.facet_number, edge.which_edge, label);
|
||||
if(edge.which_edge < 3) {
|
||||
stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3);
|
||||
stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3);
|
||||
} else {
|
||||
stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3);
|
||||
stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3);
|
||||
}
|
||||
void stl_write_neighbor(stl_file *stl, int facet)
|
||||
{
|
||||
printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet,
|
||||
stl->neighbors_start[facet].neighbor[0],
|
||||
stl->neighbors_start[facet].neighbor[1],
|
||||
stl->neighbors_start[facet].neighbor[2],
|
||||
stl->neighbors_start[facet].which_vertex_not[0],
|
||||
stl->neighbors_start[facet].which_vertex_not[1],
|
||||
stl->neighbors_start[facet].which_vertex_not[2]);
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_neighbor(stl_file *stl, int facet) {
|
||||
if (stl->error) return;
|
||||
printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet,
|
||||
stl->neighbors_start[facet].neighbor[0],
|
||||
stl->neighbors_start[facet].neighbor[1],
|
||||
stl->neighbors_start[facet].neighbor[2],
|
||||
stl->neighbors_start[facet].which_vertex_not[0],
|
||||
stl->neighbors_start[facet].which_vertex_not[1],
|
||||
stl->neighbors_start[facet].which_vertex_not[2]);
|
||||
}
|
||||
bool stl_write_quad_object(stl_file *stl, char *file)
|
||||
{
|
||||
stl_vertex connect_color = stl_vertex::Zero();
|
||||
stl_vertex uncon_1_color = stl_vertex::Zero();
|
||||
stl_vertex uncon_2_color = stl_vertex::Zero();
|
||||
stl_vertex uncon_3_color = stl_vertex::Zero();
|
||||
stl_vertex color;
|
||||
|
||||
void
|
||||
stl_write_quad_object(stl_file *stl, char *file) {
|
||||
FILE *fp;
|
||||
int i;
|
||||
int j;
|
||||
char *error_msg;
|
||||
stl_vertex connect_color = stl_vertex::Zero();
|
||||
stl_vertex uncon_1_color = stl_vertex::Zero();
|
||||
stl_vertex uncon_2_color = stl_vertex::Zero();
|
||||
stl_vertex uncon_3_color = stl_vertex::Zero();
|
||||
stl_vertex color;
|
||||
FILE *fp = boost::nowide::fopen(file, "w");
|
||||
if (fp == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = boost::nowide::fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_quad_object: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "CQUAD\n");
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
j = ((stl->neighbors_start[i].neighbor[0] == -1) +
|
||||
(stl->neighbors_start[i].neighbor[1] == -1) +
|
||||
(stl->neighbors_start[i].neighbor[2] == -1));
|
||||
if(j == 0) {
|
||||
color = connect_color;
|
||||
} else if(j == 1) {
|
||||
color = uncon_1_color;
|
||||
} else if(j == 2) {
|
||||
color = uncon_2_color;
|
||||
} else {
|
||||
color = uncon_3_color;
|
||||
}
|
||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
||||
stl->facet_start[i].vertex[0](0),
|
||||
stl->facet_start[i].vertex[0](1),
|
||||
stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
|
||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
||||
stl->facet_start[i].vertex[1](0),
|
||||
stl->facet_start[i].vertex[1](1),
|
||||
stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
|
||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
||||
stl->facet_start[i].vertex[2](0),
|
||||
stl->facet_start[i].vertex[2](1),
|
||||
stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
|
||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
||||
stl->facet_start[i].vertex[2](0),
|
||||
stl->facet_start[i].vertex[2](1),
|
||||
stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
|
||||
fprintf(fp, "CQUAD\n");
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
switch (stl->neighbors_start[i].num_neighbors_missing()) {
|
||||
case 0: color = connect_color; break;
|
||||
case 1: color = uncon_1_color; break;
|
||||
case 2: color = uncon_2_color; break;
|
||||
default: color = uncon_3_color;
|
||||
}
|
||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
|
||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
|
||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
|
||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_dxf(stl_file *stl, const char *file, char *label) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
char *error_msg;
|
||||
bool stl_write_dxf(stl_file *stl, const char *file, char *label)
|
||||
{
|
||||
FILE *fp = boost::nowide::fopen(file, "w");
|
||||
if (fp == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stl->error) return;
|
||||
fprintf(fp, "999\n%s\n", label);
|
||||
fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n");
|
||||
fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\
|
||||
0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n");
|
||||
fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n");
|
||||
|
||||
/* Open the file */
|
||||
fp = boost::nowide::fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
fprintf(fp, "0\nSECTION\n2\nENTITIES\n");
|
||||
|
||||
fprintf(fp, "999\n%s\n", label);
|
||||
fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n");
|
||||
fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\
|
||||
0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n");
|
||||
fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n");
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
fprintf(fp, "0\n3DFACE\n8\n0\n");
|
||||
fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2));
|
||||
fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2));
|
||||
fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
|
||||
fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
|
||||
}
|
||||
|
||||
fprintf(fp, "0\nSECTION\n2\nENTITIES\n");
|
||||
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
fprintf(fp, "0\n3DFACE\n8\n0\n");
|
||||
fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n",
|
||||
stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
|
||||
stl->facet_start[i].vertex[0](2));
|
||||
fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n",
|
||||
stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
|
||||
stl->facet_start[i].vertex[1](2));
|
||||
fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n",
|
||||
stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
|
||||
stl->facet_start[i].vertex[2](2));
|
||||
fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n",
|
||||
stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
|
||||
stl->facet_start[i].vertex[2](2));
|
||||
}
|
||||
|
||||
fprintf(fp, "0\nENDSEC\n0\nEOF\n");
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void
|
||||
stl_clear_error(stl_file *stl) {
|
||||
stl->error = 0;
|
||||
}
|
||||
|
||||
void
|
||||
stl_exit_on_error(stl_file *stl) {
|
||||
if (!stl->error) return;
|
||||
stl->error = 0;
|
||||
stl_close(stl);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
stl_get_error(stl_file *stl) {
|
||||
return stl->error;
|
||||
fprintf(fp, "0\nENDSEC\n0\nEOF\n");
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/detail/endian.hpp>
|
||||
|
||||
|
|
@ -35,351 +36,236 @@
|
|||
#error "SEEK_SET not defined"
|
||||
#endif
|
||||
|
||||
void
|
||||
stl_open(stl_file *stl, const char *file) {
|
||||
stl_initialize(stl);
|
||||
stl_count_facets(stl, file);
|
||||
stl_allocate(stl);
|
||||
stl_read(stl, 0, true);
|
||||
if (stl->fp != nullptr) {
|
||||
fclose(stl->fp);
|
||||
stl->fp = nullptr;
|
||||
}
|
||||
static FILE* stl_open_count_facets(stl_file *stl, const char *file)
|
||||
{
|
||||
// Open the file in binary mode first.
|
||||
FILE *fp = boost::nowide::fopen(file, "rb");
|
||||
if (fp == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading";
|
||||
return nullptr;
|
||||
}
|
||||
// Find size of file.
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long file_size = ftell(fp);
|
||||
|
||||
// Check for binary or ASCII file.
|
||||
fseek(fp, HEADER_SIZE, SEEK_SET);
|
||||
unsigned char chtest[128];
|
||||
if (! fread(chtest, sizeof(chtest), 1, fp)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The input is an empty file: " << file;
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
stl->stats.type = ascii;
|
||||
for (size_t s = 0; s < sizeof(chtest); s++) {
|
||||
if (chtest[s] > 127) {
|
||||
stl->stats.type = binary;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rewind(fp);
|
||||
|
||||
uint32_t num_facets = 0;
|
||||
|
||||
// Get the header and the number of facets in the .STL file.
|
||||
// If the .STL file is binary, then do the following:
|
||||
if (stl->stats.type == binary) {
|
||||
// Test if the STL file has the right size.
|
||||
if (((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0) || (file_size < STL_MIN_FILE_SIZE)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The file " << file << " has the wrong size.";
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
|
||||
|
||||
// Read the header.
|
||||
if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79)
|
||||
stl->stats.header[80] = '\0';
|
||||
|
||||
// Read the int following the header. This should contain # of facets.
|
||||
uint32_t header_num_facets;
|
||||
bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0;
|
||||
#ifndef BOOST_LITTLE_ENDIAN
|
||||
// Convert from little endian to big endian.
|
||||
stl_internal_reverse_quads((char*)&header_num_facets, 4);
|
||||
#endif /* BOOST_LITTLE_ENDIAN */
|
||||
if (! header_num_faces_read || num_facets != header_num_facets)
|
||||
BOOST_LOG_TRIVIAL(info) << "stl_open_count_facets: Warning: File size doesn't match number of facets in the header: " << file;
|
||||
}
|
||||
// Otherwise, if the .STL file is ASCII, then do the following:
|
||||
else
|
||||
{
|
||||
// Reopen the file in text mode (for getting correct newlines on Windows)
|
||||
// fix to silence a warning about unused return value.
|
||||
// obviously if it fails we have problems....
|
||||
fp = boost::nowide::freopen(file, "r", fp);
|
||||
|
||||
// do another null check to be safe
|
||||
if (fp == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading";
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Find the number of facets.
|
||||
char linebuf[100];
|
||||
int num_lines = 1;
|
||||
while (fgets(linebuf, 100, fp) != nullptr) {
|
||||
// Don't count short lines.
|
||||
if (strlen(linebuf) <= 4)
|
||||
continue;
|
||||
// Skip solid/endsolid lines as broken STL file generators may put several of them.
|
||||
if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0)
|
||||
continue;
|
||||
++ num_lines;
|
||||
}
|
||||
|
||||
rewind(fp);
|
||||
|
||||
// Get the header.
|
||||
int i = 0;
|
||||
for (; i < 80 && (stl->stats.header[i] = getc(fp)) != '\n'; ++ i) ;
|
||||
stl->stats.header[i] = '\0'; // Lose the '\n'
|
||||
stl->stats.header[80] = '\0';
|
||||
|
||||
num_facets = num_lines / ASCII_LINES_PER_FACET;
|
||||
}
|
||||
|
||||
stl->stats.number_of_facets += num_facets;
|
||||
stl->stats.original_num_facets = stl->stats.number_of_facets;
|
||||
return fp;
|
||||
}
|
||||
|
||||
void
|
||||
stl_initialize(stl_file *stl) {
|
||||
memset(stl, 0, sizeof(stl_file));
|
||||
stl->stats.volume = -1.0;
|
||||
/* Reads the contents of the file pointed to by fp into the stl structure,
|
||||
starting at facet first_facet. The second argument says if it's our first
|
||||
time running this for the stl and therefore we should reset our max and min stats. */
|
||||
static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first)
|
||||
{
|
||||
if (stl->stats.type == binary)
|
||||
fseek(fp, HEADER_SIZE, SEEK_SET);
|
||||
else
|
||||
rewind(fp);
|
||||
|
||||
char normal_buf[3][32];
|
||||
for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++ i) {
|
||||
stl_facet facet;
|
||||
|
||||
if (stl->stats.type == binary) {
|
||||
// Read a single facet from a binary .STL file. We assume little-endian architecture!
|
||||
if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET)
|
||||
return false;
|
||||
#ifndef BOOST_LITTLE_ENDIAN
|
||||
// Convert the loaded little endian data to big endian.
|
||||
stl_internal_reverse_quads((char*)&facet, 48);
|
||||
#endif /* BOOST_LITTLE_ENDIAN */
|
||||
} else {
|
||||
// Read a single facet from an ASCII .STL file
|
||||
// skip solid/endsolid
|
||||
// (in this order, otherwise it won't work when they are paired in the middle of a file)
|
||||
fscanf(fp, "endsolid%*[^\n]\n");
|
||||
fscanf(fp, "solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid")
|
||||
// Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs.
|
||||
int res_normal = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
|
||||
assert(res_normal == 3);
|
||||
int res_outer_loop = fscanf(fp, " outer loop");
|
||||
assert(res_outer_loop == 0);
|
||||
int res_vertex1 = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
|
||||
assert(res_vertex1 == 3);
|
||||
int res_vertex2 = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
|
||||
assert(res_vertex2 == 3);
|
||||
int res_vertex3 = fscanf(fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
|
||||
assert(res_vertex3 == 3);
|
||||
int res_endloop = fscanf(fp, " endloop");
|
||||
assert(res_endloop == 0);
|
||||
// There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines.
|
||||
int res_endfacet = fscanf(fp, " endfacet ");
|
||||
if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Something is syntactically very wrong with this ASCII STL! ";
|
||||
return false;
|
||||
}
|
||||
|
||||
// The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
|
||||
if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
|
||||
sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
|
||||
sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
|
||||
// Normal was mangled. Maybe denormals or "not a number" were stored?
|
||||
// Just reset the normal and silently ignore it.
|
||||
memset(&facet.normal, 0, sizeof(facet.normal));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Report close to zero vertex coordinates. Due to the nature of the floating point numbers,
|
||||
// close to zero values may be represented with singificantly higher precision than the rest of the vertices.
|
||||
// It may be worth to round these numbers to zero during loading to reduce the number of errors reported
|
||||
// during the STL import.
|
||||
for (size_t j = 0; j < 3; ++ j) {
|
||||
if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f)
|
||||
printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0));
|
||||
if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f)
|
||||
printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1));
|
||||
if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f)
|
||||
printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Write the facet into memory.
|
||||
stl->facet_start[i] = facet;
|
||||
stl_facet_stats(stl, facet, first);
|
||||
}
|
||||
|
||||
stl->stats.size = stl->stats.max - stl->stats.min;
|
||||
stl->stats.bounding_diameter = stl->stats.size.norm();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool stl_open(stl_file *stl, const char *file)
|
||||
{
|
||||
stl->clear();
|
||||
FILE *fp = stl_open_count_facets(stl, file);
|
||||
if (fp == nullptr)
|
||||
return false;
|
||||
stl_allocate(stl);
|
||||
bool result = stl_read(stl, fp, 0, true);
|
||||
fclose(fp);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef BOOST_LITTLE_ENDIAN
|
||||
extern void stl_internal_reverse_quads(char *buf, size_t cnt);
|
||||
#endif /* BOOST_LITTLE_ENDIAN */
|
||||
|
||||
void
|
||||
stl_count_facets(stl_file *stl, const char *file) {
|
||||
long file_size;
|
||||
uint32_t header_num_facets;
|
||||
uint32_t num_facets;
|
||||
int i;
|
||||
size_t s;
|
||||
unsigned char chtest[128];
|
||||
int num_lines = 1;
|
||||
char *error_msg;
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file in binary mode first */
|
||||
stl->fp = boost::nowide::fopen(file, "rb");
|
||||
if(stl->fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
/* Find size of file */
|
||||
fseek(stl->fp, 0, SEEK_END);
|
||||
file_size = ftell(stl->fp);
|
||||
|
||||
/* Check for binary or ASCII file */
|
||||
fseek(stl->fp, HEADER_SIZE, SEEK_SET);
|
||||
if (!fread(chtest, sizeof(chtest), 1, stl->fp)) {
|
||||
perror("The input is an empty file");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
stl->stats.type = ascii;
|
||||
for(s = 0; s < sizeof(chtest); s++) {
|
||||
if(chtest[s] > 127) {
|
||||
stl->stats.type = binary;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rewind(stl->fp);
|
||||
|
||||
/* Get the header and the number of facets in the .STL file */
|
||||
/* If the .STL file is binary, then do the following */
|
||||
if(stl->stats.type == binary) {
|
||||
/* Test if the STL file has the right size */
|
||||
if(((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0)
|
||||
|| (file_size < STL_MIN_FILE_SIZE)) {
|
||||
fprintf(stderr, "The file %s has the wrong size.\n", file);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
|
||||
|
||||
/* Read the header */
|
||||
if (fread(stl->stats.header, LABEL_SIZE, 1, stl->fp) > 79) {
|
||||
stl->stats.header[80] = '\0';
|
||||
}
|
||||
|
||||
/* Read the int following the header. This should contain # of facets */
|
||||
bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, stl->fp) != 0;
|
||||
#ifndef BOOST_LITTLE_ENDIAN
|
||||
// Convert from little endian to big endian.
|
||||
stl_internal_reverse_quads((char*)&header_num_facets, 4);
|
||||
#endif /* BOOST_LITTLE_ENDIAN */
|
||||
if (! header_num_faces_read || num_facets != header_num_facets) {
|
||||
fprintf(stderr,
|
||||
"Warning: File size doesn't match number of facets in the header\n");
|
||||
}
|
||||
}
|
||||
/* Otherwise, if the .STL file is ASCII, then do the following */
|
||||
else {
|
||||
/* Reopen the file in text mode (for getting correct newlines on Windows) */
|
||||
// fix to silence a warning about unused return value.
|
||||
// obviously if it fails we have problems....
|
||||
stl->fp = boost::nowide::freopen(file, "r", stl->fp);
|
||||
|
||||
// do another null check to be safe
|
||||
if(stl->fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find the number of facets */
|
||||
char linebuf[100];
|
||||
while (fgets(linebuf, 100, stl->fp) != NULL) {
|
||||
/* don't count short lines */
|
||||
if (strlen(linebuf) <= 4) continue;
|
||||
|
||||
/* skip solid/endsolid lines as broken STL file generators may put several of them */
|
||||
if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0) continue;
|
||||
|
||||
++num_lines;
|
||||
}
|
||||
|
||||
rewind(stl->fp);
|
||||
|
||||
/* Get the header */
|
||||
for(i = 0;
|
||||
(i < 80) && (stl->stats.header[i] = getc(stl->fp)) != '\n'; i++);
|
||||
stl->stats.header[i] = '\0'; /* Lose the '\n' */
|
||||
stl->stats.header[80] = '\0';
|
||||
|
||||
num_facets = num_lines / ASCII_LINES_PER_FACET;
|
||||
}
|
||||
stl->stats.number_of_facets += num_facets;
|
||||
stl->stats.original_num_facets = stl->stats.number_of_facets;
|
||||
void stl_allocate(stl_file *stl)
|
||||
{
|
||||
// Allocate memory for the entire .STL file.
|
||||
stl->facet_start.assign(stl->stats.number_of_facets, stl_facet());
|
||||
// Allocate memory for the neighbors list.
|
||||
stl->neighbors_start.assign(stl->stats.number_of_facets, stl_neighbors());
|
||||
}
|
||||
|
||||
void
|
||||
stl_allocate(stl_file *stl) {
|
||||
if (stl->error) return;
|
||||
|
||||
/* Allocate memory for the entire .STL file */
|
||||
stl->facet_start = (stl_facet*)calloc(stl->stats.number_of_facets,
|
||||
sizeof(stl_facet));
|
||||
if(stl->facet_start == NULL) perror("stl_initialize");
|
||||
stl->stats.facets_malloced = stl->stats.number_of_facets;
|
||||
|
||||
/* Allocate memory for the neighbors list */
|
||||
stl->neighbors_start = (stl_neighbors*)
|
||||
calloc(stl->stats.number_of_facets, sizeof(stl_neighbors));
|
||||
if(stl->facet_start == NULL) perror("stl_initialize");
|
||||
}
|
||||
|
||||
void
|
||||
stl_open_merge(stl_file *stl, char *file_to_merge) {
|
||||
int num_facets_so_far;
|
||||
stl_type origStlType;
|
||||
FILE *origFp;
|
||||
stl_file stl_to_merge;
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
/* Record how many facets we have so far from the first file. We will start putting
|
||||
facets in the next position. Since we're 0-indexed, it'l be the same position. */
|
||||
num_facets_so_far = stl->stats.number_of_facets;
|
||||
|
||||
/* Record the file type we started with: */
|
||||
origStlType=stl->stats.type;
|
||||
/* Record the file pointer too: */
|
||||
origFp=stl->fp;
|
||||
|
||||
/* Initialize the sturucture with zero stats, header info and sizes: */
|
||||
stl_initialize(&stl_to_merge);
|
||||
stl_count_facets(&stl_to_merge, file_to_merge);
|
||||
|
||||
/* Copy what we need to into stl so that we can read the file_to_merge directly into it
|
||||
using stl_read: Save the rest of the valuable info: */
|
||||
stl->stats.type=stl_to_merge.stats.type;
|
||||
stl->fp=stl_to_merge.fp;
|
||||
|
||||
/* Add the number of facets we already have in stl with what we we found in stl_to_merge but
|
||||
haven't read yet. */
|
||||
stl->stats.number_of_facets=num_facets_so_far+stl_to_merge.stats.number_of_facets;
|
||||
|
||||
/* Allocate enough room for stl->stats.number_of_facets facets and neighbors: */
|
||||
stl_reallocate(stl);
|
||||
|
||||
/* Read the file to merge directly into stl, adding it to what we have already.
|
||||
Start at num_facets_so_far, the index to the first unused facet. Also say
|
||||
that this isn't our first time so we should augment stats like min and max
|
||||
instead of erasing them. */
|
||||
stl_read(stl, num_facets_so_far, false);
|
||||
|
||||
/* Restore the stl information we overwrote (for stl_read) so that it still accurately
|
||||
reflects the subject part: */
|
||||
stl->stats.type=origStlType;
|
||||
stl->fp=origFp;
|
||||
}
|
||||
|
||||
extern void
|
||||
stl_reallocate(stl_file *stl) {
|
||||
if (stl->error) return;
|
||||
/* Reallocate more memory for the .STL file(s) */
|
||||
stl->facet_start = (stl_facet*)realloc(stl->facet_start, stl->stats.number_of_facets *
|
||||
sizeof(stl_facet));
|
||||
if(stl->facet_start == NULL) perror("stl_initialize");
|
||||
stl->stats.facets_malloced = stl->stats.number_of_facets;
|
||||
|
||||
/* Reallocate more memory for the neighbors list */
|
||||
stl->neighbors_start = (stl_neighbors*)
|
||||
realloc(stl->neighbors_start, stl->stats.number_of_facets *
|
||||
sizeof(stl_neighbors));
|
||||
if(stl->facet_start == NULL) perror("stl_initialize");
|
||||
}
|
||||
|
||||
|
||||
/* Reads the contents of the file pointed to by stl->fp into the stl structure,
|
||||
starting at facet first_facet. The second argument says if it's our first
|
||||
time running this for the stl and therefore we should reset our max and min stats. */
|
||||
void stl_read(stl_file *stl, int first_facet, bool first) {
|
||||
stl_facet facet;
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
if(stl->stats.type == binary) {
|
||||
fseek(stl->fp, HEADER_SIZE, SEEK_SET);
|
||||
} else {
|
||||
rewind(stl->fp);
|
||||
}
|
||||
|
||||
char normal_buf[3][32];
|
||||
for(uint32_t i = first_facet; i < stl->stats.number_of_facets; i++) {
|
||||
if(stl->stats.type == binary)
|
||||
/* Read a single facet from a binary .STL file */
|
||||
{
|
||||
/* we assume little-endian architecture! */
|
||||
if (fread(&facet, 1, SIZEOF_STL_FACET, stl->fp) != SIZEOF_STL_FACET) {
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
#ifndef BOOST_LITTLE_ENDIAN
|
||||
// Convert the loaded little endian data to big endian.
|
||||
stl_internal_reverse_quads((char*)&facet, 48);
|
||||
#endif /* BOOST_LITTLE_ENDIAN */
|
||||
} else
|
||||
/* Read a single facet from an ASCII .STL file */
|
||||
{
|
||||
// skip solid/endsolid
|
||||
// (in this order, otherwise it won't work when they are paired in the middle of a file)
|
||||
fscanf(stl->fp, "endsolid%*[^\n]\n");
|
||||
fscanf(stl->fp, "solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid")
|
||||
// Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs.
|
||||
int res_normal = fscanf(stl->fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
|
||||
assert(res_normal == 3);
|
||||
int res_outer_loop = fscanf(stl->fp, " outer loop");
|
||||
assert(res_outer_loop == 0);
|
||||
int res_vertex1 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
|
||||
assert(res_vertex1 == 3);
|
||||
int res_vertex2 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
|
||||
assert(res_vertex2 == 3);
|
||||
int res_vertex3 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
|
||||
assert(res_vertex3 == 3);
|
||||
int res_endloop = fscanf(stl->fp, " endloop");
|
||||
assert(res_endloop == 0);
|
||||
// There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines.
|
||||
int res_endfacet = fscanf(stl->fp, " endfacet ");
|
||||
if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
|
||||
perror("Something is syntactically very wrong with this ASCII STL!");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
|
||||
if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
|
||||
sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
|
||||
sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
|
||||
// Normal was mangled. Maybe denormals or "not a number" were stored?
|
||||
// Just reset the normal and silently ignore it.
|
||||
memset(&facet.normal, 0, sizeof(facet.normal));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Report close to zero vertex coordinates. Due to the nature of the floating point numbers,
|
||||
// close to zero values may be represented with singificantly higher precision than the rest of the vertices.
|
||||
// It may be worth to round these numbers to zero during loading to reduce the number of errors reported
|
||||
// during the STL import.
|
||||
for (size_t j = 0; j < 3; ++ j) {
|
||||
if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f)
|
||||
printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0));
|
||||
if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f)
|
||||
printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1));
|
||||
if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f)
|
||||
printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Write the facet into memory. */
|
||||
stl->facet_start[i] = facet;
|
||||
stl_facet_stats(stl, facet, first);
|
||||
}
|
||||
stl->stats.size = stl->stats.max - stl->stats.min;
|
||||
stl->stats.bounding_diameter = stl->stats.size.norm();
|
||||
void stl_reallocate(stl_file *stl)
|
||||
{
|
||||
stl->facet_start.resize(stl->stats.number_of_facets);
|
||||
stl->neighbors_start.resize(stl->stats.number_of_facets);
|
||||
}
|
||||
|
||||
void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
// While we are going through all of the facets, let's find the
|
||||
// maximum and minimum values for x, y, and z
|
||||
|
||||
// While we are going through all of the facets, let's find the
|
||||
// maximum and minimum values for x, y, and z
|
||||
if (first) {
|
||||
// Initialize the max and min values the first time through
|
||||
stl->stats.min = facet.vertex[0];
|
||||
stl->stats.max = facet.vertex[0];
|
||||
stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs();
|
||||
stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2)));
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
// Initialize the max and min values the first time through
|
||||
stl->stats.min = facet.vertex[0];
|
||||
stl->stats.max = facet.vertex[0];
|
||||
stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs();
|
||||
stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2)));
|
||||
first = false;
|
||||
}
|
||||
|
||||
// Now find the max and min values.
|
||||
for (size_t i = 0; i < 3; ++ i) {
|
||||
stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]);
|
||||
stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void stl_close(stl_file *stl)
|
||||
{
|
||||
assert(stl->fp == nullptr);
|
||||
assert(stl->heads == nullptr);
|
||||
assert(stl->tail == nullptr);
|
||||
|
||||
if (stl->facet_start != NULL)
|
||||
free(stl->facet_start);
|
||||
if (stl->neighbors_start != NULL)
|
||||
free(stl->neighbors_start);
|
||||
if (stl->v_indices != NULL)
|
||||
free(stl->v_indices);
|
||||
if (stl->v_shared != NULL)
|
||||
free(stl->v_shared);
|
||||
memset(stl, 0, sizeof(stl_file));
|
||||
// Now find the max and min values.
|
||||
for (size_t i = 0; i < 3; ++ i) {
|
||||
stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]);
|
||||
stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,435 +25,375 @@
|
|||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include "stl.h"
|
||||
|
||||
static void stl_rotate(float *x, float *y, const double c, const double s);
|
||||
static float get_area(stl_facet *facet);
|
||||
static float get_volume(stl_file *stl);
|
||||
void stl_verify_neighbors(stl_file *stl)
|
||||
{
|
||||
stl->stats.backwards_edges = 0;
|
||||
|
||||
|
||||
void
|
||||
stl_verify_neighbors(stl_file *stl) {
|
||||
int i;
|
||||
int j;
|
||||
stl_edge edge_a;
|
||||
stl_edge edge_b;
|
||||
int neighbor;
|
||||
int vnot;
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
stl->stats.backwards_edges = 0;
|
||||
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
for(j = 0; j < 3; j++) {
|
||||
edge_a.p1 = stl->facet_start[i].vertex[j];
|
||||
edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3];
|
||||
neighbor = stl->neighbors_start[i].neighbor[j];
|
||||
vnot = stl->neighbors_start[i].which_vertex_not[j];
|
||||
|
||||
if(neighbor == -1)
|
||||
continue; /* this edge has no neighbor... Continue. */
|
||||
if(vnot < 3) {
|
||||
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
|
||||
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
|
||||
} else {
|
||||
stl->stats.backwards_edges += 1;
|
||||
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
|
||||
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
|
||||
}
|
||||
if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) {
|
||||
/* These edges should match but they don't. Print results. */
|
||||
printf("edge %d of facet %d doesn't match edge %d of facet %d\n",
|
||||
j, i, vnot + 1, neighbor);
|
||||
stl_write_facet(stl, (char*)"first facet", i);
|
||||
stl_write_facet(stl, (char*)"second facet", neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
for (int j = 0; j < 3; ++ j) {
|
||||
struct stl_edge {
|
||||
stl_vertex p1;
|
||||
stl_vertex p2;
|
||||
int facet_number;
|
||||
};
|
||||
stl_edge edge_a;
|
||||
edge_a.p1 = stl->facet_start[i].vertex[j];
|
||||
edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3];
|
||||
int neighbor = stl->neighbors_start[i].neighbor[j];
|
||||
if (neighbor == -1)
|
||||
continue; // this edge has no neighbor... Continue.
|
||||
int vnot = stl->neighbors_start[i].which_vertex_not[j];
|
||||
stl_edge edge_b;
|
||||
if (vnot < 3) {
|
||||
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
|
||||
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
|
||||
} else {
|
||||
stl->stats.backwards_edges += 1;
|
||||
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
|
||||
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
|
||||
}
|
||||
if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) {
|
||||
// These edges should match but they don't. Print results.
|
||||
BOOST_LOG_TRIVIAL(info) << "edge " << j << " of facet " << i << " doesn't match edge " << (vnot + 1) << " of facet " << neighbor;
|
||||
stl_write_facet(stl, (char*)"first facet", i);
|
||||
stl_write_facet(stl, (char*)"second facet", neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stl_translate(stl_file *stl, float x, float y, float z)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
|
||||
stl_vertex new_min(x, y, z);
|
||||
stl_vertex shift = new_min - stl->stats.min;
|
||||
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
stl->facet_start[i].vertex[j] += shift;
|
||||
stl->stats.min = new_min;
|
||||
stl->stats.max += shift;
|
||||
stl_invalidate_shared_vertices(stl);
|
||||
stl_vertex new_min(x, y, z);
|
||||
stl_vertex shift = new_min - stl->stats.min;
|
||||
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
stl->facet_start[i].vertex[j] += shift;
|
||||
stl->stats.min = new_min;
|
||||
stl->stats.max += shift;
|
||||
}
|
||||
|
||||
/* Translates the stl by x,y,z, relatively from wherever it is currently */
|
||||
void stl_translate_relative(stl_file *stl, float x, float y, float z)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
|
||||
stl_vertex shift(x, y, z);
|
||||
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
stl->facet_start[i].vertex[j] += shift;
|
||||
stl->stats.min += shift;
|
||||
stl->stats.max += shift;
|
||||
stl_invalidate_shared_vertices(stl);
|
||||
stl_vertex shift(x, y, z);
|
||||
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
stl->facet_start[i].vertex[j] += shift;
|
||||
stl->stats.min += shift;
|
||||
stl->stats.max += shift;
|
||||
}
|
||||
|
||||
void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
|
||||
// Scale extents.
|
||||
auto s = versor.array();
|
||||
stl->stats.min.array() *= s;
|
||||
stl->stats.max.array() *= s;
|
||||
// Scale size.
|
||||
stl->stats.size.array() *= s;
|
||||
// Scale volume.
|
||||
if (stl->stats.volume > 0.0)
|
||||
stl->stats.volume *= versor(0) * versor(1) * versor(2);
|
||||
// Scale the mesh.
|
||||
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
stl->facet_start[i].vertex[j].array() *= s;
|
||||
stl_invalidate_shared_vertices(stl);
|
||||
// Scale extents.
|
||||
auto s = versor.array();
|
||||
stl->stats.min.array() *= s;
|
||||
stl->stats.max.array() *= s;
|
||||
// Scale size.
|
||||
stl->stats.size.array() *= s;
|
||||
// Scale volume.
|
||||
if (stl->stats.volume > 0.0)
|
||||
stl->stats.volume *= versor(0) * versor(1) * versor(2);
|
||||
// Scale the mesh.
|
||||
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
stl->facet_start[i].vertex[j].array() *= s;
|
||||
}
|
||||
|
||||
static void calculate_normals(stl_file *stl)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
|
||||
stl_normal normal;
|
||||
for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
stl_calculate_normal(normal, &stl->facet_start[i]);
|
||||
stl_normalize_vector(normal);
|
||||
stl->facet_start[i].normal = normal;
|
||||
}
|
||||
stl_normal normal;
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
stl_calculate_normal(normal, &stl->facet_start[i]);
|
||||
stl_normalize_vector(normal);
|
||||
stl->facet_start[i].normal = normal;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
stl_rotate_x(stl_file *stl, float angle) {
|
||||
int i;
|
||||
int j;
|
||||
double radian_angle = (angle / 180.0) * M_PI;
|
||||
double c = cos(radian_angle);
|
||||
double s = sin(radian_angle);
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
for(j = 0; j < 3; j++) {
|
||||
stl_rotate(&stl->facet_start[i].vertex[j](1),
|
||||
&stl->facet_start[i].vertex[j](2), c, s);
|
||||
}
|
||||
}
|
||||
stl_get_size(stl);
|
||||
calculate_normals(stl);
|
||||
static inline void rotate_point_2d(float &x, float &y, const double c, const double s)
|
||||
{
|
||||
double xold = x;
|
||||
double yold = y;
|
||||
x = float(c * xold - s * yold);
|
||||
y = float(s * xold + c * yold);
|
||||
}
|
||||
|
||||
void
|
||||
stl_rotate_y(stl_file *stl, float angle) {
|
||||
int i;
|
||||
int j;
|
||||
double radian_angle = (angle / 180.0) * M_PI;
|
||||
double c = cos(radian_angle);
|
||||
double s = sin(radian_angle);
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
for(j = 0; j < 3; j++) {
|
||||
stl_rotate(&stl->facet_start[i].vertex[j](2),
|
||||
&stl->facet_start[i].vertex[j](0), c, s);
|
||||
}
|
||||
}
|
||||
stl_get_size(stl);
|
||||
calculate_normals(stl);
|
||||
void stl_rotate_x(stl_file *stl, float angle)
|
||||
{
|
||||
double radian_angle = (angle / 180.0) * M_PI;
|
||||
double c = cos(radian_angle);
|
||||
double s = sin(radian_angle);
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
rotate_point_2d(stl->facet_start[i].vertex[j](1), stl->facet_start[i].vertex[j](2), c, s);
|
||||
stl_get_size(stl);
|
||||
calculate_normals(stl);
|
||||
}
|
||||
|
||||
void
|
||||
stl_rotate_z(stl_file *stl, float angle) {
|
||||
int i;
|
||||
int j;
|
||||
double radian_angle = (angle / 180.0) * M_PI;
|
||||
double c = cos(radian_angle);
|
||||
double s = sin(radian_angle);
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
for(j = 0; j < 3; j++) {
|
||||
stl_rotate(&stl->facet_start[i].vertex[j](0),
|
||||
&stl->facet_start[i].vertex[j](1), c, s);
|
||||
}
|
||||
}
|
||||
stl_get_size(stl);
|
||||
calculate_normals(stl);
|
||||
void stl_rotate_y(stl_file *stl, float angle)
|
||||
{
|
||||
double radian_angle = (angle / 180.0) * M_PI;
|
||||
double c = cos(radian_angle);
|
||||
double s = sin(radian_angle);
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
rotate_point_2d(stl->facet_start[i].vertex[j](2), stl->facet_start[i].vertex[j](0), c, s);
|
||||
stl_get_size(stl);
|
||||
calculate_normals(stl);
|
||||
}
|
||||
|
||||
void stl_rotate_z(stl_file *stl, float angle)
|
||||
{
|
||||
double radian_angle = (angle / 180.0) * M_PI;
|
||||
double c = cos(radian_angle);
|
||||
double s = sin(radian_angle);
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
rotate_point_2d(stl->facet_start[i].vertex[j](0), stl->facet_start[i].vertex[j](1), c, s);
|
||||
stl_get_size(stl);
|
||||
calculate_normals(stl);
|
||||
}
|
||||
|
||||
void its_rotate_x(indexed_triangle_set &its, float angle)
|
||||
{
|
||||
double radian_angle = (angle / 180.0) * M_PI;
|
||||
double c = cos(radian_angle);
|
||||
double s = sin(radian_angle);
|
||||
for (stl_vertex &v : its.vertices)
|
||||
rotate_point_2d(v(1), v(2), c, s);
|
||||
}
|
||||
|
||||
static void
|
||||
stl_rotate(float *x, float *y, const double c, const double s) {
|
||||
double xold = *x;
|
||||
double yold = *y;
|
||||
*x = float(c * xold - s * yold);
|
||||
*y = float(s * xold + c * yold);
|
||||
void its_rotate_y(indexed_triangle_set& its, float angle)
|
||||
{
|
||||
double radian_angle = (angle / 180.0) * M_PI;
|
||||
double c = cos(radian_angle);
|
||||
double s = sin(radian_angle);
|
||||
for (stl_vertex& v : its.vertices)
|
||||
rotate_point_2d(v(2), v(0), c, s);
|
||||
}
|
||||
|
||||
void its_rotate_z(indexed_triangle_set& its, float angle)
|
||||
{
|
||||
double radian_angle = (angle / 180.0) * M_PI;
|
||||
double c = cos(radian_angle);
|
||||
double s = sin(radian_angle);
|
||||
for (stl_vertex& v : its.vertices)
|
||||
rotate_point_2d(v(0), v(1), c, s);
|
||||
}
|
||||
|
||||
void stl_get_size(stl_file *stl)
|
||||
{
|
||||
if (stl->error || stl->stats.number_of_facets == 0)
|
||||
return;
|
||||
stl->stats.min = stl->facet_start[0].vertex[0];
|
||||
stl->stats.max = stl->stats.min;
|
||||
for (int i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
const stl_facet &face = stl->facet_start[i];
|
||||
for (int j = 0; j < 3; ++ j) {
|
||||
stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]);
|
||||
stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]);
|
||||
}
|
||||
}
|
||||
stl->stats.size = stl->stats.max - stl->stats.min;
|
||||
stl->stats.bounding_diameter = stl->stats.size.norm();
|
||||
if (stl->stats.number_of_facets == 0)
|
||||
return;
|
||||
stl->stats.min = stl->facet_start[0].vertex[0];
|
||||
stl->stats.max = stl->stats.min;
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
const stl_facet &face = stl->facet_start[i];
|
||||
for (int j = 0; j < 3; ++ j) {
|
||||
stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]);
|
||||
stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]);
|
||||
}
|
||||
}
|
||||
stl->stats.size = stl->stats.max - stl->stats.min;
|
||||
stl->stats.bounding_diameter = stl->stats.size.norm();
|
||||
}
|
||||
|
||||
void stl_mirror_xy(stl_file *stl)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
|
||||
for(int i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
for(int j = 0; j < 3; j++) {
|
||||
stl->facet_start[i].vertex[j](2) *= -1.0;
|
||||
}
|
||||
}
|
||||
float temp_size = stl->stats.min(2);
|
||||
stl->stats.min(2) = stl->stats.max(2);
|
||||
stl->stats.max(2) = temp_size;
|
||||
stl->stats.min(2) *= -1.0;
|
||||
stl->stats.max(2) *= -1.0;
|
||||
stl_reverse_all_facets(stl);
|
||||
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
stl->facet_start[i].vertex[j](2) *= -1.0;
|
||||
float temp_size = stl->stats.min(2);
|
||||
stl->stats.min(2) = stl->stats.max(2);
|
||||
stl->stats.max(2) = temp_size;
|
||||
stl->stats.min(2) *= -1.0;
|
||||
stl->stats.max(2) *= -1.0;
|
||||
stl_reverse_all_facets(stl);
|
||||
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
||||
}
|
||||
|
||||
void stl_mirror_yz(stl_file *stl)
|
||||
{
|
||||
if (stl->error) return;
|
||||
|
||||
for (int i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
stl->facet_start[i].vertex[j](0) *= -1.0;
|
||||
}
|
||||
}
|
||||
float temp_size = stl->stats.min(0);
|
||||
stl->stats.min(0) = stl->stats.max(0);
|
||||
stl->stats.max(0) = temp_size;
|
||||
stl->stats.min(0) *= -1.0;
|
||||
stl->stats.max(0) *= -1.0;
|
||||
stl_reverse_all_facets(stl);
|
||||
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; j++)
|
||||
stl->facet_start[i].vertex[j](0) *= -1.0;
|
||||
float temp_size = stl->stats.min(0);
|
||||
stl->stats.min(0) = stl->stats.max(0);
|
||||
stl->stats.max(0) = temp_size;
|
||||
stl->stats.min(0) *= -1.0;
|
||||
stl->stats.max(0) *= -1.0;
|
||||
stl_reverse_all_facets(stl);
|
||||
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
||||
}
|
||||
|
||||
void stl_mirror_xz(stl_file *stl)
|
||||
{
|
||||
if (stl->error)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < stl->stats.number_of_facets; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
stl->facet_start[i].vertex[j](1) *= -1.0;
|
||||
}
|
||||
}
|
||||
float temp_size = stl->stats.min(1);
|
||||
stl->stats.min(1) = stl->stats.max(1);
|
||||
stl->stats.max(1) = temp_size;
|
||||
stl->stats.min(1) *= -1.0;
|
||||
stl->stats.max(1) *= -1.0;
|
||||
stl_reverse_all_facets(stl);
|
||||
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
||||
}
|
||||
|
||||
static float get_volume(stl_file *stl)
|
||||
{
|
||||
if (stl->error)
|
||||
return 0;
|
||||
|
||||
// Choose a point, any point as the reference.
|
||||
stl_vertex p0 = stl->facet_start[0].vertex[0];
|
||||
float volume = 0.f;
|
||||
for(uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
// Do dot product to get distance from point to plane.
|
||||
float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0);
|
||||
float area = get_area(&stl->facet_start[i]);
|
||||
volume += (area * height) / 3.0f;
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
|
||||
void stl_calculate_volume(stl_file *stl)
|
||||
{
|
||||
if (stl->error) return;
|
||||
stl->stats.volume = get_volume(stl);
|
||||
if(stl->stats.volume < 0.0) {
|
||||
stl_reverse_all_facets(stl);
|
||||
stl->stats.volume = -stl->stats.volume;
|
||||
}
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||
for (int j = 0; j < 3; ++ j)
|
||||
stl->facet_start[i].vertex[j](1) *= -1.0;
|
||||
float temp_size = stl->stats.min(1);
|
||||
stl->stats.min(1) = stl->stats.max(1);
|
||||
stl->stats.max(1) = temp_size;
|
||||
stl->stats.min(1) *= -1.0;
|
||||
stl->stats.max(1) *= -1.0;
|
||||
stl_reverse_all_facets(stl);
|
||||
stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats
|
||||
}
|
||||
|
||||
static float get_area(stl_facet *facet)
|
||||
{
|
||||
/* cast to double before calculating cross product because large coordinates
|
||||
can result in overflowing product
|
||||
(bad area is responsible for bad volume and bad facets reversal) */
|
||||
double cross[3][3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) -
|
||||
((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1)));
|
||||
cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) -
|
||||
((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2)));
|
||||
cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) -
|
||||
((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0)));
|
||||
}
|
||||
/* cast to double before calculating cross product because large coordinates
|
||||
can result in overflowing product
|
||||
(bad area is responsible for bad volume and bad facets reversal) */
|
||||
double cross[3][3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) -
|
||||
((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1)));
|
||||
cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) -
|
||||
((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2)));
|
||||
cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) -
|
||||
((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0)));
|
||||
}
|
||||
|
||||
stl_normal sum;
|
||||
sum(0) = cross[0][0] + cross[1][0] + cross[2][0];
|
||||
sum(1) = cross[0][1] + cross[1][1] + cross[2][1];
|
||||
sum(2) = cross[0][2] + cross[1][2] + cross[2][2];
|
||||
stl_normal sum;
|
||||
sum(0) = cross[0][0] + cross[1][0] + cross[2][0];
|
||||
sum(1) = cross[0][1] + cross[1][1] + cross[2][1];
|
||||
sum(2) = cross[0][2] + cross[1][2] + cross[2][2];
|
||||
|
||||
// This should already be done. But just in case, let's do it again.
|
||||
//FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy.
|
||||
stl_normal n;
|
||||
stl_calculate_normal(n, facet);
|
||||
stl_normalize_vector(n);
|
||||
return 0.5f * n.dot(sum);
|
||||
// This should already be done. But just in case, let's do it again.
|
||||
//FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy.
|
||||
stl_normal n;
|
||||
stl_calculate_normal(n, facet);
|
||||
stl_normalize_vector(n);
|
||||
return 0.5f * n.dot(sum);
|
||||
}
|
||||
|
||||
void stl_repair(stl_file *stl,
|
||||
int fixall_flag,
|
||||
int exact_flag,
|
||||
int tolerance_flag,
|
||||
float tolerance,
|
||||
int increment_flag,
|
||||
float increment,
|
||||
int nearby_flag,
|
||||
int iterations,
|
||||
int remove_unconnected_flag,
|
||||
int fill_holes_flag,
|
||||
int normal_directions_flag,
|
||||
int normal_values_flag,
|
||||
int reverse_all_flag,
|
||||
int verbose_flag) {
|
||||
|
||||
int i;
|
||||
int last_edges_fixed = 0;
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
if(exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag
|
||||
|| fill_holes_flag || normal_directions_flag) {
|
||||
if (verbose_flag)
|
||||
printf("Checking exact...\n");
|
||||
exact_flag = 1;
|
||||
stl_check_facets_exact(stl);
|
||||
stl->stats.facets_w_1_bad_edge =
|
||||
(stl->stats.connected_facets_2_edge -
|
||||
stl->stats.connected_facets_3_edge);
|
||||
stl->stats.facets_w_2_bad_edge =
|
||||
(stl->stats.connected_facets_1_edge -
|
||||
stl->stats.connected_facets_2_edge);
|
||||
stl->stats.facets_w_3_bad_edge =
|
||||
(stl->stats.number_of_facets -
|
||||
stl->stats.connected_facets_1_edge);
|
||||
}
|
||||
|
||||
if(nearby_flag || fixall_flag) {
|
||||
if(!tolerance_flag) {
|
||||
tolerance = stl->stats.shortest_edge;
|
||||
}
|
||||
if(!increment_flag) {
|
||||
increment = stl->stats.bounding_diameter / 10000.0;
|
||||
}
|
||||
|
||||
if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
|
||||
for(i = 0; i < iterations; i++) {
|
||||
if(stl->stats.connected_facets_3_edge <
|
||||
stl->stats.number_of_facets) {
|
||||
if (verbose_flag)
|
||||
printf("\
|
||||
Checking nearby. Tolerance= %f Iteration=%d of %d...",
|
||||
tolerance, i + 1, iterations);
|
||||
stl_check_facets_nearby(stl, tolerance);
|
||||
if (verbose_flag)
|
||||
printf(" Fixed %d edges.\n",
|
||||
stl->stats.edges_fixed - last_edges_fixed);
|
||||
last_edges_fixed = stl->stats.edges_fixed;
|
||||
tolerance += increment;
|
||||
} else {
|
||||
if (verbose_flag)
|
||||
printf("\
|
||||
All facets connected. No further nearby check necessary.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (verbose_flag)
|
||||
printf("All facets connected. No nearby check necessary.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(remove_unconnected_flag || fixall_flag || fill_holes_flag) {
|
||||
if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
|
||||
if (verbose_flag)
|
||||
printf("Removing unconnected facets...\n");
|
||||
stl_remove_unconnected_facets(stl);
|
||||
} else
|
||||
if (verbose_flag)
|
||||
printf("No unconnected need to be removed.\n");
|
||||
}
|
||||
|
||||
if(fill_holes_flag || fixall_flag) {
|
||||
if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
|
||||
if (verbose_flag)
|
||||
printf("Filling holes...\n");
|
||||
stl_fill_holes(stl);
|
||||
} else
|
||||
if (verbose_flag)
|
||||
printf("No holes need to be filled.\n");
|
||||
}
|
||||
|
||||
if(reverse_all_flag) {
|
||||
if (verbose_flag)
|
||||
printf("Reversing all facets...\n");
|
||||
stl_reverse_all_facets(stl);
|
||||
}
|
||||
|
||||
if(normal_directions_flag || fixall_flag) {
|
||||
if (verbose_flag)
|
||||
printf("Checking normal directions...\n");
|
||||
stl_fix_normal_directions(stl);
|
||||
}
|
||||
|
||||
if(normal_values_flag || fixall_flag) {
|
||||
if (verbose_flag)
|
||||
printf("Checking normal values...\n");
|
||||
stl_fix_normal_values(stl);
|
||||
}
|
||||
|
||||
/* Always calculate the volume. It shouldn't take too long */
|
||||
if (verbose_flag)
|
||||
printf("Calculating volume...\n");
|
||||
stl_calculate_volume(stl);
|
||||
|
||||
if(exact_flag) {
|
||||
if (verbose_flag)
|
||||
printf("Verifying neighbors...\n");
|
||||
stl_verify_neighbors(stl);
|
||||
}
|
||||
static float get_volume(stl_file *stl)
|
||||
{
|
||||
// Choose a point, any point as the reference.
|
||||
stl_vertex p0 = stl->facet_start[0].vertex[0];
|
||||
float volume = 0.f;
|
||||
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||
// Do dot product to get distance from point to plane.
|
||||
float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0);
|
||||
float area = get_area(&stl->facet_start[i]);
|
||||
volume += (area * height) / 3.0f;
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
|
||||
void stl_calculate_volume(stl_file *stl)
|
||||
{
|
||||
stl->stats.volume = get_volume(stl);
|
||||
if (stl->stats.volume < 0.0) {
|
||||
stl_reverse_all_facets(stl);
|
||||
stl->stats.volume = -stl->stats.volume;
|
||||
}
|
||||
}
|
||||
|
||||
void stl_repair(
|
||||
stl_file *stl,
|
||||
bool fixall_flag,
|
||||
bool exact_flag,
|
||||
bool tolerance_flag,
|
||||
float tolerance,
|
||||
bool increment_flag,
|
||||
float increment,
|
||||
bool nearby_flag,
|
||||
int iterations,
|
||||
bool remove_unconnected_flag,
|
||||
bool fill_holes_flag,
|
||||
bool normal_directions_flag,
|
||||
bool normal_values_flag,
|
||||
bool reverse_all_flag,
|
||||
bool verbose_flag)
|
||||
{
|
||||
if (exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag || fill_holes_flag || normal_directions_flag) {
|
||||
if (verbose_flag)
|
||||
printf("Checking exact...\n");
|
||||
exact_flag = true;
|
||||
stl_check_facets_exact(stl);
|
||||
stl->stats.facets_w_1_bad_edge = (stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge);
|
||||
stl->stats.facets_w_2_bad_edge = (stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge);
|
||||
stl->stats.facets_w_3_bad_edge = (stl->stats.number_of_facets - stl->stats.connected_facets_1_edge);
|
||||
}
|
||||
|
||||
if (nearby_flag || fixall_flag) {
|
||||
if (! tolerance_flag)
|
||||
tolerance = stl->stats.shortest_edge;
|
||||
if (! increment_flag)
|
||||
increment = stl->stats.bounding_diameter / 10000.0;
|
||||
}
|
||||
|
||||
if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
|
||||
int last_edges_fixed = 0;
|
||||
for (int i = 0; i < iterations; ++ i) {
|
||||
if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
|
||||
if (verbose_flag)
|
||||
printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations);
|
||||
stl_check_facets_nearby(stl, tolerance);
|
||||
if (verbose_flag)
|
||||
printf(" Fixed %d edges.\n", stl->stats.edges_fixed - last_edges_fixed);
|
||||
last_edges_fixed = stl->stats.edges_fixed;
|
||||
tolerance += increment;
|
||||
} else {
|
||||
if (verbose_flag)
|
||||
printf("All facets connected. No further nearby check necessary.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (verbose_flag)
|
||||
printf("All facets connected. No nearby check necessary.\n");
|
||||
|
||||
if (remove_unconnected_flag || fixall_flag || fill_holes_flag) {
|
||||
if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
|
||||
if (verbose_flag)
|
||||
printf("Removing unconnected facets...\n");
|
||||
stl_remove_unconnected_facets(stl);
|
||||
} else if (verbose_flag)
|
||||
printf("No unconnected need to be removed.\n");
|
||||
}
|
||||
|
||||
if (fill_holes_flag || fixall_flag) {
|
||||
if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
|
||||
if (verbose_flag)
|
||||
printf("Filling holes...\n");
|
||||
stl_fill_holes(stl);
|
||||
} else if (verbose_flag)
|
||||
printf("No holes need to be filled.\n");
|
||||
}
|
||||
|
||||
if (reverse_all_flag) {
|
||||
if (verbose_flag)
|
||||
printf("Reversing all facets...\n");
|
||||
stl_reverse_all_facets(stl);
|
||||
}
|
||||
|
||||
if (normal_directions_flag || fixall_flag) {
|
||||
if (verbose_flag)
|
||||
printf("Checking normal directions...\n");
|
||||
stl_fix_normal_directions(stl);
|
||||
}
|
||||
|
||||
if (normal_values_flag || fixall_flag) {
|
||||
if (verbose_flag)
|
||||
printf("Checking normal values...\n");
|
||||
stl_fix_normal_values(stl);
|
||||
}
|
||||
|
||||
// Always calculate the volume. It shouldn't take too long.
|
||||
if (verbose_flag)
|
||||
printf("Calculating volume...\n");
|
||||
stl_calculate_volume(stl);
|
||||
|
||||
if (exact_flag) {
|
||||
if (verbose_flag)
|
||||
printf("Verifying neighbors...\n");
|
||||
stl_verify_neighbors(stl);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ if (MSVC)
|
|||
windows/unistd.cpp
|
||||
windows/getopt.c
|
||||
)
|
||||
elseif (MINGW)
|
||||
set(AVRDUDE_SOURCES ${AVRDUDE_SOURCES}
|
||||
windows/utf8.c
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(avrdude-conf-gen conf-generate.cpp)
|
||||
|
|
@ -81,13 +85,13 @@ add_executable(avrdude-conf-gen conf-generate.cpp)
|
|||
# Config file embedding
|
||||
add_custom_command(
|
||||
DEPENDS avrdude-conf-gen ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf
|
||||
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h
|
||||
COMMAND $<TARGET_FILE:avrdude-conf-gen> avrdude-slic3r.conf avrdude_slic3r_conf > avrdude-slic3r.conf.h
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h
|
||||
COMMAND $<TARGET_FILE:avrdude-conf-gen> avrdude-slic3r.conf avrdude_slic3r_conf ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
add_custom_target(gen_conf_h
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/avrdude-slic3r.conf.h
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/avrdude-slic3r.conf.h
|
||||
)
|
||||
|
||||
add_library(avrdude STATIC ${AVRDUDE_SOURCES})
|
||||
|
|
@ -96,7 +100,15 @@ add_dependencies(avrdude gen_conf_h)
|
|||
add_executable(avrdude-slic3r main-standalone.cpp)
|
||||
target_link_libraries(avrdude-slic3r avrdude)
|
||||
|
||||
encoding_check(avrdude)
|
||||
encoding_check(avrdude-slic3r)
|
||||
|
||||
# Make avrdude-slic3r.conf.h includable:
|
||||
target_include_directories(avrdude SYSTEM PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
if (WIN32)
|
||||
target_compile_definitions(avrdude PRIVATE WIN32NATIVE=1)
|
||||
target_include_directories(avrdude SYSTEM PRIVATE windows) # So that sources find the getopt.h windows drop-in
|
||||
if(MSVC)
|
||||
target_include_directories(avrdude SYSTEM PRIVATE windows) # So that sources find the getopt.h windows drop-in
|
||||
endif(MSVC)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
|
||||
{
|
||||
unsigned char buf[32];
|
||||
(void)p;
|
||||
|
||||
/* Signature byte reads are always 3 bytes. */
|
||||
|
||||
|
|
@ -83,9 +84,9 @@ static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
|
|||
static int prusa_init_external_flash(PROGRAMMER * pgm)
|
||||
{
|
||||
// Note: send/receive as in _the firmare_ send & receives
|
||||
const char entry_magic_send [] = "start\n";
|
||||
const char entry_magic_receive[] = "w25x20cl_enter\n";
|
||||
const char entry_magic_cfm [] = "w25x20cl_cfm\n";
|
||||
const char entry_magic_send[] = "start\n";
|
||||
const unsigned char entry_magic_receive[] = "w25x20cl_enter\n";
|
||||
const char entry_magic_cfm[] = "w25x20cl_cfm\n";
|
||||
const size_t buffer_len = 32; // Should be large enough for the above messages
|
||||
|
||||
int res;
|
||||
|
|
@ -94,7 +95,7 @@ static int prusa_init_external_flash(PROGRAMMER * pgm)
|
|||
|
||||
// 1. receive the "start" command
|
||||
recv_size = sizeof(entry_magic_send) - 1;
|
||||
res = serial_recv(&pgm->fd, buffer, recv_size);
|
||||
res = serial_recv(&pgm->fd, (unsigned char *)buffer, recv_size);
|
||||
if (res < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer did not boot up on time or serial communication failed\n", progname);
|
||||
return -1;
|
||||
|
|
@ -111,7 +112,7 @@ static int prusa_init_external_flash(PROGRAMMER * pgm)
|
|||
|
||||
// 3. Receive the entry confirmation command
|
||||
recv_size = sizeof(entry_magic_cfm) - 1;
|
||||
res = serial_recv(&pgm->fd, buffer, recv_size);
|
||||
res = serial_recv(&pgm->fd, (unsigned char *)buffer, recv_size);
|
||||
if (res < 0) {
|
||||
avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer did not boot up on time or serial communication failed\n", progname);
|
||||
return -1;
|
||||
|
|
@ -142,7 +143,7 @@ static int arduino_open(PROGRAMMER * pgm, char * port)
|
|||
|
||||
// Sometimes there may be line noise generating input on the printer's USB-to-serial IC
|
||||
// Here we try to clean its input buffer with a sequence of newlines (a minimum of 9 is needed):
|
||||
const char cleanup_newlines[] = "\n\n\n\n\n\n\n\n\n\n";
|
||||
const unsigned char cleanup_newlines[] = "\n\n\n\n\n\n\n\n\n\n";
|
||||
if (serial_send(&pgm->fd, cleanup_newlines, sizeof(cleanup_newlines) - 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
|
|||
avr_tpi_setup_rw(pgm, mem, 0, TPI_NVMCMD_NO_OPERATION);
|
||||
|
||||
/* load bytes */
|
||||
for (lastaddr = i = 0; i < mem->size; i++) {
|
||||
for (lastaddr = i = 0; i < (unsigned)mem->size; i++) {
|
||||
RETURN_IF_CANCEL();
|
||||
if (vmem == NULL ||
|
||||
(vmem->tags[i] & TAG_ALLOCATED) != 0)
|
||||
|
|
@ -374,7 +374,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
|
|||
|
||||
/* quickly scan number of pages to be written to first */
|
||||
for (pageaddr = 0, npages = 0;
|
||||
pageaddr < mem->size;
|
||||
pageaddr < (unsigned)mem->size;
|
||||
pageaddr += mem->page_size) {
|
||||
/* check whether this page must be read */
|
||||
for (i = pageaddr;
|
||||
|
|
@ -391,7 +391,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
|
|||
}
|
||||
|
||||
for (pageaddr = 0, failure = 0, nread = 0;
|
||||
!failure && pageaddr < mem->size;
|
||||
!failure && pageaddr < (unsigned)mem->size;
|
||||
pageaddr += mem->page_size) {
|
||||
RETURN_IF_CANCEL();
|
||||
/* check whether this page must be read */
|
||||
|
|
@ -437,7 +437,7 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype,
|
|||
}
|
||||
}
|
||||
|
||||
for (i=0; i < mem->size; i++) {
|
||||
for (i = 0; i < (unsigned)mem->size; i++) {
|
||||
RETURN_IF_CANCEL();
|
||||
if (vmem == NULL ||
|
||||
(vmem->tags[i] & TAG_ALLOCATED) != 0)
|
||||
|
|
@ -634,18 +634,18 @@ int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
writeop = mem->op[AVR_OP_WRITE_HI];
|
||||
else
|
||||
writeop = mem->op[AVR_OP_WRITE_LO];
|
||||
caddr = addr / 2;
|
||||
caddr = (unsigned short)(addr / 2);
|
||||
}
|
||||
else if (mem->paged && mem->op[AVR_OP_LOADPAGE_LO]) {
|
||||
if (addr & 0x01)
|
||||
writeop = mem->op[AVR_OP_LOADPAGE_HI];
|
||||
else
|
||||
writeop = mem->op[AVR_OP_LOADPAGE_LO];
|
||||
caddr = addr / 2;
|
||||
caddr = (unsigned short)(addr / 2);
|
||||
}
|
||||
else {
|
||||
writeop = mem->op[AVR_OP_WRITE];
|
||||
caddr = addr;
|
||||
caddr = (unsigned short)addr;
|
||||
}
|
||||
|
||||
if (writeop == NULL) {
|
||||
|
|
@ -723,7 +723,7 @@ int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
gettimeofday (&tv, NULL);
|
||||
prog_time = (tv.tv_sec * 1000000) + tv.tv_usec;
|
||||
} while ((r != data) &&
|
||||
((prog_time-start_time) < mem->max_write_delay));
|
||||
((prog_time - start_time) < (unsigned long)mem->max_write_delay));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -878,7 +878,7 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
|
|||
}
|
||||
|
||||
/* write words, low byte first */
|
||||
for (lastaddr = i = 0; i < wsize; i += 2) {
|
||||
for (lastaddr = i = 0; i < (unsigned)wsize; i += 2) {
|
||||
RETURN_IF_CANCEL();
|
||||
if ((m->tags[i] & TAG_ALLOCATED) != 0 ||
|
||||
(m->tags[i + 1] & TAG_ALLOCATED) != 0) {
|
||||
|
|
@ -915,7 +915,7 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
|
|||
|
||||
/* quickly scan number of pages to be written to first */
|
||||
for (pageaddr = 0, npages = 0;
|
||||
pageaddr < wsize;
|
||||
pageaddr < (unsigned)wsize;
|
||||
pageaddr += m->page_size) {
|
||||
/* check whether this page must be written to */
|
||||
for (i = pageaddr;
|
||||
|
|
@ -928,7 +928,7 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
|
|||
}
|
||||
|
||||
for (pageaddr = 0, failure = 0, nwritten = 0;
|
||||
!failure && pageaddr < wsize;
|
||||
!failure && pageaddr < (unsigned)wsize;
|
||||
pageaddr += m->page_size) {
|
||||
RETURN_IF_CANCEL();
|
||||
/* check whether this page must be written to */
|
||||
|
|
@ -968,7 +968,7 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
|
|||
page_tainted = 0;
|
||||
flush_page = 0;
|
||||
|
||||
for (i=0; i<wsize; i++) {
|
||||
for (i = 0; i < (unsigned)wsize; i++) {
|
||||
RETURN_IF_CANCEL();
|
||||
data = m->buf[i];
|
||||
report_progress(i, wsize, NULL);
|
||||
|
|
|
|||
|
|
@ -676,7 +676,7 @@ static int avr910_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
avr910_set_addr(pgm, addr / rd_size);
|
||||
|
||||
while (addr < max_addr) {
|
||||
if ((max_addr - addr) < blocksize) {
|
||||
if ((max_addr - addr) < (unsigned)blocksize) {
|
||||
blocksize = max_addr - addr;
|
||||
}
|
||||
cmd[1] = (blocksize >> 8) & 0xff;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -93,7 +93,7 @@ void AvrDude::priv::unset_handlers()
|
|||
|
||||
|
||||
int AvrDude::priv::run_one(const std::vector<std::string> &args) {
|
||||
std::vector<char*> c_args {{ const_cast<char*>(PACKAGE) }};
|
||||
std::vector<char*> c_args { const_cast<char*>(PACKAGE) };
|
||||
std::string command_line { PACKAGE };
|
||||
|
||||
for (const auto &arg : args) {
|
||||
|
|
@ -105,7 +105,7 @@ int AvrDude::priv::run_one(const std::vector<std::string> &args) {
|
|||
|
||||
HandlerGuard guard(*this);
|
||||
|
||||
message_fn(command_line.c_str(), command_line.size());
|
||||
message_fn(command_line.c_str(), (unsigned)command_line.size());
|
||||
|
||||
const auto res = ::avrdude_main(static_cast<int>(c_args.size()), c_args.data());
|
||||
|
||||
|
|
@ -200,7 +200,7 @@ AvrDude::Ptr AvrDude::run()
|
|||
auto &message_fn = self->p->message_fn;
|
||||
if (message_fn) {
|
||||
message_fn(msg, sizeof(msg));
|
||||
message_fn(what, std::strlen(what));
|
||||
message_fn(what, (unsigned)std::strlen(what));
|
||||
message_fn("\n", 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ int avrdude_main(int argc, char * argv []);
|
|||
#include <windows.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define strdup _strdup
|
||||
|
||||
#ifdef UNICODE
|
||||
#error "UNICODE should not be defined for avrdude bits on Windows"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
|
|||
int matches;
|
||||
int l;
|
||||
|
||||
l = strlen(desc);
|
||||
l = (int)strlen(desc);
|
||||
matches = 0;
|
||||
match = NULL;
|
||||
for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
|
||||
|
|
@ -662,7 +662,7 @@ void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose)
|
|||
prefix);
|
||||
|
||||
px = prefix;
|
||||
i = strlen(prefix) + 5;
|
||||
i = (int)strlen(prefix) + 5;
|
||||
buf = (char *)malloc(i);
|
||||
if (buf == NULL) {
|
||||
/* ugh, this is not important enough to bail, just ignore it */
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ static int buspirate_recv_bin(struct programmer_t *pgm, unsigned char *buf, size
|
|||
avrdude_message(MSG_DEBUG, "%s: buspirate_recv_bin():\n", progname);
|
||||
dump_mem(MSG_DEBUG, buf, len);
|
||||
|
||||
return len;
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
static int buspirate_expect_bin(struct programmer_t *pgm,
|
||||
|
|
@ -249,7 +249,7 @@ static int buspirate_send(struct programmer_t *pgm, const char *str)
|
|||
|
||||
static int buspirate_is_prompt(const char *str)
|
||||
{
|
||||
int strlen_str = strlen(str);
|
||||
int strlen_str = (int)strlen(str);
|
||||
/* Prompt ends with '>' or '> '
|
||||
* all other input probably ends with '\n' */
|
||||
return (str[strlen_str - 1] == '>' || str[strlen_str - 2] == '>');
|
||||
|
|
|
|||
|
|
@ -675,7 +675,7 @@ static int butterfly_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
butterfly_set_addr(pgm, addr / rd_size);
|
||||
}
|
||||
while (addr < max_addr) {
|
||||
if ((max_addr - addr) < blocksize) {
|
||||
if ((max_addr - addr) < (unsigned)blocksize) {
|
||||
blocksize = max_addr - addr;
|
||||
};
|
||||
cmd[1] = (blocksize >> 8) & 0xff;
|
||||
|
|
|
|||
|
|
@ -6,36 +6,42 @@
|
|||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " <file> <symbol name>" << std::endl;
|
||||
if (argc != 4) {
|
||||
std::cerr << "Usage: " << argv[0] << " <file> <symbol name> <output file>" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* filename = argv[1];
|
||||
const char* filename_in = argv[1];
|
||||
const char* symbol = argv[2];
|
||||
const char* filename_out = argv[3];
|
||||
|
||||
size_t size = 0;
|
||||
std::fstream file(filename);
|
||||
std::fstream file(filename_in, std::ios::in | std::ios::binary);
|
||||
if (!file.good()) {
|
||||
std::cerr << "Cannot read file: " << filename << std::endl;
|
||||
std::cerr << "Cannot read file: " << filename_in << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "/* WARN: This file is auto-generated from `" << filename << "` */" << std::endl;
|
||||
std::cout << "unsigned char " << symbol << "[] = {";
|
||||
std::fstream output(filename_out, std::ios::out | std::ios::trunc);
|
||||
if (!output.good()) {
|
||||
std::cerr << "Cannot open output file: " << filename_out << std::endl;
|
||||
}
|
||||
|
||||
output << "/* WARN: This file is auto-generated from `" << filename_in << "` */" << std::endl;
|
||||
output << "const unsigned char " << symbol << "[] = {";
|
||||
|
||||
char c;
|
||||
std::cout << std::hex;
|
||||
std::cout.fill('0');
|
||||
output << std::hex;
|
||||
output.fill('0');
|
||||
for (file.get(c); !file.eof(); size++, file.get(c)) {
|
||||
if (size % 12 == 0) { std::cout << "\n "; }
|
||||
std::cout << "0x" << std::setw(2) << (unsigned)c << ", ";
|
||||
if (size % 12 == 0) { output << "\n "; }
|
||||
output << "0x" << std::setw(2) << (unsigned)c << ", ";
|
||||
}
|
||||
|
||||
std::cout << "\n 0, 0\n};\n";
|
||||
output << "\n 0, 0\n};\n";
|
||||
|
||||
std::cout << std::dec;
|
||||
std::cout << "size_t " << symbol << "_size = " << size << ";" << std::endl;
|
||||
std::cout << "size_t " << symbol << "_size_yy = " << size + 2 << ";" << std::endl;
|
||||
output << std::dec;
|
||||
output << "const size_t " << symbol << "_size = " << size << ";" << std::endl;
|
||||
output << "const size_t " << symbol << "_size_yy = " << size + 2 << ";" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ TOKEN * string(char * text)
|
|||
return NULL; /* yyerror already called */
|
||||
}
|
||||
|
||||
len = strlen(text);
|
||||
len = (int)strlen(text);
|
||||
|
||||
tkn->value.type = V_STR;
|
||||
tkn->value.string = (char *) malloc(len+1);
|
||||
|
|
@ -351,7 +351,7 @@ int read_config(const char * file)
|
|||
}
|
||||
|
||||
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
||||
extern YY_BUFFER_STATE yy_scan_bytes(char *base, size_t size);
|
||||
extern YY_BUFFER_STATE yy_scan_bytes(const char *base, size_t size);
|
||||
extern void yy_delete_buffer(YY_BUFFER_STATE b);
|
||||
|
||||
int read_config_builtin()
|
||||
|
|
@ -363,7 +363,7 @@ int read_config_builtin()
|
|||
|
||||
// Note: Can't use yy_scan_buffer, it's buggy (?), leads to fread from a null FILE*
|
||||
// and so unfortunatelly we have to use the copying variant here
|
||||
YY_BUFFER_STATE buffer = yy_scan_bytes(avrdude_slic3r_conf, avrdude_slic3r_conf_size);
|
||||
YY_BUFFER_STATE buffer = yy_scan_bytes((const char *)avrdude_slic3r_conf, avrdude_slic3r_conf_size);
|
||||
if (buffer == NULL) {
|
||||
avrdude_message(MSG_INFO, "%s: read_config_builtin: Failed to initialize parsing buffer\n", progname);
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -3640,7 +3640,7 @@ static int parse_cmdbits(OPCODE * op)
|
|||
break;
|
||||
}
|
||||
|
||||
len = strlen(s);
|
||||
len = (int)strlen(s);
|
||||
|
||||
if (len == 0) {
|
||||
yyerror("invalid bit specifier \"\"");
|
||||
|
|
|
|||
|
|
@ -1493,7 +1493,7 @@ static int parse_cmdbits(OPCODE * op)
|
|||
break;
|
||||
}
|
||||
|
||||
len = strlen(s);
|
||||
len = (int)strlen(s);
|
||||
|
||||
if (len == 0) {
|
||||
yyerror("invalid bit specifier \"\"");
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
|
|||
unsigned char cksum;
|
||||
int rc;
|
||||
|
||||
len = strlen(rec);
|
||||
len = (int)strlen(rec);
|
||||
offset = 1;
|
||||
cksum = 0;
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
|
|||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
ihex->reclen = strtoul(buf, &e, 16);
|
||||
ihex->reclen = (unsigned char)strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
|
||||
|
|
@ -294,7 +294,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
|
|||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
ihex->rectyp = strtoul(buf, &e, 16);
|
||||
ihex->rectyp = (unsigned char)strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
|
||||
|
|
@ -308,7 +308,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
|
|||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
ihex->data[j] = strtoul(buf, &e, 16);
|
||||
ihex->data[j] = (char)strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
cksum += ihex->data[j];
|
||||
|
|
@ -320,7 +320,7 @@ static int ihex_readrec(struct ihexrec * ihex, char * rec)
|
|||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
ihex->cksum = strtoul(buf, &e, 16);
|
||||
ihex->cksum = (char)strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
|
||||
|
|
@ -361,7 +361,7 @@ static int ihex2b(char * infile, FILE * inf,
|
|||
|
||||
while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
|
||||
lineno++;
|
||||
len = strlen(buffer);
|
||||
len = (int)strlen(buffer);
|
||||
if (buffer[len-1] == '\n')
|
||||
buffer[--len] = 0;
|
||||
if (buffer[0] != ':')
|
||||
|
|
@ -388,7 +388,7 @@ static int ihex2b(char * infile, FILE * inf,
|
|||
return -1;
|
||||
}
|
||||
nextaddr = ihex.loadofs + baseaddr - fileoffset;
|
||||
if (nextaddr + ihex.reclen > bufsize) {
|
||||
if (nextaddr + ihex.reclen > (unsigned)bufsize) {
|
||||
avrdude_message(MSG_INFO, "%s: ERROR: address 0x%04x out of range at line %d of %s\n",
|
||||
progname, nextaddr+ihex.reclen, lineno, infile);
|
||||
return -1;
|
||||
|
|
@ -502,10 +502,11 @@ static int b2srec(unsigned char * inbuf, int bufsize,
|
|||
|
||||
cksum += n + addr_width + 1;
|
||||
|
||||
for (i=addr_width; i>0; i--)
|
||||
for (i = addr_width; i>0; i--) {
|
||||
cksum += (nextaddr >> (i-1) * 8) & 0xff;
|
||||
}
|
||||
|
||||
for (i=nextaddr; i<nextaddr + n; i++) {
|
||||
for (unsigned i = nextaddr; i < nextaddr + n; i++) {
|
||||
fprintf(outf, "%02X", buf[i]);
|
||||
cksum += buf[i];
|
||||
}
|
||||
|
|
@ -562,7 +563,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
|
|||
unsigned char cksum;
|
||||
int rc;
|
||||
|
||||
len = strlen(rec);
|
||||
len = (int)strlen(rec);
|
||||
offset = 1;
|
||||
cksum = 0;
|
||||
addr_width = 2;
|
||||
|
|
@ -582,7 +583,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
|
|||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
srec->reclen = strtoul(buf, &e, 16);
|
||||
srec->reclen = (char)strtoul(buf, &e, 16);
|
||||
cksum += srec->reclen;
|
||||
srec->reclen -= (addr_width+1);
|
||||
if (e == buf || *e != 0)
|
||||
|
|
@ -594,7 +595,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
|
|||
for (i=0; i<addr_width*2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
srec->loadofs = strtoull(buf, &e, 16);
|
||||
srec->loadofs = strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
|
||||
|
|
@ -608,7 +609,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
|
|||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
srec->data[j] = strtoul(buf, &e, 16);
|
||||
srec->data[j] = (char)strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
cksum += srec->data[j];
|
||||
|
|
@ -620,7 +621,7 @@ static int srec_readrec(struct ihexrec * srec, char * rec)
|
|||
for (i=0; i<2; i++)
|
||||
buf[i] = rec[offset++];
|
||||
buf[i] = 0;
|
||||
srec->cksum = strtoul(buf, &e, 16);
|
||||
srec->cksum = (char)strtoul(buf, &e, 16);
|
||||
if (e == buf || *e != 0)
|
||||
return -1;
|
||||
|
||||
|
|
@ -650,7 +651,7 @@ static int srec2b(char * infile, FILE * inf,
|
|||
|
||||
while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
|
||||
lineno++;
|
||||
len = strlen(buffer);
|
||||
len = (int)strlen(buffer);
|
||||
if (buffer[len-1] == '\n')
|
||||
buffer[--len] = 0;
|
||||
if (buffer[0] != 0x53)
|
||||
|
|
@ -729,7 +730,7 @@ static int srec2b(char * infile, FILE * inf,
|
|||
return -1;
|
||||
}
|
||||
nextaddr -= fileoffset;
|
||||
if (nextaddr + srec.reclen > bufsize) {
|
||||
if (nextaddr + srec.reclen > (unsigned)bufsize) {
|
||||
avrdude_message(MSG_INFO, msg, progname, nextaddr+srec.reclen, "",
|
||||
lineno, infile);
|
||||
return -1;
|
||||
|
|
@ -740,7 +741,7 @@ static int srec2b(char * infile, FILE * inf,
|
|||
}
|
||||
if (nextaddr+srec.reclen > maxaddr)
|
||||
maxaddr = nextaddr+srec.reclen;
|
||||
reccount++;
|
||||
reccount++;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1143,12 +1144,12 @@ static int fileio_rbin(struct fioparms * fio,
|
|||
|
||||
switch (fio->op) {
|
||||
case FIO_READ:
|
||||
rc = fread(buf, 1, size, f);
|
||||
rc = (int)fread(buf, 1, size, f);
|
||||
if (rc > 0)
|
||||
memset(mem->tags, TAG_ALLOCATED, rc);
|
||||
break;
|
||||
case FIO_WRITE:
|
||||
rc = fwrite(buf, 1, size, f);
|
||||
rc = (int)fwrite(buf, 1, size, f);
|
||||
break;
|
||||
default:
|
||||
avrdude_message(MSG_INFO, "%s: fileio: invalid operation=%d\n",
|
||||
|
|
@ -1190,7 +1191,7 @@ static int fileio_imm(struct fioparms * fio,
|
|||
progname, p);
|
||||
return -1;
|
||||
}
|
||||
mem->buf[loc] = b;
|
||||
mem->buf[loc] = (char)b;
|
||||
mem->tags[loc++] = TAG_ALLOCATED;
|
||||
p = strtok(NULL, " ,");
|
||||
rc = loc;
|
||||
|
|
@ -1452,7 +1453,7 @@ static int fmt_autodetect(char * fname, unsigned section)
|
|||
}
|
||||
|
||||
buf[MAX_LINE_LEN-1] = 0;
|
||||
len = strlen((char *)buf);
|
||||
len = (int)strlen((char *)buf);
|
||||
if (buf[len-1] == '\n')
|
||||
buf[--len] = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
|
||||
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(_MSC_VER)
|
||||
|
||||
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
|
||||
* if you want the limit (max/min) macros for int types.
|
||||
|
|
|
|||
|
|
@ -444,7 +444,7 @@ lcreat ( void * liststruct, int elements )
|
|||
l->poolsize = DEFAULT_POOLSIZE;
|
||||
}
|
||||
else {
|
||||
l->poolsize = elements*sizeof(LISTNODE)+sizeof(NODEPOOL);
|
||||
l->poolsize = (short)(elements*sizeof(LISTNODE)+sizeof(NODEPOOL));
|
||||
}
|
||||
|
||||
l->n_ln_pool = (l->poolsize-sizeof(NODEPOOL))/sizeof(LISTNODE);
|
||||
|
|
@ -803,7 +803,7 @@ lget_n ( LISTID lid, unsigned int n )
|
|||
|
||||
CKLMAGIC(l);
|
||||
|
||||
if ((n<1)||(n>lsize(l))) {
|
||||
if ((n < 1) || (n > (unsigned)lsize(l))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -844,7 +844,7 @@ lget_ln ( LISTID lid, unsigned int n )
|
|||
|
||||
CKLMAGIC(l);
|
||||
|
||||
if ((n<1)||(n>lsize(l))) {
|
||||
if ((n < 1) || (n > (unsigned)lsize(l))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -941,7 +941,7 @@ insert_ln ( LIST * l, LISTNODE * ln, void * data_ptr )
|
|||
|
|
||||
| Insert data before the nth item in the list.
|
||||
-----------------------------------------------------------------*/
|
||||
int
|
||||
int
|
||||
lins_n ( LISTID lid, void * data_ptr, unsigned int n )
|
||||
{
|
||||
int i;
|
||||
|
|
@ -952,7 +952,7 @@ lins_n ( LISTID lid, void * data_ptr, unsigned int n )
|
|||
|
||||
CKLMAGIC(l);
|
||||
|
||||
if ((n<1)||(n>(l->num+1))) {
|
||||
if ((n < 1) || (n > (unsigned)(l->num+1))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -1193,7 +1193,7 @@ lrmv_n ( LISTID lid, unsigned int n )
|
|||
|
||||
CKLMAGIC(l);
|
||||
|
||||
if ((n<1)||(n>l->num)) {
|
||||
if ((n < 1) || (n > (unsigned)l->num)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ struct ArgvUtf8 : std::vector<char*>
|
|||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
int wmain(int argc_w, wchar_t *argv_w[])
|
||||
{
|
||||
ArgvUtf8 argv_utf8(argc_w, argv_w);
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ int avrdude_message(const int msglvl, const char *format, ...)
|
|||
if (rc > 0 && rc < MSGBUFFER_SIZE) {
|
||||
avrdude_message_handler(msgbuffer, rc, avrdude_message_handler_user_p);
|
||||
} else {
|
||||
avrdude_message_handler(format_error, strlen(format_error), avrdude_message_handler_user_p);
|
||||
avrdude_message_handler(format_error, (unsigned)strlen(format_error), avrdude_message_handler_user_p);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -567,7 +567,7 @@ int avrdude_main(int argc, char * argv [])
|
|||
|
||||
// #endif
|
||||
|
||||
len = strlen(progname) + 2;
|
||||
len = (int)strlen(progname) + 2;
|
||||
for (i=0; i<len; i++)
|
||||
progbuf[i] = ' ';
|
||||
progbuf[i] = 0;
|
||||
|
|
@ -601,7 +601,7 @@ int avrdude_main(int argc, char * argv [])
|
|||
bitclock = strtod(optarg, &e);
|
||||
if (*e != 0) {
|
||||
/* trailing unit of measure present */
|
||||
int suffixlen = strlen(e);
|
||||
size_t suffixlen = strlen(e);
|
||||
switch (suffixlen) {
|
||||
case 2:
|
||||
if ((e[0] != 'h' && e[0] != 'H') || e[1] != 'z')
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ const char * pinmask_to_str(const pinmask_t * const pinmask) {
|
|||
* @param[in] size the number of entries in checklist
|
||||
* @returns 0 if all pin definitions are valid, -1 otherwise
|
||||
*/
|
||||
int pins_check(const struct programmer_t * const pgm, const struct pin_checklist_t * const checklist, const int size, bool output) {
|
||||
int pins_check(const struct programmer_t *const pgm, const struct pin_checklist_t *const checklist, const int size, const bool output) {
|
||||
static const struct pindef_t no_valid_pins = {{0}, {0}}; // default value if check list does not contain anything else
|
||||
int rv = 0; // return value
|
||||
int pinname; // loop counter through pinnames
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ static int ser_open(char * port, union pinfo pinfo, union filedescriptor *fdp)
|
|||
if (hComPort == INVALID_HANDLE_VALUE) {
|
||||
const char *error = last_error_string(0);
|
||||
avrdude_message(MSG_INFO, "%s: ser_open(): can't open device \"%s\": %s\n", progname, port, error);
|
||||
free(error);
|
||||
free((char *)error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -460,10 +460,10 @@ static int ser_send(union filedescriptor *fd, const unsigned char * buf, size_t
|
|||
|
||||
serial_w32SetTimeOut(hComPort,500);
|
||||
|
||||
if (!WriteFile(hComPort, buf, buflen, &written, NULL)) {
|
||||
if (!WriteFile(hComPort, buf, (DWORD)buflen, &written, NULL)) {
|
||||
const char *error = last_error_string(0);
|
||||
avrdude_message(MSG_INFO, "%s: ser_send(): write error: %s\n", progname, error);
|
||||
free(error);
|
||||
free((char *)error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -576,10 +576,10 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen
|
|||
|
||||
serial_w32SetTimeOut(hComPort, serial_recv_timeout);
|
||||
|
||||
if (!ReadFile(hComPort, buf, buflen, &read, NULL)) {
|
||||
if (!ReadFile(hComPort, buf, (DWORD)buflen, &read, NULL)) {
|
||||
const char *error = last_error_string(0);
|
||||
avrdude_message(MSG_INFO, "%s: ser_recv(): read error: %s\n", progname, error);
|
||||
free(error);
|
||||
free((char *)error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -642,7 +642,7 @@ static int ser_drain(union filedescriptor *fd, int display)
|
|||
if (!readres) {
|
||||
const char *error = last_error_string(0);
|
||||
avrdude_message(MSG_INFO, "%s: ser_drain(): read error: %s\n", progname, error);
|
||||
free(error);
|
||||
free((char *)error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -308,8 +308,8 @@ static int serbb_open(PROGRAMMER *pgm, char *port)
|
|||
progname, port);
|
||||
return -1;
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: ser_open(): opened comm port \"%s\", handle 0x%x\n",
|
||||
progname, port, (int)hComPort);
|
||||
avrdude_message(MSG_DEBUG, "%s: ser_open(): opened comm port \"%s\", handle %p\n",
|
||||
progname, port, (void *)hComPort);
|
||||
|
||||
pgm->fd.pfd = (void *)hComPort;
|
||||
|
||||
|
|
@ -326,8 +326,8 @@ static void serbb_close(PROGRAMMER *pgm)
|
|||
pgm->setpin(pgm, PIN_AVR_RESET, 1);
|
||||
CloseHandle (hComPort);
|
||||
}
|
||||
avrdude_message(MSG_DEBUG, "%s: ser_close(): closed comm port handle 0x%x\n",
|
||||
progname, (int)hComPort);
|
||||
avrdude_message(MSG_DEBUG, "%s: ser_close(): closed comm port handle %p\n",
|
||||
progname, (void *)hComPort);
|
||||
|
||||
hComPort = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -504,7 +504,7 @@ static int stk500_initialize(PROGRAMMER * pgm, AVRPART * p)
|
|||
}
|
||||
else {
|
||||
buf[9] = 0xff;
|
||||
buf[10] = 0xff;
|
||||
buf[10] = 0xff;
|
||||
buf[13] = 0;
|
||||
buf[14] = 0;
|
||||
buf[17] = 0;
|
||||
|
|
@ -821,7 +821,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
break;
|
||||
}
|
||||
|
||||
for (prusa3d_semicolon_workaround_round = 0; prusa3d_semicolon_workaround_round < (has_semicolon ? 2 : 1); ++ prusa3d_semicolon_workaround_round) {
|
||||
for (prusa3d_semicolon_workaround_round = 0; prusa3d_semicolon_workaround_round < (has_semicolon ? 2u : 1u); prusa3d_semicolon_workaround_round++) {
|
||||
/* build command block and avoid multiple send commands as it leads to a crash
|
||||
of the silabs usb serial driver on mac os x */
|
||||
i = 0;
|
||||
|
|
@ -834,7 +834,7 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
buf[i++] = block_size & 0x0f;
|
||||
buf[i++] = memtype;
|
||||
if (has_semicolon) {
|
||||
for (j = 0; j < block_size; ++i, ++ j) {
|
||||
for (j = 0; j < (unsigned)block_size; ++i, ++ j) {
|
||||
buf[i] = m->buf[addr + j];
|
||||
if (buf[i] == ';')
|
||||
buf[i] |= (prusa3d_semicolon_workaround_round ? 0xf0 : 0x0f);
|
||||
|
|
@ -1088,8 +1088,8 @@ static int stk500_set_sck_period(PROGRAMMER * pgm, double v)
|
|||
|
||||
min = 8.0 / STK500_XTAL;
|
||||
max = 255 * min;
|
||||
dur = v / min + 0.5;
|
||||
|
||||
dur = (int)(v / min + 0.5);
|
||||
|
||||
if (v < min) {
|
||||
dur = 1;
|
||||
avrdude_message(MSG_INFO, "%s: stk500_set_sck_period(): p = %.1f us too small, using %.1f us\n",
|
||||
|
|
@ -1099,7 +1099,7 @@ static int stk500_set_sck_period(PROGRAMMER * pgm, double v)
|
|||
avrdude_message(MSG_INFO, "%s: stk500_set_sck_period(): p = %.1f us too large, using %.1f us\n",
|
||||
progname, v / 1e-6, dur * min / 1e-6);
|
||||
}
|
||||
|
||||
|
||||
return stk500_setparm(pgm, Parm_STK_SCK_DURATION, dur);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -130,58 +130,58 @@ struct jtagispentry
|
|||
#define SZ_SPI_MULTI (USHRT_MAX - 1)
|
||||
};
|
||||
|
||||
static const struct jtagispentry jtagispcmds[] = {
|
||||
/* generic */
|
||||
{ CMD_SET_PARAMETER, 2 },
|
||||
{ CMD_GET_PARAMETER, 3 },
|
||||
{ CMD_OSCCAL, 2 },
|
||||
{ CMD_LOAD_ADDRESS, 2 },
|
||||
/* ISP mode */
|
||||
{ CMD_ENTER_PROGMODE_ISP, 2 },
|
||||
{ CMD_LEAVE_PROGMODE_ISP, 2 },
|
||||
{ CMD_CHIP_ERASE_ISP, 2 },
|
||||
{ CMD_PROGRAM_FLASH_ISP, 2 },
|
||||
{ CMD_READ_FLASH_ISP, SZ_READ_FLASH_EE },
|
||||
{ CMD_PROGRAM_EEPROM_ISP, 2 },
|
||||
{ CMD_READ_EEPROM_ISP, SZ_READ_FLASH_EE },
|
||||
{ CMD_PROGRAM_FUSE_ISP, 3 },
|
||||
{ CMD_READ_FUSE_ISP, 4 },
|
||||
{ CMD_PROGRAM_LOCK_ISP, 3 },
|
||||
{ CMD_READ_LOCK_ISP, 4 },
|
||||
{ CMD_READ_SIGNATURE_ISP, 4 },
|
||||
{ CMD_READ_OSCCAL_ISP, 4 },
|
||||
{ CMD_SPI_MULTI, SZ_SPI_MULTI },
|
||||
/* all HV modes */
|
||||
{ CMD_SET_CONTROL_STACK, 2 },
|
||||
/* HVSP mode */
|
||||
{ CMD_ENTER_PROGMODE_HVSP, 2 },
|
||||
{ CMD_LEAVE_PROGMODE_HVSP, 2 },
|
||||
{ CMD_CHIP_ERASE_HVSP, 2 },
|
||||
{ CMD_PROGRAM_FLASH_HVSP, 2 },
|
||||
{ CMD_READ_FLASH_HVSP, SZ_READ_FLASH_EE },
|
||||
{ CMD_PROGRAM_EEPROM_HVSP, 2 },
|
||||
{ CMD_READ_EEPROM_HVSP, SZ_READ_FLASH_EE },
|
||||
{ CMD_PROGRAM_FUSE_HVSP, 2 },
|
||||
{ CMD_READ_FUSE_HVSP, 3 },
|
||||
{ CMD_PROGRAM_LOCK_HVSP, 2 },
|
||||
{ CMD_READ_LOCK_HVSP, 3 },
|
||||
{ CMD_READ_SIGNATURE_HVSP, 3 },
|
||||
{ CMD_READ_OSCCAL_HVSP, 3 },
|
||||
/* PP mode */
|
||||
{ CMD_ENTER_PROGMODE_PP, 2 },
|
||||
{ CMD_LEAVE_PROGMODE_PP, 2 },
|
||||
{ CMD_CHIP_ERASE_PP, 2 },
|
||||
{ CMD_PROGRAM_FLASH_PP, 2 },
|
||||
{ CMD_READ_FLASH_PP, SZ_READ_FLASH_EE },
|
||||
{ CMD_PROGRAM_EEPROM_PP, 2 },
|
||||
{ CMD_READ_EEPROM_PP, SZ_READ_FLASH_EE },
|
||||
{ CMD_PROGRAM_FUSE_PP, 2 },
|
||||
{ CMD_READ_FUSE_PP, 3 },
|
||||
{ CMD_PROGRAM_LOCK_PP, 2 },
|
||||
{ CMD_READ_LOCK_PP, 3 },
|
||||
{ CMD_READ_SIGNATURE_PP, 3 },
|
||||
{ CMD_READ_OSCCAL_PP, 3 },
|
||||
};
|
||||
// static const struct jtagispentry jtagispcmds[] = {
|
||||
// /* generic */
|
||||
// { CMD_SET_PARAMETER, 2 },
|
||||
// { CMD_GET_PARAMETER, 3 },
|
||||
// { CMD_OSCCAL, 2 },
|
||||
// { CMD_LOAD_ADDRESS, 2 },
|
||||
// /* ISP mode */
|
||||
// { CMD_ENTER_PROGMODE_ISP, 2 },
|
||||
// { CMD_LEAVE_PROGMODE_ISP, 2 },
|
||||
// { CMD_CHIP_ERASE_ISP, 2 },
|
||||
// { CMD_PROGRAM_FLASH_ISP, 2 },
|
||||
// { CMD_READ_FLASH_ISP, SZ_READ_FLASH_EE },
|
||||
// { CMD_PROGRAM_EEPROM_ISP, 2 },
|
||||
// { CMD_READ_EEPROM_ISP, SZ_READ_FLASH_EE },
|
||||
// { CMD_PROGRAM_FUSE_ISP, 3 },
|
||||
// { CMD_READ_FUSE_ISP, 4 },
|
||||
// { CMD_PROGRAM_LOCK_ISP, 3 },
|
||||
// { CMD_READ_LOCK_ISP, 4 },
|
||||
// { CMD_READ_SIGNATURE_ISP, 4 },
|
||||
// { CMD_READ_OSCCAL_ISP, 4 },
|
||||
// { CMD_SPI_MULTI, SZ_SPI_MULTI },
|
||||
// /* all HV modes */
|
||||
// { CMD_SET_CONTROL_STACK, 2 },
|
||||
// /* HVSP mode */
|
||||
// { CMD_ENTER_PROGMODE_HVSP, 2 },
|
||||
// { CMD_LEAVE_PROGMODE_HVSP, 2 },
|
||||
// { CMD_CHIP_ERASE_HVSP, 2 },
|
||||
// { CMD_PROGRAM_FLASH_HVSP, 2 },
|
||||
// { CMD_READ_FLASH_HVSP, SZ_READ_FLASH_EE },
|
||||
// { CMD_PROGRAM_EEPROM_HVSP, 2 },
|
||||
// { CMD_READ_EEPROM_HVSP, SZ_READ_FLASH_EE },
|
||||
// { CMD_PROGRAM_FUSE_HVSP, 2 },
|
||||
// { CMD_READ_FUSE_HVSP, 3 },
|
||||
// { CMD_PROGRAM_LOCK_HVSP, 2 },
|
||||
// { CMD_READ_LOCK_HVSP, 3 },
|
||||
// { CMD_READ_SIGNATURE_HVSP, 3 },
|
||||
// { CMD_READ_OSCCAL_HVSP, 3 },
|
||||
// /* PP mode */
|
||||
// { CMD_ENTER_PROGMODE_PP, 2 },
|
||||
// { CMD_LEAVE_PROGMODE_PP, 2 },
|
||||
// { CMD_CHIP_ERASE_PP, 2 },
|
||||
// { CMD_PROGRAM_FLASH_PP, 2 },
|
||||
// { CMD_READ_FLASH_PP, SZ_READ_FLASH_EE },
|
||||
// { CMD_PROGRAM_EEPROM_PP, 2 },
|
||||
// { CMD_READ_EEPROM_PP, SZ_READ_FLASH_EE },
|
||||
// { CMD_PROGRAM_FUSE_PP, 2 },
|
||||
// { CMD_READ_FUSE_PP, 3 },
|
||||
// { CMD_PROGRAM_LOCK_PP, 2 },
|
||||
// { CMD_READ_LOCK_PP, 3 },
|
||||
// { CMD_READ_SIGNATURE_PP, 3 },
|
||||
// { CMD_READ_OSCCAL_PP, 3 },
|
||||
// };
|
||||
|
||||
/*
|
||||
* From XML file:
|
||||
|
|
@ -379,15 +379,15 @@ static void stk500v2_jtag3_teardown(PROGRAMMER * pgm)
|
|||
}
|
||||
|
||||
|
||||
static unsigned short
|
||||
b2_to_u16(unsigned char *b)
|
||||
{
|
||||
unsigned short l;
|
||||
l = b[0];
|
||||
l += (unsigned)b[1] << 8;
|
||||
// static unsigned short
|
||||
// b2_to_u16(unsigned char *b)
|
||||
// {
|
||||
// unsigned short l;
|
||||
// l = b[0];
|
||||
// l += (unsigned)b[1] << 8;
|
||||
|
||||
return l;
|
||||
}
|
||||
// return l;
|
||||
// }
|
||||
|
||||
static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len)
|
||||
{
|
||||
|
|
@ -399,16 +399,16 @@ static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned short get_jtagisp_return_size(unsigned char cmd)
|
||||
{
|
||||
int i;
|
||||
// static unsigned short get_jtagisp_return_size(unsigned char cmd)
|
||||
// {
|
||||
// int i;
|
||||
|
||||
for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
|
||||
if (jtagispcmds[i].cmd == cmd)
|
||||
return jtagispcmds[i].size;
|
||||
// for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
|
||||
// if (jtagispcmds[i].cmd == cmd)
|
||||
// return jtagispcmds[i].size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
/*
|
||||
* Send the data as a JTAG ICE mkII encapsulated ISP packet.
|
||||
|
|
@ -504,7 +504,7 @@ static int stk500v2_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
|
|||
|
||||
buf[0] = MESSAGE_START;
|
||||
buf[1] = PDATA(pgm)->command_sequence;
|
||||
buf[2] = len / 256;
|
||||
buf[2] = (char)(len / 256);
|
||||
buf[3] = len % 256;
|
||||
buf[4] = TOKEN;
|
||||
memcpy(buf+5, data, len);
|
||||
|
|
@ -1128,7 +1128,8 @@ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p)
|
|||
{
|
||||
unsigned char buf[16];
|
||||
char msg[100]; /* see remarks above about size needed */
|
||||
int rv, tries;
|
||||
int rv;
|
||||
// int tries;
|
||||
|
||||
PDATA(pgm)->lastpart = p;
|
||||
|
||||
|
|
@ -1143,7 +1144,7 @@ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p)
|
|||
/* Activate AVR-style (low active) RESET */
|
||||
stk500v2_setparm_real(pgm, PARAM_RESET_POLARITY, 0x01);
|
||||
|
||||
tries = 0;
|
||||
// tries = 0;
|
||||
// retry:
|
||||
buf[0] = CMD_ENTER_PROGMODE_ISP;
|
||||
buf[1] = p->timeout;
|
||||
|
|
@ -1882,7 +1883,7 @@ static int stk500hv_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
if (stk500v2_loadaddr(pgm, use_ext_addr | (paddr >> addrshift)) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
buf[1] = addr;
|
||||
buf[1] = (char)addr;
|
||||
}
|
||||
|
||||
avrdude_message(MSG_NOTICE2, "%s: stk500hv_read_byte(): Sending read memory command: ",
|
||||
|
|
@ -2137,7 +2138,7 @@ static int stk500hv_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
if (stk500v2_loadaddr(pgm, use_ext_addr | (paddr >> addrshift)) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
buf[1] = addr;
|
||||
buf[1] = (char)addr;
|
||||
buf[2] = data;
|
||||
if (mode == PPMODE) {
|
||||
buf[3] = pulsewidth;
|
||||
|
|
@ -2298,7 +2299,7 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
|
|||
unsigned int page_size,
|
||||
unsigned int addr, unsigned int n_bytes)
|
||||
{
|
||||
static int page = 0;
|
||||
// static int page = 0;
|
||||
unsigned int block_size, last_addr, addrshift, use_ext_addr;
|
||||
unsigned int maxaddr = addr + n_bytes;
|
||||
unsigned char commandbuf[10];
|
||||
|
|
@ -2833,10 +2834,10 @@ static int stk500v2_set_fosc(PROGRAMMER * pgm, double v)
|
|||
progname, v, unit, STK500V2_XTAL / 2e6);
|
||||
fosc = STK500V2_XTAL / 2;
|
||||
} else
|
||||
fosc = (unsigned)v;
|
||||
fosc = (int)v;
|
||||
|
||||
for (idx = 0; idx < sizeof(ps) / sizeof(ps[0]); idx++) {
|
||||
if (fosc >= STK500V2_XTAL / (256 * ps[idx] * 2)) {
|
||||
if (fosc >= (int)(STK500V2_XTAL / (256 * ps[idx] * 2))) {
|
||||
/* this prescaler value can handle our frequency */
|
||||
prescale = idx + 1;
|
||||
cmatch = (unsigned)(STK500V2_XTAL / (2 * fosc * ps[idx])) - 1;
|
||||
|
|
@ -3065,8 +3066,8 @@ static int stk600_set_fosc(PROGRAMMER * pgm, double v)
|
|||
{
|
||||
unsigned int oct, dac;
|
||||
|
||||
oct = 1.443 * log(v / 1039.0);
|
||||
dac = 2048 - (2078.0 * pow(2, (double)(10 + oct))) / v;
|
||||
oct = (unsigned)(1.443 * log(v / 1039.0));
|
||||
dac = (unsigned)(2048.0 - (2078.0 * pow(2, (double)(10 + oct))) / v);
|
||||
|
||||
return stk500v2_setparm2(pgm, PARAM2_CLOCK_CONF, (oct << 12) | (dac << 2));
|
||||
}
|
||||
|
|
@ -3075,7 +3076,7 @@ static int stk600_set_sck_period(PROGRAMMER * pgm, double v)
|
|||
{
|
||||
unsigned int sck;
|
||||
|
||||
sck = ceil((16e6 / (2 * 1.0 / v)) - 1);
|
||||
sck = (unsigned)ceil((16e6 / (2 * 1.0 / v)) - 1);
|
||||
|
||||
if (sck >= 4096)
|
||||
sck = 4095;
|
||||
|
|
@ -3093,7 +3094,7 @@ static int stk500v2_jtag3_set_sck_period(PROGRAMMER * pgm, double v)
|
|||
else if (v > 1E-3)
|
||||
sck = 1;
|
||||
else
|
||||
sck = 1.0 / (1000.0 * v);
|
||||
sck = (unsigned)(1.0 / (1000.0 * v));
|
||||
|
||||
value[0] = CMD_SET_SCK;
|
||||
value[1] = sck & 0xff;
|
||||
|
|
@ -3143,7 +3144,7 @@ static int stk500v2_setparm_real(PROGRAMMER * pgm, unsigned char parm, unsigned
|
|||
|
||||
static int stk500v2_setparm(PROGRAMMER * pgm, unsigned char parm, unsigned char value)
|
||||
{
|
||||
unsigned char current_value;
|
||||
unsigned char current_value = 0;
|
||||
int res;
|
||||
|
||||
res = stk500v2_getparm(pgm, parm, ¤t_value);
|
||||
|
|
@ -3214,8 +3215,15 @@ static const char *stk600_get_cardname(const struct carddata *table,
|
|||
|
||||
static void stk500v2_display(PROGRAMMER * pgm, const char * p)
|
||||
{
|
||||
unsigned char maj, min, hdw, topcard, maj_s1, min_s1, maj_s2, min_s2;
|
||||
unsigned int rev;
|
||||
unsigned char maj = 0;
|
||||
unsigned char min = 0;
|
||||
unsigned char hdw = 0;
|
||||
unsigned char topcard = 0;
|
||||
unsigned char maj_s1 = 0;
|
||||
unsigned char min_s1 = 0;
|
||||
unsigned char maj_s2 = 0;
|
||||
unsigned char min_s2 = 0;
|
||||
unsigned int rev = 0;
|
||||
const char *topcard_name, *pgmname;
|
||||
|
||||
switch (PDATA(pgm)->pgmtype) {
|
||||
|
|
@ -3294,13 +3302,20 @@ f_to_kHz_MHz(double f, const char **unit)
|
|||
|
||||
static void stk500v2_print_parms1(PROGRAMMER * pgm, const char * p)
|
||||
{
|
||||
unsigned char vtarget, vadjust, osc_pscale, osc_cmatch, sck_duration =0; //XXX 0 is not correct, check caller
|
||||
unsigned int sck_stk600, clock_conf, dac, oct, varef;
|
||||
unsigned char vtarget_jtag[4];
|
||||
unsigned char vtarget = 0;
|
||||
unsigned char vadjust = 0;
|
||||
unsigned char sck_duration = 0;
|
||||
unsigned char osc_pscale = 0;
|
||||
unsigned char osc_cmatch = 0;
|
||||
unsigned varef = 0;
|
||||
unsigned sck_stk600 = 0;
|
||||
unsigned clock_conf = 0;
|
||||
unsigned dac, oct;
|
||||
// unsigned char vtarget_jtag[4];
|
||||
int prescale;
|
||||
double f;
|
||||
const char *unit;
|
||||
void *mycookie;
|
||||
// void *mycookie;
|
||||
|
||||
if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII) {
|
||||
return;
|
||||
|
|
@ -3963,10 +3978,10 @@ static int stk600_xprog_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
b[0] = XPRG_CMD_WRITE_MEM;
|
||||
b[1] = memcode;
|
||||
b[2] = 0; /* pagemode: non-paged write */
|
||||
b[3] = addr >> 24;
|
||||
b[4] = addr >> 16;
|
||||
b[5] = addr >> 8;
|
||||
b[6] = addr;
|
||||
b[3] = (char)(addr >> 24);
|
||||
b[4] = (char)(addr >> 16);
|
||||
b[5] = (char)(addr >> 8);
|
||||
b[6] = (char)addr;
|
||||
b[7] = 0;
|
||||
b[8] = write_size;
|
||||
b[9] = data;
|
||||
|
|
@ -4011,10 +4026,10 @@ static int stk600_xprog_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
addr += mem->offset;
|
||||
|
||||
b[0] = XPRG_CMD_READ_MEM;
|
||||
b[2] = addr >> 24;
|
||||
b[3] = addr >> 16;
|
||||
b[4] = addr >> 8;
|
||||
b[5] = addr;
|
||||
b[2] = (char)(addr >> 24);
|
||||
b[3] = (char)(addr >> 16);
|
||||
b[4] = (char)(addr >> 8);
|
||||
b[5] = (char)addr;
|
||||
b[6] = 0;
|
||||
b[7] = 1;
|
||||
if (stk600_xprog_command(pgm, b, 8, 3) < 0) {
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
|
|||
|
||||
maxsize = mem->size;
|
||||
|
||||
if (addr >= maxsize) {
|
||||
if (addr >= (unsigned long)maxsize) {
|
||||
if (argc == 2) {
|
||||
/* wrap around */
|
||||
addr = 0;
|
||||
|
|
@ -294,7 +294,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
|
|||
}
|
||||
|
||||
/* trim len if nessary to not read past the end of memory */
|
||||
if ((addr + len) > maxsize)
|
||||
if ((addr + len) > (unsigned long)maxsize)
|
||||
len = maxsize - addr;
|
||||
|
||||
buf = malloc(len);
|
||||
|
|
@ -303,7 +303,7 @@ static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
|
|||
return -1;
|
||||
}
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
for (i = 0; i < (unsigned long)len; i++) {
|
||||
rc = pgm->read_byte(pgm, p, mem, addr+i, &buf[i]);
|
||||
if (rc != 0) {
|
||||
avrdude_message(MSG_INFO, "error reading %s address 0x%05lx of part %s\n",
|
||||
|
|
@ -364,7 +364,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (addr > maxsize) {
|
||||
if (addr > (unsigned long)maxsize) {
|
||||
avrdude_message(MSG_INFO, "%s (write): address 0x%05lx is out of range for %s memory\n",
|
||||
progname, addr, memtype);
|
||||
return -1;
|
||||
|
|
@ -373,7 +373,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
|
|||
/* number of bytes to write at the specified address */
|
||||
len = argc - 3;
|
||||
|
||||
if ((addr + len) > maxsize) {
|
||||
if ((addr + len) > (unsigned long)maxsize) {
|
||||
avrdude_message(MSG_INFO, "%s (write): selected address and # bytes exceed "
|
||||
"range for %s memory\n",
|
||||
progname, memtype);
|
||||
|
|
@ -386,8 +386,8 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
|
|||
return -1;
|
||||
}
|
||||
|
||||
for (i=3; i<argc; i++) {
|
||||
buf[i-3] = strtoul(argv[i], &e, 0);
|
||||
for (i = 3; i < (unsigned long)argc; i++) {
|
||||
buf[i-3] = (char)strtoul(argv[i], &e, 0);
|
||||
if (*e || (e == argv[i])) {
|
||||
avrdude_message(MSG_INFO, "%s (write): can't parse byte \"%s\"\n",
|
||||
progname, argv[i]);
|
||||
|
|
@ -397,7 +397,7 @@ static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
|
|||
}
|
||||
|
||||
pgm->err_led(pgm, OFF);
|
||||
for (werror=0, i=0; i<len; i++) {
|
||||
for (werror = 0, i = 0; i < (unsigned long)len; i++) {
|
||||
|
||||
rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]);
|
||||
if (rc) {
|
||||
|
|
@ -462,7 +462,7 @@ static int cmd_send(PROGRAMMER * pgm, struct avrpart * p,
|
|||
|
||||
/* load command bytes */
|
||||
for (i=1; i<argc; i++) {
|
||||
cmd[i-1] = strtoul(argv[i], &e, 0);
|
||||
cmd[i-1] = (char)strtoul(argv[i], &e, 0);
|
||||
if (*e || (e == argv[i])) {
|
||||
avrdude_message(MSG_INFO, "%s (send): can't parse byte \"%s\"\n",
|
||||
progname, argv[i]);
|
||||
|
|
@ -789,7 +789,7 @@ static int tokenize(char * s, char *** argv)
|
|||
char * nbuf;
|
||||
char ** av;
|
||||
|
||||
slen = strlen(s);
|
||||
slen = (int)strlen(s);
|
||||
|
||||
/*
|
||||
* initialize allow for 20 arguments, use realloc to grow this if
|
||||
|
|
@ -812,7 +812,7 @@ static int tokenize(char * s, char *** argv)
|
|||
nexttok(r, &q, &r);
|
||||
strcpy(nbuf, q);
|
||||
bufv[n] = nbuf;
|
||||
len = strlen(q);
|
||||
len = (int)strlen(q);
|
||||
l += len + 1;
|
||||
nbuf += len + 1;
|
||||
nbuf[0] = 0;
|
||||
|
|
@ -841,7 +841,7 @@ static int tokenize(char * s, char *** argv)
|
|||
q = (char *)&av[n+1];
|
||||
memcpy(q, buf, l);
|
||||
for (i=0; i<n; i++) {
|
||||
offset = bufv[i] - buf;
|
||||
offset = (int)(bufv[i] - buf);
|
||||
av[i] = q + offset;
|
||||
}
|
||||
av[i] = NULL;
|
||||
|
|
@ -862,7 +862,7 @@ static int do_cmd(PROGRAMMER * pgm, struct avrpart * p,
|
|||
int hold;
|
||||
int len;
|
||||
|
||||
len = strlen(argv[0]);
|
||||
len = (int)strlen(argv[0]);
|
||||
hold = -1;
|
||||
for (i=0; i<NCMDS; i++) {
|
||||
if (strcasecmp(argv[0], cmd[i].name) == 0) {
|
||||
|
|
|
|||
|
|
@ -63,10 +63,15 @@ extern "C" {
|
|||
#define STDOUT_FILENO 1
|
||||
#define STDERR_FILENO 2
|
||||
|
||||
#if defined(_MSC_VER) && defined(__clang__)
|
||||
#include <stdint.h>
|
||||
struct timezone;
|
||||
struct timeval;
|
||||
#else
|
||||
#ifndef __cplusplus
|
||||
/* should be in some equivalent to <sys/types.h> */
|
||||
typedef __int8 int8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
|
|
@ -74,6 +79,7 @@ typedef unsigned __int16 uint16_t;
|
|||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
int usleep(unsigned usec);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ add_library(nowide STATIC
|
|||
nowide/windows.hpp
|
||||
)
|
||||
|
||||
target_include_directories(nowide SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(nowide PUBLIC boost_headeronly)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ protected:
|
|||
#ifndef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
return from - save_from;
|
||||
#else
|
||||
return save_max - max;
|
||||
return int(save_max - max);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
39
src/build-utils/CMakeLists.txt
Normal file
39
src/build-utils/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
add_executable(encoding-check encoding-check.cpp)
|
||||
|
||||
# A global no-op target which depends on all encodings checks,
|
||||
# and on which in turn all checked targets depend.
|
||||
# This is done to make encoding checks the first thing to be
|
||||
# performed before actually compiling any sources of the checked targets
|
||||
# to make the check fail as early as possible.
|
||||
add_custom_target(global-encoding-check
|
||||
ALL
|
||||
DEPENDS encoding-check
|
||||
)
|
||||
|
||||
# Function that adds source file encoding check to a target
|
||||
# using the above encoding-check binary
|
||||
|
||||
function(encoding_check TARGET)
|
||||
# Obtain target source files
|
||||
get_target_property(T_SOURCES ${TARGET} SOURCES)
|
||||
|
||||
# Define top-level encoding check target for this ${TARGET}
|
||||
add_custom_target(encoding-check-${TARGET}
|
||||
DEPENDS encoding-check ${T_SOURCES}
|
||||
COMMENT "Checking source files encodings for target ${TARGET}"
|
||||
)
|
||||
|
||||
# Add checking of each source file as a subcommand of encoding-check-${TARGET}
|
||||
foreach(file ${T_SOURCES})
|
||||
add_custom_command(TARGET encoding-check-${TARGET}
|
||||
COMMAND $<TARGET_FILE:encoding-check> ${TARGET} ${file}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
# This adds dependency on encoding-check-${TARGET} to ${TARET}
|
||||
# via the global-encoding-check
|
||||
add_dependencies(global-encoding-check encoding-check-${TARGET})
|
||||
add_dependencies(${TARGET} global-encoding-check)
|
||||
endfunction()
|
||||
119
src/build-utils/encoding-check.cpp
Normal file
119
src/build-utils/encoding-check.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
/*
|
||||
* The utf8_check() function scans the '\0'-terminated string starting
|
||||
* at s. It returns a pointer to the first byte of the first malformed
|
||||
* or overlong UTF-8 sequence found, or NULL if the string contains
|
||||
* only correct UTF-8. It also spots UTF-8 sequences that could cause
|
||||
* trouble if converted to UTF-16, namely surrogate characters
|
||||
* (U+D800..U+DFFF) and non-Unicode positions (U+FFFE..U+FFFF). This
|
||||
* routine is very likely to find a malformed sequence if the input
|
||||
* uses any other encoding than UTF-8. It therefore can be used as a
|
||||
* very effective heuristic for distinguishing between UTF-8 and other
|
||||
* encodings.
|
||||
*
|
||||
* I wrote this code mainly as a specification of functionality; there
|
||||
* are no doubt performance optimizations possible for certain CPUs.
|
||||
*
|
||||
* Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> -- 2005-03-30
|
||||
* License: http://www.cl.cam.ac.uk/~mgk25/short-license.html
|
||||
*/
|
||||
|
||||
unsigned char *utf8_check(unsigned char *s)
|
||||
{
|
||||
while (*s) {
|
||||
if (*s < 0x80) {
|
||||
// 0xxxxxxx
|
||||
s++;
|
||||
} else if ((s[0] & 0xe0) == 0xc0) {
|
||||
// 110xxxxx 10xxxxxx
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[0] & 0xfe) == 0xc0) { // overlong?
|
||||
return s;
|
||||
} else {
|
||||
s += 2;
|
||||
}
|
||||
} else if ((s[0] & 0xf0) == 0xe0) {
|
||||
// 1110xxxx 10xxxxxx 10xxxxxx
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[2] & 0xc0) != 0x80 ||
|
||||
(s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || // overlong?
|
||||
(s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || // surrogate?
|
||||
(s[0] == 0xef && s[1] == 0xbf &&
|
||||
(s[2] & 0xfe) == 0xbe)) { // U+FFFE or U+FFFF?
|
||||
return s;
|
||||
} else {
|
||||
s += 3;
|
||||
}
|
||||
} else if ((s[0] & 0xf8) == 0xf0) {
|
||||
// 11110xxX 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[2] & 0xc0) != 0x80 ||
|
||||
(s[3] & 0xc0) != 0x80 ||
|
||||
(s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || // overlong?
|
||||
(s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) { // > U+10FFFF?
|
||||
return s;
|
||||
} else {
|
||||
s += 4;
|
||||
}
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " <program/library> <file>" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* target = argv[1];
|
||||
const char* filename = argv[2];
|
||||
|
||||
const auto error_exit = [=](const char* error) {
|
||||
std::cerr << "\n\tError: " << error << ": " << filename << "\n"
|
||||
<< "\tTarget: " << target << "\n"
|
||||
<< std::endl;
|
||||
std::exit(-2);
|
||||
};
|
||||
|
||||
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||
const auto size = file.tellg();
|
||||
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
file.seekg(0, std::ios::beg);
|
||||
std::vector<char> buffer(size);
|
||||
|
||||
if (file.read(buffer.data(), size)) {
|
||||
buffer.push_back('\0');
|
||||
|
||||
// Check UTF-8 validity
|
||||
if (utf8_check(reinterpret_cast<unsigned char*>(buffer.data())) != nullptr) {
|
||||
error_exit("Source file does not contain (valid) UTF-8");
|
||||
}
|
||||
|
||||
// Check against a BOM mark
|
||||
if (buffer.size() >= 3
|
||||
&& buffer[0] == '\xef'
|
||||
&& buffer[1] == '\xbb'
|
||||
&& buffer[2] == '\xbf') {
|
||||
error_exit("Source file is valid UTF-8 but contains a BOM mark");
|
||||
}
|
||||
} else {
|
||||
error_exit("Could not read source file");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_SORTABLE_ROW_H
|
||||
#define IGL_SORTABLE_ROW_H
|
||||
|
||||
// Simple class to contain a rowvector which allows rowwise sorting and
|
||||
// reordering
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Templates:
|
||||
// T should be a matrix that implements .size(), and operator(int i)
|
||||
template <typename T>
|
||||
class SortableRow
|
||||
{
|
||||
public:
|
||||
T data;
|
||||
public:
|
||||
SortableRow():data(){};
|
||||
SortableRow(const T & data):data(data){};
|
||||
bool operator<(const SortableRow & that) const
|
||||
{
|
||||
// Get reference so that I can use parenthesis
|
||||
const SortableRow<T> & THIS = *this;
|
||||
// Lexicographical
|
||||
int minc = (THIS.data.size() < that.data.size()?
|
||||
THIS.data.size() : that.data.size());
|
||||
// loop over columns
|
||||
for(int i = 0;i<minc;i++)
|
||||
{
|
||||
if(THIS.data(i) == that.data(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return THIS.data(i) < that.data(i);
|
||||
}
|
||||
// All characters the same, comes done to length
|
||||
return THIS.data.size()<that.data.size();
|
||||
};
|
||||
bool operator==(const SortableRow & that) const
|
||||
{
|
||||
// Get reference so that I can use parenthesis
|
||||
const SortableRow<T> & THIS = *this;
|
||||
if(THIS.data.size() != that.data.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for(int i = 0;i<THIS.data.size();i++)
|
||||
{
|
||||
if(THIS.data(i) != that.data(i))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
bool operator!=(const SortableRow & that) const
|
||||
{
|
||||
return !(*this == that);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
14
src/libigl/CMakeLists.txt
Normal file
14
src/libigl/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
project(libigl)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
add_library(libigl INTERFACE)
|
||||
|
||||
find_package(libigl QUIET)
|
||||
|
||||
if(libigl_FOUND)
|
||||
message(STATUS "IGL found, using system version...")
|
||||
target_link_libraries(libigl INTERFACE igl::core)
|
||||
else()
|
||||
message(STATUS "IGL NOT found, using bundled version...")
|
||||
target_include_directories(libigl SYSTEM BEFORE INTERFACE ${LIBDIR}/libigl)
|
||||
endif()
|
||||
66
src/libigl/igl/SortableRow.h
Normal file
66
src/libigl/igl/SortableRow.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// This file is part of libigl, a simple c++ geometry processing library.
|
||||
//
|
||||
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public License
|
||||
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
// obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#ifndef IGL_SORTABLE_ROW_H
|
||||
#define IGL_SORTABLE_ROW_H
|
||||
|
||||
// Simple class to contain a rowvector which allows rowwise sorting and
|
||||
// reordering
|
||||
#include <Eigen/Core>
|
||||
|
||||
namespace igl
|
||||
{
|
||||
// Templates:
|
||||
// T should be a matrix that implements .size(), and operator(int i)
|
||||
template <typename T>
|
||||
class SortableRow
|
||||
{
|
||||
public:
|
||||
T data;
|
||||
public:
|
||||
SortableRow():data(){};
|
||||
SortableRow(const T & data):data(data){};
|
||||
bool operator<(const SortableRow & that) const
|
||||
{
|
||||
// Lexicographical
|
||||
int minc = (this->data.size() < that.data.size()?
|
||||
this->data.size() : that.data.size());
|
||||
// loop over columns
|
||||
for(int i = 0;i<minc;i++)
|
||||
{
|
||||
if(this->data(i) == that.data(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return this->data(i) < that.data(i);
|
||||
}
|
||||
// All characters the same, comes done to length
|
||||
return this->data.size()<that.data.size();
|
||||
};
|
||||
bool operator==(const SortableRow & that) const
|
||||
{
|
||||
if(this->data.size() != that.data.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for(int i = 0;i<this->data.size();i++)
|
||||
{
|
||||
if(this->data(i) != that.data(i))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
bool operator!=(const SortableRow & that) const
|
||||
{
|
||||
return !(*this == that);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue