Implement a command-line interface.
This commit adds a basic command-line interface. This interface allows rendering thumbnails and exporting data in batch mode.pull/36/merge
parent
dbc567ed89
commit
47244c5e89
|
@ -29,6 +29,7 @@ New rendering features:
|
|||
* The "Show/hide outlines" button is now independent from "Show/hide edges".
|
||||
|
||||
Other new features:
|
||||
* New command-line interface, for batch exporting and more.
|
||||
* New command for measuring total length of selected entities,
|
||||
"Analyze → Measure Perimeter".
|
||||
* New link to match the on-screen size of the sketch with its actual size,
|
||||
|
|
18
appveyor.yml
18
appveyor.yml
|
@ -9,28 +9,22 @@ before_build:
|
|||
- cmake -G"Visual Studio 12" -T v120 ..
|
||||
build_script:
|
||||
- msbuild "src\solvespace.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
- msbuild "test\solvespace_testsuite.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
- msbuild "src\solvespace-cli.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
- msbuild "test\solvespace-testsuite.vcxproj" /verbosity:minimal /property:Configuration=%BUILD_TYPE% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
test_script:
|
||||
- bin\%BUILD_TYPE%\solvespace_testsuite.exe
|
||||
- bin\%BUILD_TYPE%\solvespace-testsuite.exe
|
||||
artifacts:
|
||||
- path: build\bin\%BUILD_TYPE%\solvespace.exe
|
||||
name: solvespace.exe
|
||||
- path: build\bin\%BUILD_TYPE%\solvespace-cli.exe
|
||||
name: solvespace-cli.exe
|
||||
- path: build\bin\%BUILD_TYPE%\solvespace.pdb
|
||||
name: solvespace.pdb
|
||||
deploy:
|
||||
# Releases to solvespace/solvespace
|
||||
- provider: GitHub
|
||||
auth_token:
|
||||
secure: P9/pf2nM+jlWKe7pCjMp41HycBNP/+5AsmE/TETrDUoBOa/9WFHelqdVFrbRn9IC
|
||||
description: ""
|
||||
artifact: solvespace.exe
|
||||
on:
|
||||
appveyor_repo_tag: true
|
||||
# Releases to whitequark/solvespace (to be removed)
|
||||
- provider: GitHub
|
||||
auth_token:
|
||||
secure: Flqxu1cz6PyxVT1wzTP4bSrQOY8wFrO7pJxYxvjEkLqIUU4dsDQrs2rac/A9deet
|
||||
description: ""
|
||||
artifact: solvespace.exe
|
||||
artifact: solvespace.exe,solvespace-cli.exe,solvespace.pdb
|
||||
on:
|
||||
appveyor_repo_tag: true
|
||||
|
|
|
@ -5,12 +5,13 @@ foreach(pkg_config_lib CAIRO)
|
|||
link_directories(${${pkg_config_lib}_LIBRARY_DIRS})
|
||||
endforeach()
|
||||
|
||||
add_executable(solvespace_benchmark
|
||||
add_executable(solvespace-benchmark
|
||||
harness.cpp
|
||||
$<TARGET_PROPERTY:resources,EXTRA_SOURCES>)
|
||||
|
||||
target_link_libraries(solvespace_benchmark
|
||||
solvespace_headless)
|
||||
target_link_libraries(solvespace-benchmark
|
||||
solvespace-core
|
||||
solvespace-headless)
|
||||
|
||||
add_dependencies(solvespace_benchmark
|
||||
add_dependencies(solvespace-benchmark
|
||||
resources)
|
||||
|
|
|
@ -127,7 +127,7 @@ endif()
|
|||
|
||||
# solvespace library
|
||||
|
||||
set(solvespace_cad_HEADERS
|
||||
set(solvespace_core_HEADERS
|
||||
config.h
|
||||
dsc.h
|
||||
expr.h
|
||||
|
@ -139,7 +139,7 @@ set(solvespace_cad_HEADERS
|
|||
render/gl2shader.h
|
||||
srf/surface.h)
|
||||
|
||||
set(solvespace_cad_SOURCES
|
||||
set(solvespace_core_SOURCES
|
||||
bsp.cpp
|
||||
clipboard.cpp
|
||||
confscreen.cpp
|
||||
|
@ -186,16 +186,16 @@ set(solvespace_cad_SOURCES
|
|||
srf/surfinter.cpp
|
||||
srf/triangulate.cpp)
|
||||
|
||||
set(solvespace_cad_gl_SOURCES
|
||||
set(solvespace_core_gl_SOURCES
|
||||
export.cpp
|
||||
solvespace.cpp)
|
||||
|
||||
add_library(solvespace_cad STATIC
|
||||
add_library(solvespace-core STATIC
|
||||
${util_SOURCES}
|
||||
${solvespace_cad_HEADERS}
|
||||
${solvespace_cad_SOURCES})
|
||||
${solvespace_core_HEADERS}
|
||||
${solvespace_core_SOURCES})
|
||||
|
||||
target_link_libraries(solvespace_cad
|
||||
target_link_libraries(solvespace-core
|
||||
dxfrw
|
||||
${util_LIBRARIES}
|
||||
${ZLIB_LIBRARY}
|
||||
|
@ -203,13 +203,13 @@ target_link_libraries(solvespace_cad
|
|||
${FREETYPE_LIBRARY}
|
||||
${Backtrace_LIBRARIES})
|
||||
|
||||
target_compile_options(solvespace_cad
|
||||
target_compile_options(solvespace-core
|
||||
PRIVATE ${COVERAGE_FLAGS})
|
||||
|
||||
# solvespace gui executable
|
||||
# solvespace graphical executable
|
||||
|
||||
add_executable(solvespace WIN32 MACOSX_BUNDLE
|
||||
${solvespace_cad_gl_SOURCES}
|
||||
${solvespace_core_gl_SOURCES}
|
||||
${platform_SOURCES}
|
||||
$<TARGET_PROPERTY:resources,EXTRA_SOURCES>)
|
||||
|
||||
|
@ -217,69 +217,93 @@ add_dependencies(solvespace
|
|||
resources)
|
||||
|
||||
target_link_libraries(solvespace
|
||||
solvespace_cad
|
||||
solvespace-core
|
||||
${OPENGL_LIBRARIES}
|
||||
${platform_LIBRARIES}
|
||||
${COVERAGE_LIBRARY})
|
||||
|
||||
if(WIN32 AND NOT MINGW)
|
||||
if(MSVC)
|
||||
set_target_properties(solvespace PROPERTIES
|
||||
LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
foreach(lib ${platform_BUNDLED_LIBS})
|
||||
get_filename_component(name ${lib} NAME)
|
||||
set(target ${CMAKE_CURRENT_BINARY_DIR}/solvespace.app/Contents/MacOS/${name})
|
||||
|
||||
execute_process(COMMAND otool -D ${lib}
|
||||
OUTPUT_VARIABLE canonical_lib OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(REGEX REPLACE "^.+:\n" "" canonical_lib ${canonical_lib})
|
||||
add_custom_command(TARGET solvespace POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${lib} ${target}
|
||||
COMMAND install_name_tool -change ${canonical_lib} @executable_path/${name}
|
||||
$<TARGET_FILE:solvespace>
|
||||
COMMENT "Bundling shared library ${lib}"
|
||||
VERBATIM)
|
||||
endforeach()
|
||||
|
||||
set(bundle solvespace)
|
||||
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${bundle}.dmg
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_BINARY_DIR}/${bundle}.dmg
|
||||
COMMAND hdiutil create -srcfolder ${CMAKE_CURRENT_BINARY_DIR}/${bundle}.app
|
||||
${CMAKE_BINARY_DIR}/${bundle}.dmg
|
||||
DEPENDS $<TARGET_FILE:${bundle}>
|
||||
COMMENT "Building ${bundle}.dmg"
|
||||
VERBATIM)
|
||||
add_custom_target(${bundle}-dmg ALL
|
||||
DEPENDS ${CMAKE_BINARY_DIR}/${bundle}.dmg)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
install(TARGETS solvespace
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
BUNDLE DESTINATION .)
|
||||
endif()
|
||||
|
||||
# solvespace headless library
|
||||
|
||||
set(headless_SOURCES
|
||||
platform/headless.cpp
|
||||
render/rendercairo.cpp)
|
||||
|
||||
add_library(solvespace_headless STATIC EXCLUDE_FROM_ALL
|
||||
${solvespace_cad_gl_SOURCES}
|
||||
add_library(solvespace-headless STATIC EXCLUDE_FROM_ALL
|
||||
${solvespace_core_gl_SOURCES}
|
||||
${headless_SOURCES})
|
||||
|
||||
target_compile_definitions(solvespace_headless
|
||||
target_compile_definitions(solvespace-headless
|
||||
PRIVATE -DHEADLESS)
|
||||
|
||||
target_include_directories(solvespace_headless
|
||||
target_include_directories(solvespace-headless
|
||||
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(solvespace_headless
|
||||
solvespace_cad
|
||||
target_link_libraries(solvespace-headless
|
||||
solvespace-core
|
||||
${CAIRO_LIBRARIES})
|
||||
|
||||
target_compile_options(solvespace_headless
|
||||
target_compile_options(solvespace-headless
|
||||
PRIVATE ${COVERAGE_FLAGS})
|
||||
|
||||
# solvespace command-line executable
|
||||
|
||||
add_executable(solvespace-cli
|
||||
platform/climain.cpp
|
||||
$<TARGET_PROPERTY:resources,EXTRA_SOURCES>)
|
||||
|
||||
target_link_libraries(solvespace-cli
|
||||
solvespace-core
|
||||
solvespace-headless)
|
||||
|
||||
add_dependencies(solvespace-cli
|
||||
resources)
|
||||
|
||||
# solvespace unix package
|
||||
|
||||
if(NOT (WIN32 OR APPLE))
|
||||
install(TARGETS solvespace solvespace-cli
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
# solvespace macOS package
|
||||
|
||||
if(APPLE)
|
||||
set(bundle solvespace)
|
||||
set(bundle_bin ${EXECUTABLE_OUTPUT_PATH}/${bundle}.app/Contents/MacOS)
|
||||
|
||||
add_custom_command(TARGET solvespace POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:solvespace-cli> ${bundle_bin}
|
||||
COMMENT "Bundling executable solvespace-cli"
|
||||
VERBATIM)
|
||||
|
||||
foreach(lib ${platform_BUNDLED_LIBS})
|
||||
get_filename_component(name ${lib} NAME)
|
||||
|
||||
execute_process(COMMAND otool -D ${lib}
|
||||
OUTPUT_VARIABLE canonical_lib OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(REGEX REPLACE "^.+:\n" "" canonical_lib ${canonical_lib})
|
||||
add_custom_command(TARGET ${bundle} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${lib} ${bundle_bin}/${name}
|
||||
COMMAND install_name_tool -change ${canonical_lib} @executable_path/${name}
|
||||
$<TARGET_FILE:${bundle}>
|
||||
COMMAND install_name_tool -change ${canonical_lib} @executable_path/${name}
|
||||
$<TARGET_FILE:solvespace-cli>
|
||||
COMMENT "Bundling shared library ${lib}"
|
||||
VERBATIM)
|
||||
endforeach()
|
||||
|
||||
add_custom_command(OUTPUT ${EXECUTABLE_OUTPUT_PATH}/${bundle}.dmg
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${EXECUTABLE_OUTPUT_PATH}/${bundle}.dmg
|
||||
COMMAND hdiutil create -srcfolder ${EXECUTABLE_OUTPUT_PATH}/${bundle}.app
|
||||
${EXECUTABLE_OUTPUT_PATH}/${bundle}.dmg
|
||||
DEPENDS $<TARGET_FILE:${bundle}>
|
||||
COMMENT "Building ${bundle}.dmg"
|
||||
VERBATIM)
|
||||
add_custom_target(${bundle}-dmg ALL
|
||||
DEPENDS ${EXECUTABLE_OUTPUT_PATH}/${bundle}.dmg)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,317 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Our main() function for the command-line interface.
|
||||
//
|
||||
// Copyright 2016 whitequark
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "solvespace.h"
|
||||
|
||||
namespace SolveSpace {
|
||||
// These are defined in headless.cpp, and aren't exposed in solvespace.h.
|
||||
extern std::shared_ptr<Pixmap> framebuffer;
|
||||
}
|
||||
|
||||
static void ShowUsage(const char *argv0) {
|
||||
fprintf(stderr, "Usage: %s <command> <options> <filename> [filename...]", argv0);
|
||||
//-----------------------------------------------------------------------------> 80 col */
|
||||
fprintf(stderr, R"(
|
||||
When run, performs an action specified by <command> on every <filename>.
|
||||
|
||||
Common options:
|
||||
-o, --output <pattern>
|
||||
For an input file <basename>.slvs, replaces the '%%' symbol in <pattern>
|
||||
with <basename> and uses it as output file. For example, when using
|
||||
--output %%-2d.png for input files a.slvs and b.slvs, output files
|
||||
a-2d.png and b-2d.png will be written.
|
||||
-v, --view <direction>
|
||||
Selects the camera direction. <direction> can be one of "top", "bottom",
|
||||
"left", "right", "front", "back", or "isometric".
|
||||
-t, --chord-tol <tolerance>
|
||||
Selects the chord tolerance, used for converting exact curves to
|
||||
piecewise linear, and exact surfaces into triangle meshes.
|
||||
For export commands, the unit is mm, and the default is 1.0 mm.
|
||||
For non-export commands, the unit is %%, and the default is 1.0 %%.
|
||||
|
||||
Commands:
|
||||
thumbnail --output <pattern> --size <size> --view <direction>
|
||||
[--chord-tol <tolerance>]
|
||||
Outputs a rendered view of the sketch, like the SolveSpace GUI would.
|
||||
<size> is <width>x<height>, in pixels. Graphics acceleration is
|
||||
not used, and the output may look slightly different from the GUI.
|
||||
export-view --output <pattern> --view <direction> [--chord-tol <tolerance>]
|
||||
Exports a view of the sketch, in a 2d vector format.
|
||||
export-wireframe --output <pattern> [--chord-tol <tolerance>]
|
||||
Exports a wireframe of the sketch, in a 3d vector format.
|
||||
export-mesh --output <pattern> [--chord-tol <tolerance>]
|
||||
Exports a triangle mesh of solids in the sketch, with exact surfaces
|
||||
being triangulated first.
|
||||
export-surfaces --output <pattern>
|
||||
Exports exact surfaces of solids in the sketch, if any.
|
||||
)");
|
||||
|
||||
auto FormatListFromFileFilter = [](const FileFilter *filter) {
|
||||
std::string descr;
|
||||
while(filter->name) {
|
||||
descr += "\n ";
|
||||
descr += filter->name;
|
||||
descr += " (";
|
||||
const char *const *patterns = filter->patterns;
|
||||
while(*patterns) {
|
||||
descr += *patterns;
|
||||
if(*++patterns) {
|
||||
descr += ", ";
|
||||
}
|
||||
}
|
||||
descr += ")";
|
||||
filter++;
|
||||
}
|
||||
return descr;
|
||||
};
|
||||
|
||||
fprintf(stderr, R"(
|
||||
File formats:
|
||||
thumbnail:%s
|
||||
export-view:%s
|
||||
export-wireframe:%s
|
||||
export-mesh:%s
|
||||
export-surfaces:%s
|
||||
)", FormatListFromFileFilter(PngFileFilter).c_str(),
|
||||
FormatListFromFileFilter(VectorFileFilter).c_str(),
|
||||
FormatListFromFileFilter(Vector3dFileFilter).c_str(),
|
||||
FormatListFromFileFilter(MeshFileFilter).c_str(),
|
||||
FormatListFromFileFilter(SurfaceFileFilter).c_str());
|
||||
}
|
||||
|
||||
static bool RunCommand(size_t argc, char **argv) {
|
||||
if(argc < 2) return false;
|
||||
|
||||
std::function<void(const std::string &)> runner;
|
||||
|
||||
std::vector<std::string> inputFiles;
|
||||
auto ParseInputFile = [&](size_t &argn) {
|
||||
std::string arg = argv[argn];
|
||||
if(arg[0] != '-') {
|
||||
inputFiles.push_back(arg);
|
||||
return true;
|
||||
} else return false;
|
||||
};
|
||||
|
||||
std::string outputPattern;
|
||||
auto ParseOutputPattern = [&](size_t &argn) {
|
||||
if(argn + 1 < argc && (!strcmp(argv[argn], "--output") ||
|
||||
!strcmp(argv[argn], "-o"))) {
|
||||
argn++;
|
||||
outputPattern = argv[argn];
|
||||
return true;
|
||||
} else return false;
|
||||
};
|
||||
|
||||
Vector projUp, projRight;
|
||||
auto ParseViewDirection = [&](size_t &argn) {
|
||||
if(argn + 1 < argc && (!strcmp(argv[argn], "--view") ||
|
||||
!strcmp(argv[argn], "-v"))) {
|
||||
argn++;
|
||||
if(!strcmp(argv[argn], "top")) {
|
||||
projRight = Vector::From(1, 0, 0);
|
||||
projUp = Vector::From(0, 1, 0);
|
||||
} else if(!strcmp(argv[argn], "bottom")) {
|
||||
projRight = Vector::From(-1, 0, 0);
|
||||
projUp = Vector::From(0, 1, 0);
|
||||
} else if(!strcmp(argv[argn], "left")) {
|
||||
projRight = Vector::From(0, 1, 0);
|
||||
projUp = Vector::From(0, 0, 1);
|
||||
} else if(!strcmp(argv[argn], "right")) {
|
||||
projRight = Vector::From(0, -1, 0);
|
||||
projUp = Vector::From(0, 0, 1);
|
||||
} else if(!strcmp(argv[argn], "front")) {
|
||||
projRight = Vector::From(-1, 0, 0);
|
||||
projUp = Vector::From(0, 0, 1);
|
||||
} else if(!strcmp(argv[argn], "back")) {
|
||||
projRight = Vector::From(1, 0, 0);
|
||||
projUp = Vector::From(0, 0, 1);
|
||||
} else if(!strcmp(argv[argn], "isometric")) {
|
||||
projRight = Vector::From(0.707, 0.000, -0.707);
|
||||
projUp = Vector::From(-0.408, 0.816, -0.408);
|
||||
} else {
|
||||
fprintf(stderr, "Unrecognized view direction '%s'\n", argv[argn]);
|
||||
}
|
||||
return true;
|
||||
} else return false;
|
||||
};
|
||||
|
||||
double chordTol = 1.0;
|
||||
auto ParseChordTolerance = [&](size_t &argn) {
|
||||
if(argn + 1 < argc && (!strcmp(argv[argn], "--chord-tol") ||
|
||||
!strcmp(argv[argn], "-t"))) {
|
||||
argn++;
|
||||
if(sscanf(argv[argn], "%lf", &chordTol) == 1) {
|
||||
return true;
|
||||
} else return false;
|
||||
} else return false;
|
||||
};
|
||||
|
||||
if(!strcmp(argv[1], "thumbnail")) {
|
||||
unsigned width, height;
|
||||
auto ParseSize = [&](size_t &argn) {
|
||||
if(argn + 1 < argc && !strcmp(argv[argn], "--size")) {
|
||||
argn++;
|
||||
if(sscanf(argv[argn], "%ux%u", &width, &height) == 2) {
|
||||
return true;
|
||||
} else return false;
|
||||
} else return false;
|
||||
};
|
||||
|
||||
for(size_t argn = 2; argn < argc; argn++) {
|
||||
if(!(ParseInputFile(argn) ||
|
||||
ParseOutputPattern(argn) ||
|
||||
ParseViewDirection(argn) ||
|
||||
ParseChordTolerance(argn) ||
|
||||
ParseSize(argn))) {
|
||||
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(width == 0 || height == 0) {
|
||||
fprintf(stderr, "Non-zero viewport size must be specified.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(EXACT(projUp.Magnitude() == 0 || projRight.Magnitude() == 0)) {
|
||||
fprintf(stderr, "View direction must be specified.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
runner = [&](const std::string &output) {
|
||||
SS.GW.width = width;
|
||||
SS.GW.height = height;
|
||||
SS.GW.projRight = projRight;
|
||||
SS.GW.projUp = projUp;
|
||||
SS.chordTol = chordTol;
|
||||
|
||||
SS.GW.ZoomToFit(/*includingInvisibles=*/false);
|
||||
SS.GenerateAll();
|
||||
PaintGraphics();
|
||||
framebuffer->WritePng(output, /*flip=*/true);
|
||||
};
|
||||
} else if(!strcmp(argv[1], "export-view")) {
|
||||
for(size_t argn = 2; argn < argc; argn++) {
|
||||
if(!(ParseInputFile(argn) ||
|
||||
ParseOutputPattern(argn) ||
|
||||
ParseViewDirection(argn) ||
|
||||
ParseChordTolerance(argn))) {
|
||||
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(EXACT(projUp.Magnitude() == 0 || projRight.Magnitude() == 0)) {
|
||||
fprintf(stderr, "View direction must be specified.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
runner = [&](const std::string &output) {
|
||||
SS.GW.projRight = projRight;
|
||||
SS.GW.projUp = projUp;
|
||||
SS.exportChordTol = chordTol;
|
||||
|
||||
SS.ExportViewOrWireframeTo(output, /*exportWireframe=*/false);
|
||||
};
|
||||
} else if(!strcmp(argv[1], "export-wireframe")) {
|
||||
for(size_t argn = 2; argn < argc; argn++) {
|
||||
if(!(ParseInputFile(argn) ||
|
||||
ParseOutputPattern(argn) ||
|
||||
ParseChordTolerance(argn))) {
|
||||
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
runner = [&](const std::string &output) {
|
||||
SS.exportChordTol = chordTol;
|
||||
|
||||
SS.ExportViewOrWireframeTo(output, /*exportWireframe=*/true);
|
||||
};
|
||||
} else if(!strcmp(argv[1], "export-mesh")) {
|
||||
for(size_t argn = 2; argn < argc; argn++) {
|
||||
if(!(ParseInputFile(argn) ||
|
||||
ParseOutputPattern(argn) ||
|
||||
ParseChordTolerance(argn))) {
|
||||
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
runner = [&](const std::string &output) {
|
||||
SS.exportChordTol = chordTol;
|
||||
|
||||
SS.ExportMeshTo(output);
|
||||
};
|
||||
} else if(!strcmp(argv[1], "export-surfaces")) {
|
||||
for(size_t argn = 2; argn < argc; argn++) {
|
||||
if(!(ParseInputFile(argn) ||
|
||||
ParseOutputPattern(argn))) {
|
||||
fprintf(stderr, "Unrecognized option '%s'.\n", argv[argn]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
runner = [&](const std::string &output) {
|
||||
StepFileWriter sfw = {};
|
||||
sfw.ExportSurfacesTo(output);
|
||||
};
|
||||
} else {
|
||||
fprintf(stderr, "Unrecognized command '%s'.\n", argv[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(outputPattern.empty()) {
|
||||
fprintf(stderr, "An output pattern must be specified.\n");
|
||||
return false;
|
||||
} else if(outputPattern.find('%') == std::string::npos && inputFiles.size() > 1) {
|
||||
fprintf(stderr,
|
||||
"Output pattern must include a %% symbol when using multiple inputs!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(inputFiles.size() == 0) {
|
||||
fprintf(stderr, "At least one input file must be specified.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(const std::string &inputFile : inputFiles) {
|
||||
std::string outputFile = outputPattern;
|
||||
size_t replaceAt = outputFile.find('%');
|
||||
if(replaceAt != std::string::npos) {
|
||||
outputFile.replace(replaceAt, 1, Basename(inputFile, /*stripExtension=*/true));
|
||||
}
|
||||
|
||||
SS.Init();
|
||||
if(!SS.LoadFromFile(inputFile)) {
|
||||
fprintf(stderr, "Cannot load '%s'!\n", inputFile.c_str());
|
||||
return false;
|
||||
}
|
||||
SS.AfterNewFile();
|
||||
runner(outputFile);
|
||||
SK.Clear();
|
||||
SS.Clear();
|
||||
|
||||
fprintf(stderr, "Written '%s'.\n", outputFile.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
InitPlatform();
|
||||
|
||||
if(argc == 1) {
|
||||
ShowUsage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!RunCommand(argc, argv)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Our main() function for the headless (no OpenGL) test runner.
|
||||
// Our platform support functions for the headless (no OpenGL) test runner.
|
||||
//
|
||||
// Copyright 2016 whitequark
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -96,10 +96,8 @@ void ssremove(const std::string &filename)
|
|||
|
||||
static std::string ExpandPath(std::string path) {
|
||||
char *expanded_c_path = realpath(path.c_str(), NULL);
|
||||
if(expanded_c_path == NULL) {
|
||||
fprintf(stderr, "realpath(%s): %s\n", path.c_str(), strerror(errno));
|
||||
return "";
|
||||
}
|
||||
if(expanded_c_path == NULL) return "";
|
||||
|
||||
std::string expanded_path = expanded_c_path;
|
||||
free(expanded_c_path);
|
||||
return expanded_path;
|
||||
|
|
|
@ -182,7 +182,7 @@ const FileFilter SlvsFileFilter[] = {
|
|||
};
|
||||
// PNG format bitmap
|
||||
const FileFilter PngFileFilter[] = {
|
||||
{ "PNG", { "png" } },
|
||||
{ "PNG file", { "png" } },
|
||||
{ NULL, {} }
|
||||
};
|
||||
// Triangle mesh
|
||||
|
|
|
@ -57,19 +57,19 @@ set(testsuite_SOURCES
|
|||
group/translate_nd/test.cpp
|
||||
)
|
||||
|
||||
add_executable(solvespace_testsuite
|
||||
add_executable(solvespace-testsuite
|
||||
${testsuite_SOURCES}
|
||||
$<TARGET_PROPERTY:resources,EXTRA_SOURCES>)
|
||||
|
||||
target_link_libraries(solvespace_testsuite
|
||||
solvespace_headless
|
||||
target_link_libraries(solvespace-testsuite
|
||||
solvespace-headless
|
||||
${COVERAGE_LIBRARY})
|
||||
|
||||
add_dependencies(solvespace_testsuite
|
||||
add_dependencies(solvespace-testsuite
|
||||
resources)
|
||||
|
||||
add_custom_target(solvespace-test ALL
|
||||
COMMAND $<TARGET_FILE:solvespace_testsuite>
|
||||
add_custom_target(test_solvespace ALL
|
||||
COMMAND $<TARGET_FILE:solvespace-testsuite>
|
||||
COMMENT "Testing SolveSpace"
|
||||
VERBATIM)
|
||||
|
||||
|
@ -86,11 +86,11 @@ if(ENABLE_COVERAGE)
|
|||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/coverage_base.info
|
||||
COMMAND ${LCOV} ${LCOV_FLAGS} ${LCOV_COLLECT}
|
||||
-o ${CMAKE_BINARY_DIR}/coverage_base.info -i
|
||||
DEPENDS solvespace_testsuite
|
||||
DEPENDS solvespace-testsuite
|
||||
COMMENT "Importing baseline coverage data"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(solvespace-coverage ALL
|
||||
add_custom_target(coverage_solvespace ALL
|
||||
COMMAND ${LCOV} ${LCOV_FLAGS} ${LCOV_COLLECT}
|
||||
-o ${CMAKE_BINARY_DIR}/coverage_test.info
|
||||
COMMAND ${LCOV} ${LCOV_FLAGS}
|
||||
|
@ -104,7 +104,7 @@ if(ENABLE_COVERAGE)
|
|||
-o ${CMAKE_BINARY_DIR}/coverage/
|
||||
-t "SolveSpace testbench"
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/coverage_base.info
|
||||
DEPENDS solvespace-test
|
||||
DEPENDS test_solvespace
|
||||
COMMENT "Generating coverage report"
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh -ex
|
||||
|
||||
make -C build solvespace_testsuite
|
||||
./build/test/solvespace_testsuite $* || true
|
||||
make -C build solvespace-testsuite
|
||||
./build/test/solvespace-testsuite $* || true
|
||||
for e in slvs png; do
|
||||
for i in `find . -name *.out.$e`; do
|
||||
mv $i `dirname $i`/`basename $i .out.$e`.$e;
|
||||
|
|
|
@ -228,7 +228,7 @@ bool Test::Helper::CheckRender(const char *file, int line, const char *reference
|
|||
|
||||
std::shared_ptr<Pixmap> refPixmap = Pixmap::ReadPng(refPath.c_str(), /*flip=*/true);
|
||||
if(!RecordCheck(refPixmap && refPixmap->Equals(*framebuffer))) {
|
||||
framebuffer->WritePng(outPath.c_str(), /*flip=*/true);
|
||||
framebuffer->WritePng(outPath, /*flip=*/true);
|
||||
|
||||
if(!refPixmap) {
|
||||
PrintFailure(file, line, "reference render not present");
|
||||
|
|
Loading…
Reference in New Issue