Merge remote-tracking branch 'origin/master' into c++11
10
README.md
|
|
@ -86,16 +86,16 @@ libraries from aptitude. If you're using Mac, or an older Linux/BSD, there
|
|||
are build scripts that download and compile the libraries from source.
|
||||
Follow the instructions for the platform you're compiling on below.
|
||||
|
||||
* [Qt4 (4.4 - 5.2)](http://www.qt.nokia.com/)
|
||||
* [CGAL (3.6 - 4.1)](http://www.cgal.org/)
|
||||
* [Qt4 (4.4 - 5.3)](http://www.qt.nokia.com/)
|
||||
* [CGAL (3.6 - 4.4)](http://www.cgal.org/)
|
||||
* [GMP (5.x)](http://www.gmplib.org/)
|
||||
* [MPFR (3.x)](http://www.mpfr.org/)
|
||||
* [cmake (2.8, required by CGAL and the test framework)](http://www.cmake.org/)
|
||||
* [boost (1.35 - 1.55)](http://www.boost.org/)
|
||||
* [OpenCSG (1.3.2)](http://www.opencsg.org/)
|
||||
* [OpenCSG (1.3.2 ->)](http://www.opencsg.org/)
|
||||
* [GLEW (1.5.4 ->)](http://glew.sourceforge.net/)
|
||||
* [Eigen (3.0 - 3.2)](http://eigen.tuxfamily.org/)
|
||||
* [glib2 (2.2.0)](https://developer.gnome.org/glib/)
|
||||
* [Eigen (3.x)](http://eigen.tuxfamily.org/)
|
||||
* [glib2 (2.x)](https://developer.gnome.org/glib/)
|
||||
* [fontconfig (2.10)](http://fontconfig.org/)
|
||||
* [freetype2 (2.4)](http://freetype.org/)
|
||||
* [harfbuzz (0.9.19)](http://harfbuzz.org/)
|
||||
|
|
|
|||
|
|
@ -317,6 +317,7 @@ SOURCES += src/version_check.cc \
|
|||
src/ProgressWidget.cc \
|
||||
src/mathc99.cc \
|
||||
src/linalg.cc \
|
||||
src/Camera.cc \
|
||||
src/handle_dep.cc \
|
||||
src/value.cc \
|
||||
src/expr.cc \
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ if [[ $? != 0 ]]; then
|
|||
fi
|
||||
# Exclude tests known the cause issues on Travis
|
||||
# opencsgtest_rotate_extrude-tests - Fails on Ubuntu 12.04 using Gallium 0.4 drivers
|
||||
ctest -j8 -E opencsgtest_rotate_extrude-tests
|
||||
ctest -j8 -E "opencsgtest_rotate_extrude-tests|opencsgtest_render-tests"
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "Test failure"
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -113,3 +113,20 @@ void CGALRenderer::draw(bool showfaces, bool showedges) const
|
|||
this->polyhedron->draw(showfaces && showedges);
|
||||
}
|
||||
}
|
||||
|
||||
BoundingBox CGALRenderer::getBoundingBox() const
|
||||
{
|
||||
BoundingBox bbox;
|
||||
|
||||
if (this->polyhedron) {
|
||||
CGAL::Bbox_3 cgalbbox = this->polyhedron->bbox();
|
||||
bbox = BoundingBox(
|
||||
Vector3d(cgalbbox.xmin(), cgalbbox.ymin(), cgalbbox.zmin()),
|
||||
Vector3d(cgalbbox.xmax(), cgalbbox.ymax(), cgalbbox.zmax()) );
|
||||
}
|
||||
else if (this->polyset) {
|
||||
bbox = this->polyset->getBoundingBox();
|
||||
}
|
||||
|
||||
return bbox;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ class CGALRenderer : public Renderer
|
|||
{
|
||||
public:
|
||||
CGALRenderer(shared_ptr<const class Geometry> geom);
|
||||
~CGALRenderer();
|
||||
void draw(bool showfaces, bool showedges) const;
|
||||
virtual ~CGALRenderer();
|
||||
virtual void draw(bool showfaces, bool showedges) const;
|
||||
virtual BoundingBox getBoundingBox() const;
|
||||
|
||||
public:
|
||||
shared_ptr<class Polyhedron> polyhedron;
|
||||
|
|
|
|||
80
src/Camera.cc
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#include "Camera.h"
|
||||
#include "rendersettings.h"
|
||||
|
||||
Camera::Camera(enum CameraType camtype) :
|
||||
type(camtype), projection(Camera::PERSPECTIVE), fov(45), height(60), viewall(false)
|
||||
{
|
||||
if (this->type == Camera::GIMBAL) {
|
||||
object_trans << 0,0,0;
|
||||
object_rot << 35,0,25;
|
||||
viewer_distance = 500;
|
||||
} else if (this->type == Camera::VECTOR) {
|
||||
center << 0,0,0;
|
||||
Eigen::Vector3d cameradir(1, 1, -0.5);
|
||||
eye = center - 500 * cameradir;
|
||||
}
|
||||
pixel_width = RenderSettings::inst()->img_width;
|
||||
pixel_height = RenderSettings::inst()->img_height;
|
||||
}
|
||||
|
||||
void Camera::setup(std::vector<double> params)
|
||||
{
|
||||
if (params.size() == 7) {
|
||||
type = Camera::GIMBAL;
|
||||
object_trans << params[0], params[1], params[2];
|
||||
object_rot << params[3], params[4], params[5];
|
||||
viewer_distance = params[6];
|
||||
} else if (params.size() == 6) {
|
||||
type = Camera::VECTOR;
|
||||
eye << params[0], params[1], params[2];
|
||||
center << params[3], params[4], params[5];
|
||||
} else {
|
||||
assert("Gimbal cam needs 7 numbers, Vector camera needs 6");
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::gimbalDefaultTranslate()
|
||||
{ // match the GUI viewport numbers (historical reasons)
|
||||
object_trans.x() *= -1;
|
||||
object_trans.y() *= -1;
|
||||
object_trans.z() *= -1;
|
||||
object_rot.x() = fmodf(360 - object_rot.x() + 90, 360);
|
||||
object_rot.y() = fmodf(360 - object_rot.y(), 360);
|
||||
object_rot.z() = fmodf(360 - object_rot.z(), 360);
|
||||
}
|
||||
|
||||
/*!
|
||||
Moves camera so that the given bbox is fully visible.
|
||||
FIXME: The scalefactor is a temporary hack to be compatible with
|
||||
earlier ways of showing the whole scene.
|
||||
*/
|
||||
void Camera::viewAll(const BoundingBox &bbox, float scalefactor)
|
||||
{
|
||||
if (this->type == Camera::NONE) {
|
||||
this->type = Camera::VECTOR;
|
||||
this->center = bbox.center();
|
||||
this->eye = this->center - Vector3d(1,1,-0.5);
|
||||
}
|
||||
|
||||
switch (this->projection) {
|
||||
case Camera::ORTHOGONAL:
|
||||
this->height = bbox.diagonal().norm();
|
||||
break;
|
||||
case Camera::PERSPECTIVE: {
|
||||
double radius = bbox.diagonal().norm()/2;
|
||||
switch (this->type) {
|
||||
case Camera::GIMBAL:
|
||||
this->viewer_distance = radius / tan(this->fov*M_PI/360);
|
||||
break;
|
||||
case Camera::VECTOR: {
|
||||
Vector3d cameradir = (this->center - this->eye).normalized();
|
||||
this->eye = this->center - radius*scalefactor*cameradir;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false && "Camera type not specified");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
60
src/Camera.h
|
|
@ -16,61 +16,19 @@ projection, Perspective and Orthogonal.
|
|||
|
||||
*/
|
||||
|
||||
#include "linalg.h"
|
||||
#include <vector>
|
||||
#include <Eigen/Geometry>
|
||||
#include "rendersettings.h"
|
||||
|
||||
class Camera
|
||||
{
|
||||
public:
|
||||
enum CameraType { NONE, GIMBAL, VECTOR } type;
|
||||
enum ProjectionType { ORTHOGONAL, PERSPECTIVE } projection;
|
||||
Camera() {
|
||||
type = Camera::NONE;
|
||||
projection = Camera::PERSPECTIVE;
|
||||
}
|
||||
Camera( enum CameraType e )
|
||||
{
|
||||
type = e;
|
||||
if ( e == Camera::GIMBAL ) {
|
||||
object_trans << 0,0,0;
|
||||
object_rot << 35,0,25;
|
||||
viewer_distance = 500;
|
||||
} else if ( e == Camera::VECTOR ) {
|
||||
center << 0,0,0;
|
||||
Eigen::Vector3d cameradir(1, 1, -0.5);
|
||||
eye = center - 500 * cameradir;
|
||||
}
|
||||
pixel_width = RenderSettings::inst()->img_width;
|
||||
pixel_height = RenderSettings::inst()->img_height;
|
||||
projection = Camera::PERSPECTIVE;
|
||||
}
|
||||
|
||||
void setup( std::vector<double> params )
|
||||
{
|
||||
if ( params.size() == 7 ) {
|
||||
type = Camera::GIMBAL;
|
||||
object_trans << params[0], params[1], params[2];
|
||||
object_rot << params[3], params[4], params[5];
|
||||
viewer_distance = params[6];
|
||||
} else if ( params.size() == 6 ) {
|
||||
type = Camera::VECTOR;
|
||||
eye << params[0], params[1], params[2];
|
||||
center << params[3], params[4], params[5];
|
||||
} else {
|
||||
assert( "Gimbal cam needs 7 numbers, Vector camera needs 6" );
|
||||
}
|
||||
}
|
||||
|
||||
void gimbalDefaultTranslate()
|
||||
{ // match the GUI viewport numbers (historical reasons)
|
||||
object_trans.x() *= -1;
|
||||
object_trans.y() *= -1;
|
||||
object_trans.z() *= -1;
|
||||
object_rot.x() = fmodf(360 - object_rot.x() + 90, 360 );
|
||||
object_rot.y() = fmodf(360 - object_rot.y(), 360);
|
||||
object_rot.z() = fmodf(360 - object_rot.z(), 360);
|
||||
}
|
||||
Camera(enum CameraType camtype = NONE);
|
||||
void setup(std::vector<double> params);
|
||||
void gimbalDefaultTranslate();
|
||||
void viewAll(const BoundingBox &bbox, float scalefactor = 1.0f);
|
||||
|
||||
// Vectorcam
|
||||
Eigen::Vector3d eye;
|
||||
|
|
@ -82,6 +40,14 @@ public:
|
|||
Eigen::Vector3d object_rot;
|
||||
double viewer_distance;
|
||||
|
||||
// Perspective settings
|
||||
double fov; // Field of view
|
||||
|
||||
// Orthographic settings
|
||||
double height; // world-space height of viewport
|
||||
|
||||
bool viewall;
|
||||
|
||||
unsigned int pixel_width;
|
||||
unsigned int pixel_height;
|
||||
};
|
||||
|
|
|
|||
243
src/GLView.cc
|
|
@ -3,6 +3,7 @@
|
|||
#include "stdio.h"
|
||||
#include "rendersettings.h"
|
||||
#include "mathc99.h"
|
||||
#include "renderer.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <GL/wglew.h>
|
||||
|
|
@ -47,60 +48,107 @@ void GLView::resizeGL(int w, int h)
|
|||
cam.pixel_width = w;
|
||||
cam.pixel_height = h;
|
||||
glViewport(0, 0, w, h);
|
||||
w_h_ratio = sqrt((double)w / (double)h);
|
||||
aspectratio = 1.0*w/h;
|
||||
}
|
||||
|
||||
void GLView::setupGimbalCamPerspective()
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glFrustum(-w_h_ratio, +w_h_ratio, -(1/w_h_ratio), +(1/w_h_ratio), +10.0, +far_far_away);
|
||||
gluLookAt(0.0, -cam.viewer_distance, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
void GLView::setupGimbalCamOrtho(double distance, bool offset)
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
if (offset) glTranslated(-0.8, -0.8, 0);
|
||||
double l = distance/10;
|
||||
glOrtho(-w_h_ratio*l, +w_h_ratio*l,
|
||||
-(1/w_h_ratio)*l, +(1/w_h_ratio)*l,
|
||||
-far_far_away, +far_far_away);
|
||||
gluLookAt(0.0, -cam.viewer_distance, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
void GLView::setupVectorCamPerspective()
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
double dist = (cam.center - cam.eye).norm();
|
||||
gluPerspective(45, pow(w_h_ratio,2), 0.1*dist, 100*dist);
|
||||
}
|
||||
|
||||
void GLView::setupVectorCamOrtho(bool offset)
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
if (offset) glTranslated(-0.8, -0.8, 0);
|
||||
double l = (cam.center - cam.eye).norm() / 10;
|
||||
glOrtho(-pow(w_h_ratio,2)*l, +pow(w_h_ratio,2)*l,
|
||||
-(1/pow(w_h_ratio,2))*l, +(1/pow(w_h_ratio,2))*l,
|
||||
-far_far_away, +far_far_away);
|
||||
}
|
||||
|
||||
void GLView::setCamera( Camera &cam )
|
||||
void GLView::setCamera(const Camera &cam)
|
||||
{
|
||||
this->cam = cam;
|
||||
}
|
||||
|
||||
void GLView::setupCamera()
|
||||
{
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
switch (this->cam.type) {
|
||||
case Camera::GIMBAL:
|
||||
switch (this->cam.projection) {
|
||||
case Camera::PERSPECTIVE: {
|
||||
double dist = cam.viewer_distance;
|
||||
gluPerspective(cam.fov, aspectratio, 0.1*dist, 100*dist);
|
||||
break;
|
||||
}
|
||||
case Camera::ORTHOGONAL: {
|
||||
glOrtho(-cam.height/2*aspectratio, cam.height*aspectratio/2,
|
||||
-cam.height/2, cam.height/2,
|
||||
-far_far_away, +far_far_away);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gluLookAt(0.0, -cam.viewer_distance, 0.0,
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glRotated(cam.object_rot.x(), 1.0, 0.0, 0.0);
|
||||
glRotated(cam.object_rot.y(), 0.0, 1.0, 0.0);
|
||||
glRotated(cam.object_rot.z(), 0.0, 0.0, 1.0);
|
||||
glTranslated(cam.object_trans.x(), cam.object_trans.y(), cam.object_trans.z() );
|
||||
break;
|
||||
case Camera::VECTOR: {
|
||||
switch (this->cam.projection) {
|
||||
case Camera::PERSPECTIVE: {
|
||||
double dist = (cam.center - cam.eye).norm();
|
||||
gluPerspective(cam.fov, aspectratio, 0.1*dist, 100*dist);
|
||||
break;
|
||||
}
|
||||
case Camera::ORTHOGONAL: {
|
||||
glOrtho(-cam.height/2*aspectratio, cam.height*aspectratio/2,
|
||||
-cam.height/2, cam.height/2,
|
||||
-far_far_away, +far_far_away);
|
||||
break;
|
||||
}
|
||||
}
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
Vector3d dir(cam.eye - cam.center);
|
||||
Vector3d up(0.0,0.0,1.0);
|
||||
if (dir.cross(up).norm() < 0.001) { // View direction is ~parallel with up vector
|
||||
up << 0.0,1.0,0.0;
|
||||
}
|
||||
|
||||
gluLookAt(cam.eye[0], cam.eye[1], cam.eye[2],
|
||||
cam.center[0], cam.center[1], cam.center[2],
|
||||
up[0], up[1], up[2]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GLView::paintGL()
|
||||
{
|
||||
if (cam.type == Camera::GIMBAL) gimbalCamPaintGL();
|
||||
else if (cam.type == Camera::VECTOR) vectorCamPaintGL();
|
||||
else if (cam.type == Camera::NONE) {
|
||||
fprintf(stderr,"paintGL with null camera\n");
|
||||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
setupCamera();
|
||||
|
||||
Color4f bgcol = RenderSettings::inst()->color(RenderSettings::BACKGROUND_COLOR);
|
||||
glClearColor(bgcol[0], bgcol[1], bgcol[2], 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
// Only for GIMBAL cam
|
||||
if (showcrosshairs) GLView::showCrosshairs();
|
||||
if (showaxes) GLView::showAxes();
|
||||
|
||||
glDepthFunc(GL_LESS);
|
||||
glCullFace(GL_BACK);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glLineWidth(2);
|
||||
glColor3d(1.0, 0.0, 0.0);
|
||||
|
||||
if (this->renderer) {
|
||||
#if defined(ENABLE_OPENCSG)
|
||||
// FIXME: This belongs in the OpenCSG renderer, but it doesn't know about this ID yet
|
||||
OpenCSG::setContext(this->opencsg_id);
|
||||
#endif
|
||||
this->renderer->draw(showfaces, showedges);
|
||||
}
|
||||
|
||||
// Only for GIMBAL
|
||||
if (showaxes) GLView::showSmallaxes();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OPENCSG
|
||||
|
|
@ -279,86 +327,6 @@ void GLView::initializeGL()
|
|||
#endif
|
||||
}
|
||||
|
||||
void GLView::vectorCamPaintGL()
|
||||
{
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
if (cam.projection==Camera::ORTHOGONAL) setupVectorCamOrtho();
|
||||
else setupVectorCamPerspective();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glClearColor(1.0f, 1.0f, 0.92f, 1.0f);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
gluLookAt(cam.eye[0], cam.eye[1], cam.eye[2],
|
||||
cam.center[0], cam.center[1], cam.center[2],
|
||||
0.0, 0.0, 1.0);
|
||||
|
||||
// fixme - showcrosshairs doesnt work with vector camera
|
||||
// if (showcrosshairs) GLView::showCrosshairs();
|
||||
|
||||
if (showaxes) GLView::showAxes();
|
||||
|
||||
glDepthFunc(GL_LESS);
|
||||
glCullFace(GL_BACK);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glLineWidth(2);
|
||||
glColor3d(1.0, 0.0, 0.0);
|
||||
//FIXME showSmallAxes wont work with vector camera
|
||||
//if (showaxes) GLView::showSmallaxes();
|
||||
|
||||
if (this->renderer) {
|
||||
this->renderer->draw(showfaces, showedges);
|
||||
}
|
||||
}
|
||||
|
||||
void GLView::gimbalCamPaintGL()
|
||||
{
|
||||
glEnable(GL_LIGHTING);
|
||||
|
||||
if (cam.projection == Camera::ORTHOGONAL)
|
||||
GLView::setupGimbalCamOrtho(cam.viewer_distance);
|
||||
else
|
||||
GLView::setupGimbalCamPerspective();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
Color4f bgcol = RenderSettings::inst()->color(RenderSettings::BACKGROUND_COLOR);
|
||||
glClearColor(bgcol[0], bgcol[1], bgcol[2], 1.0);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
glRotated(cam.object_rot.x(), 1.0, 0.0, 0.0);
|
||||
glRotated(cam.object_rot.y(), 0.0, 1.0, 0.0);
|
||||
glRotated(cam.object_rot.z(), 0.0, 0.0, 1.0);
|
||||
|
||||
if (showcrosshairs) GLView::showCrosshairs();
|
||||
|
||||
glTranslated(cam.object_trans.x(), cam.object_trans.y(), cam.object_trans.z() );
|
||||
|
||||
if (showaxes) GLView::showAxes();
|
||||
|
||||
glDepthFunc(GL_LESS);
|
||||
glCullFace(GL_BACK);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glLineWidth(2);
|
||||
glColor3d(1.0, 0.0, 0.0);
|
||||
|
||||
if (this->renderer) {
|
||||
#if defined(ENABLE_OPENCSG)
|
||||
// FIXME: This belongs in the OpenCSG renderer, but it doesn't know about this ID yet
|
||||
OpenCSG::setContext(this->opencsg_id);
|
||||
#endif
|
||||
this->renderer->draw(showfaces, showedges);
|
||||
}
|
||||
// Small axis cross in the lower left corner
|
||||
if (showaxes) GLView::showSmallaxes();
|
||||
}
|
||||
|
||||
void GLView::showSmallaxes()
|
||||
{
|
||||
// Fixme - this doesnt work in Vector Camera mode
|
||||
|
|
@ -367,8 +335,18 @@ void GLView::showSmallaxes()
|
|||
// Small axis cross in the lower left corner
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
|
||||
GLView::setupGimbalCamOrtho(1000,true);
|
||||
|
||||
// Set up an orthographic projection of the axis cross in the corner
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glTranslatef(-0.8f, -0.8f, 0.0f);
|
||||
double scale = 90;
|
||||
glOrtho(-scale*dpi*aspectratio,scale*dpi*aspectratio,
|
||||
-scale*dpi,scale*dpi,
|
||||
-scale*dpi,scale*dpi);
|
||||
gluLookAt(0.0, -1.0, 0.0,
|
||||
0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glRotated(cam.object_rot.x(), 1.0, 0.0, 0.0);
|
||||
|
|
@ -436,10 +414,6 @@ void GLView::showSmallaxes()
|
|||
// FIXME - depends on gimbal camera 'viewer distance'.. how to fix this
|
||||
// for VectorCamera?
|
||||
glEnd();
|
||||
|
||||
//Restore perspective for next paint
|
||||
if(cam.projection==Camera::PERSPECTIVE)
|
||||
GLView::setupGimbalCamPerspective();
|
||||
}
|
||||
|
||||
void GLView::showAxes()
|
||||
|
|
@ -447,11 +421,10 @@ void GLView::showAxes()
|
|||
// FIXME: doesn't work under Vector Camera
|
||||
// Large gray axis cross inline with the model
|
||||
// FIXME: This is always gray - adjust color to keep contrast with background
|
||||
float dpi = this->getDPI();
|
||||
glLineWidth(1*dpi);
|
||||
glLineWidth(this->getDPI());
|
||||
glColor3d(0.5, 0.5, 0.5);
|
||||
glBegin(GL_LINES);
|
||||
double l = cam.viewer_distance*dpi/10;
|
||||
double l = cam.viewer_distance;
|
||||
glVertex3d(-l, 0, 0);
|
||||
glVertex3d(+l, 0, 0);
|
||||
glVertex3d(0, -l, 0);
|
||||
|
|
|
|||
17
src/GLView.h
|
|
@ -25,28 +25,21 @@ Some actions (showCrossHairs) only work properly on Gimbal Camera.
|
|||
#endif
|
||||
#include "system-gl.h"
|
||||
#include <iostream>
|
||||
#include "renderer.h"
|
||||
#include "Camera.h"
|
||||
|
||||
class GLView
|
||||
{
|
||||
public:
|
||||
GLView();
|
||||
void setRenderer(Renderer* r);
|
||||
void setRenderer(class Renderer* r);
|
||||
Renderer *getRenderer() const { return this->renderer; }
|
||||
|
||||
void initializeGL();
|
||||
void resizeGL(int w, int h);
|
||||
virtual void paintGL();
|
||||
|
||||
void setCamera( Camera &cam );
|
||||
|
||||
void setupGimbalCamPerspective();
|
||||
void setupGimbalCamOrtho(double distance, bool offset=false);
|
||||
void gimbalCamPaintGL();
|
||||
|
||||
void setupVectorCamPerspective();
|
||||
void setupVectorCamOrtho(bool offset=false);
|
||||
void vectorCamPaintGL();
|
||||
void setCamera(const Camera &cam);
|
||||
void setupCamera();
|
||||
|
||||
void showCrosshairs();
|
||||
void showAxes();
|
||||
|
|
@ -61,7 +54,7 @@ public:
|
|||
double far_far_away;
|
||||
size_t width;
|
||||
size_t height;
|
||||
double w_h_ratio;
|
||||
double aspectratio;
|
||||
bool orthomode;
|
||||
bool showaxes;
|
||||
bool showfaces;
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ private:
|
|||
void openFile(const QString &filename);
|
||||
void handleFileDrop(const QString &filename);
|
||||
void refreshDocument();
|
||||
void updateCamera();
|
||||
void updateTemporalVariables();
|
||||
bool fileChangedOnDisk();
|
||||
void compileTopLevelDocument();
|
||||
|
|
@ -202,6 +203,7 @@ public slots:
|
|||
void viewPerspective();
|
||||
void viewOrthogonal();
|
||||
void viewResetView();
|
||||
void viewAll();
|
||||
void hideConsole();
|
||||
void animateUpdateDocChanged();
|
||||
void animateUpdate();
|
||||
|
|
@ -224,6 +226,7 @@ private:
|
|||
|
||||
char const * afterCompileSlot;
|
||||
bool procevents;
|
||||
bool isClosing;
|
||||
class QTemporaryFile *tempFile;
|
||||
class ProgressWidget *progresswidget;
|
||||
class CGALWorker *cgalworker;
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>936</width>
|
||||
<height>34</height>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menu_File">
|
||||
|
|
@ -234,6 +234,7 @@
|
|||
<addaction name="viewActionBack"/>
|
||||
<addaction name="viewActionDiagonal"/>
|
||||
<addaction name="viewActionCenter"/>
|
||||
<addaction name="viewActionViewAll"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="viewActionZoomIn"/>
|
||||
<addaction name="viewActionZoomOut"/>
|
||||
|
|
@ -961,6 +962,11 @@
|
|||
<string>Ctrl+[</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="viewActionViewAll">
|
||||
<property name="text">
|
||||
<string>View All</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
|
|||
|
|
@ -147,3 +147,10 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo,
|
|||
}
|
||||
std::for_each(primitives.begin(), primitives.end(), del_fun<OpenCSG::Primitive>());
|
||||
}
|
||||
|
||||
BoundingBox OpenCSGRenderer::getBoundingBox() const
|
||||
{
|
||||
BoundingBox bbox;
|
||||
if (this->root_chain) bbox = this->root_chain->getBoundingBox();
|
||||
return bbox;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ class OpenCSGRenderer : public Renderer
|
|||
public:
|
||||
OpenCSGRenderer(class CSGChain *root_chain, CSGChain *highlights_chain,
|
||||
CSGChain *background_chain, GLint *shaderinfo);
|
||||
void draw(bool showfaces, bool showedges) const;
|
||||
virtual void draw(bool showfaces, bool showedges) const;
|
||||
virtual BoundingBox getBoundingBox() const;
|
||||
private:
|
||||
void renderCSGChain(class CSGChain *chain, GLint *shaderinfo,
|
||||
bool highlight, bool background) const;
|
||||
|
|
|
|||
|
|
@ -85,7 +85,16 @@ void QGLView::resetView()
|
|||
{
|
||||
cam.object_rot << 35, 0, -25;
|
||||
cam.object_trans << 0, 0, 0;
|
||||
cam.viewer_distance = 500;
|
||||
cam.viewer_distance = 140;
|
||||
}
|
||||
|
||||
void QGLView::viewAll()
|
||||
{
|
||||
if (Renderer *r = this->getRenderer()) {
|
||||
BoundingBox bbox = r->getBoundingBox();
|
||||
cam.object_trans = -bbox.center();
|
||||
cam.viewAll(r->getBoundingBox());
|
||||
}
|
||||
}
|
||||
|
||||
void QGLView::initializeGL()
|
||||
|
|
@ -147,17 +156,16 @@ void QGLView::display_opencsg_warning_dialog()
|
|||
void QGLView::resizeGL(int w, int h)
|
||||
{
|
||||
GLView::resizeGL(w,h);
|
||||
GLView::setupGimbalCamPerspective();
|
||||
}
|
||||
|
||||
void QGLView::paintGL()
|
||||
{
|
||||
GLView::gimbalCamPaintGL();
|
||||
GLView::paintGL();
|
||||
|
||||
if (statusLabel) {
|
||||
QString msg;
|
||||
|
||||
Camera nc( cam );
|
||||
Camera nc(cam);
|
||||
nc.gimbalDefaultTranslate();
|
||||
msg.sprintf("Viewport: translate = [ %.2f %.2f %.2f ], rotate = [ %.2f %.2f %.2f ], distance = %.2f",
|
||||
nc.object_trans.x(), nc.object_trans.y(), nc.object_trans.z(),
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ public:
|
|||
#endif
|
||||
bool save(const char *filename);
|
||||
void resetView();
|
||||
void viewAll();
|
||||
|
||||
public slots:
|
||||
void ZoomIn(void);
|
||||
|
|
|
|||
|
|
@ -123,3 +123,10 @@ void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool highlight,
|
|||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
BoundingBox ThrownTogetherRenderer::getBoundingBox() const
|
||||
{
|
||||
BoundingBox bbox;
|
||||
if (this->root_chain) bbox = this->root_chain->getBoundingBox();
|
||||
return bbox;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ class ThrownTogetherRenderer : public Renderer
|
|||
public:
|
||||
ThrownTogetherRenderer(class CSGChain *root_chain,
|
||||
CSGChain *highlights_chain, CSGChain *background_chain);
|
||||
void draw(bool showfaces, bool showedges) const;
|
||||
virtual void draw(bool showfaces, bool showedges) const;
|
||||
virtual BoundingBox getBoundingBox() const;
|
||||
private:
|
||||
void renderCSGChain(CSGChain *chain, bool highlight, bool background, bool showedges,
|
||||
bool fberror) const;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ Builtins::Builtins()
|
|||
Value zero3val(zero3);
|
||||
this->globalscope.assignments.push_back(Assignment("$vpt", boost::shared_ptr<Expression>(new Expression(zero3val))));
|
||||
this->globalscope.assignments.push_back(Assignment("$vpr", boost::shared_ptr<Expression>(new Expression(zero3val))));
|
||||
this->globalscope.assignments.push_back(Assignment("$vpd", boost::shared_ptr<Expression>(new Expression(500))));
|
||||
}
|
||||
|
||||
Builtins::~Builtins()
|
||||
|
|
|
|||
|
|
@ -13,11 +13,17 @@
|
|||
#include "cgalutils.h"
|
||||
#include "CGAL_Nef_polyhedron.h"
|
||||
|
||||
static void setupCamera(Camera &cam, const BoundingBox &bbox, float scalefactor)
|
||||
{
|
||||
if (cam.type == Camera::NONE) cam.viewall = true;
|
||||
if (cam.viewall) cam.viewAll(bbox, scalefactor);
|
||||
}
|
||||
|
||||
void export_png(const Geometry *root_geom, Camera &cam, std::ostream &output)
|
||||
{
|
||||
OffscreenView *glview;
|
||||
try {
|
||||
glview = new OffscreenView( cam.pixel_width, cam.pixel_height );
|
||||
glview = new OffscreenView(cam.pixel_width, cam.pixel_height);
|
||||
} catch (int error) {
|
||||
fprintf(stderr,"Can't create OpenGL OffscreenView. Code: %i.\n", error);
|
||||
return;
|
||||
|
|
@ -25,32 +31,16 @@ void export_png(const Geometry *root_geom, Camera &cam, std::ostream &output)
|
|||
shared_ptr<const Geometry> ptr(root_geom);
|
||||
CGALRenderer cgalRenderer(ptr);
|
||||
|
||||
BoundingBox bbox;
|
||||
if (cgalRenderer.polyhedron) {
|
||||
CGAL::Bbox_3 cgalbbox = cgalRenderer.polyhedron->bbox();
|
||||
bbox = BoundingBox(
|
||||
Vector3d(cgalbbox.xmin(), cgalbbox.ymin(), cgalbbox.zmin()),
|
||||
Vector3d(cgalbbox.xmax(), cgalbbox.ymax(), cgalbbox.zmax()) );
|
||||
}
|
||||
else if (cgalRenderer.polyset) {
|
||||
bbox = cgalRenderer.polyset->getBoundingBox();
|
||||
}
|
||||
BoundingBox bbox = cgalRenderer.getBoundingBox();
|
||||
setupCamera(cam, bbox, 3);
|
||||
|
||||
if (cam.type == Camera::NONE) {
|
||||
cam.type = Camera::VECTOR;
|
||||
cam.center = getBoundingCenter(bbox);
|
||||
double radius = getBoundingRadius(bbox);
|
||||
Vector3d cameradir(1, 1, -0.5);
|
||||
cam.eye = cam.center - radius*2*cameradir;
|
||||
}
|
||||
|
||||
glview->setCamera( cam );
|
||||
glview->setCamera(cam);
|
||||
glview->setRenderer(&cgalRenderer);
|
||||
glview->paintGL();
|
||||
glview->save(output);
|
||||
}
|
||||
|
||||
enum Previewer { OPENCSG, THROWN } previewer;
|
||||
enum Previewer { OPENCSG, THROWNTOGETHER } previewer;
|
||||
|
||||
#ifdef ENABLE_OPENCSG
|
||||
#include "OpenCSGRenderer.h"
|
||||
|
|
@ -58,16 +48,16 @@ enum Previewer { OPENCSG, THROWN } previewer;
|
|||
#endif
|
||||
#include "ThrownTogetherRenderer.h"
|
||||
|
||||
void export_png_preview_common( Tree &tree, Camera &cam, std::ostream &output, Previewer previewer = OPENCSG )
|
||||
void export_png_preview_common(Tree &tree, Camera &cam, std::ostream &output, Previewer previewer = OPENCSG)
|
||||
{
|
||||
CsgInfo csgInfo = CsgInfo();
|
||||
if ( !csgInfo.compile_chains( tree ) ) {
|
||||
if (!csgInfo.compile_chains(tree)) {
|
||||
fprintf(stderr,"Couldn't initialize CSG chains\n");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
csgInfo.glview = new OffscreenView( cam.pixel_width, cam.pixel_height );
|
||||
csgInfo.glview = new OffscreenView(cam.pixel_width, cam.pixel_height);
|
||||
} catch (int error) {
|
||||
fprintf(stderr,"Can't create OpenGL OffscreenView. Code: %i.\n", error);
|
||||
return;
|
||||
|
|
@ -76,39 +66,30 @@ void export_png_preview_common( Tree &tree, Camera &cam, std::ostream &output, P
|
|||
#ifdef ENABLE_OPENCSG
|
||||
OpenCSGRenderer openCSGRenderer(csgInfo.root_chain, csgInfo.highlights_chain, csgInfo.background_chain, csgInfo.glview->shaderinfo);
|
||||
#endif
|
||||
ThrownTogetherRenderer thrownTogetherRenderer( csgInfo.root_chain, csgInfo.highlights_chain, csgInfo.background_chain );
|
||||
ThrownTogetherRenderer thrownTogetherRenderer(csgInfo.root_chain, csgInfo.highlights_chain, csgInfo.background_chain);
|
||||
|
||||
if (cam.type == Camera::NONE) {
|
||||
cam.type = Camera::VECTOR;
|
||||
double radius = 1.0;
|
||||
if (csgInfo.root_chain) {
|
||||
BoundingBox bbox = csgInfo.root_chain->getBoundingBox();
|
||||
cam.center = (bbox.min() + bbox.max()) / 2;
|
||||
radius = (bbox.max() - bbox.min()).norm() / 2;
|
||||
}
|
||||
Vector3d cameradir(1, 1, -0.5);
|
||||
cam.eye = cam.center - radius*1.8*cameradir;
|
||||
}
|
||||
|
||||
csgInfo.glview->setCamera( cam );
|
||||
#ifdef ENABLE_OPENCSG
|
||||
if ( previewer == OPENCSG )
|
||||
csgInfo.glview->setRenderer( &openCSGRenderer );
|
||||
if (previewer == OPENCSG)
|
||||
csgInfo.glview->setRenderer(&openCSGRenderer);
|
||||
else
|
||||
#endif
|
||||
csgInfo.glview->setRenderer( &thrownTogetherRenderer );
|
||||
csgInfo.glview->setRenderer(&thrownTogetherRenderer);
|
||||
#ifdef ENABLE_OPENCSG
|
||||
OpenCSG::setContext( 0 );
|
||||
OpenCSG::setOption( OpenCSG::OffscreenSetting, OpenCSG::FrameBufferObject );
|
||||
BoundingBox bbox = csgInfo.glview->getRenderer()->getBoundingBox();
|
||||
setupCamera(cam, bbox, 2.7);
|
||||
|
||||
csgInfo.glview->setCamera(cam);
|
||||
OpenCSG::setContext(0);
|
||||
OpenCSG::setOption(OpenCSG::OffscreenSetting, OpenCSG::FrameBufferObject);
|
||||
#endif
|
||||
csgInfo.glview->paintGL();
|
||||
csgInfo.glview->save( output );
|
||||
csgInfo.glview->save(output);
|
||||
}
|
||||
|
||||
void export_png_with_opencsg(Tree &tree, Camera &cam, std::ostream &output)
|
||||
{
|
||||
#ifdef ENABLE_OPENCSG
|
||||
export_png_preview_common( tree, cam, output, OPENCSG );
|
||||
export_png_preview_common(tree, cam, output, OPENCSG);
|
||||
#else
|
||||
fprintf(stderr,"This openscad was built without OpenCSG support\n");
|
||||
#endif
|
||||
|
|
@ -116,8 +97,7 @@ void export_png_with_opencsg(Tree &tree, Camera &cam, std::ostream &output)
|
|||
|
||||
void export_png_with_throwntogether(Tree &tree, Camera &cam, std::ostream &output)
|
||||
{
|
||||
export_png_preview_common( tree, cam, output, THROWN );
|
||||
export_png_preview_common(tree, cam, output, THROWNTOGETHER);
|
||||
}
|
||||
|
||||
|
||||
#endif // ENABLE_CGAL
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ Highlighter::Highlighter(QTextDocument *parent)
|
|||
tokentypes["prim3d"] << "cube" << "cylinder" << "sphere" << "polyhedron";
|
||||
tokentypes["prim2d"] << "square" << "polygon" << "circle";
|
||||
tokentypes["import"] << "include" << "use" << "import_stl" << "import" << "import_dxf" << "dxf_dim" << "dxf_cross" << "surface";
|
||||
tokentypes["special"] << "$children" << "child" << "children" << "$fn" << "$fa" << "$fs" << "$t" << "$vpt" << "$vpr";
|
||||
tokentypes["special"] << "$children" << "child" << "children" << "$fn" << "$fa" << "$fs" << "$t" << "$vpt" << "$vpr" << "$vpd";
|
||||
tokentypes["extrude"] << "linear_extrude" << "rotate_extrude";
|
||||
tokentypes["bracket"] << "[" << "]" << "(" << ")";
|
||||
tokentypes["curlies"] << "{" << "}";
|
||||
|
|
|
|||
|
|
@ -46,18 +46,3 @@ bool matrix_contains_nan( const Transform3d &m )
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
double getBoundingRadius(BoundingBox bbox)
|
||||
{
|
||||
// FIXME: For eigen3, we can use bbox.diagonal().norm()/2;
|
||||
double radius = (bbox.max() - bbox.min()).norm() / 2;
|
||||
return radius; // 0;
|
||||
}
|
||||
|
||||
Vector3d getBoundingCenter(BoundingBox bbox)
|
||||
{
|
||||
// FIXME: For eigen3, we can use bbox.center();
|
||||
Vector3d center = (bbox.min() + bbox.max()) / 2;
|
||||
return center; // Vector3d(0,0,0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,9 +21,6 @@ bool matrix_contains_infinity( const Transform3d &m );
|
|||
bool matrix_contains_nan( const Transform3d &m );
|
||||
|
||||
BoundingBox operator*(const Transform3d &m, const BoundingBox &box);
|
||||
Vector3d getBoundingCenter(BoundingBox bbox);
|
||||
double getBoundingRadius(BoundingBox bbox);
|
||||
|
||||
|
||||
class Color4f : public Eigen::Vector4f
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "highlighter.h"
|
||||
#include "export.h"
|
||||
#include "builtin.h"
|
||||
#include "expression.h"
|
||||
#include "progress.h"
|
||||
#include "dxfdim.h"
|
||||
#include "AboutDialog.h"
|
||||
|
|
@ -204,6 +205,7 @@ MainWindow::MainWindow(const QString &filename)
|
|||
tval = 0;
|
||||
fps = 0;
|
||||
fsteps = 1;
|
||||
isClosing = false;
|
||||
|
||||
const QString importStatement = "import(\"%1\");\n";
|
||||
const QString surfaceStatement = "surface(\"%1\");\n";
|
||||
|
|
@ -370,6 +372,7 @@ MainWindow::MainWindow(const QString &filename)
|
|||
connect(this->viewActionDiagonal, SIGNAL(triggered()), this, SLOT(viewAngleDiagonal()));
|
||||
connect(this->viewActionCenter, SIGNAL(triggered()), this, SLOT(viewCenter()));
|
||||
connect(this->viewActionResetView, SIGNAL(triggered()), this, SLOT(viewResetView()));
|
||||
connect(this->viewActionViewAll, SIGNAL(triggered()), this, SLOT(viewAll()));
|
||||
connect(this->viewActionPerspective, SIGNAL(triggered()), this, SLOT(viewPerspective()));
|
||||
connect(this->viewActionOrthogonal, SIGNAL(triggered()), this, SLOT(viewOrthogonal()));
|
||||
connect(this->viewActionHide, SIGNAL(triggered()), this, SLOT(hideConsole()));
|
||||
|
|
@ -485,14 +488,10 @@ MainWindow::loadViewSettings(){
|
|||
} else {
|
||||
viewPerspective();
|
||||
}
|
||||
if (settings.value("view/hideConsole").toBool()) {
|
||||
viewActionHide->setChecked(true);
|
||||
hideConsole();
|
||||
}
|
||||
if (settings.value("view/hideEditor").toBool()) {
|
||||
editActionHide->setChecked(true);
|
||||
hideEditor();
|
||||
}
|
||||
viewActionHide->setChecked(settings.value("view/hideConsole").toBool());
|
||||
hideConsole();
|
||||
editActionHide->setChecked(settings.value("view/hideEditor").toBool());
|
||||
hideEditor();
|
||||
updateMdiMode(settings.value("advanced/mdi").toBool());
|
||||
updateUndockMode(settings.value("advanced/undockableWindows").toBool());
|
||||
}
|
||||
|
|
@ -1366,6 +1365,68 @@ void MainWindow::updateTemporalVariables()
|
|||
vpr.push_back(Value(fmodf(360 - qglview->cam.object_rot.y(), 360)));
|
||||
vpr.push_back(Value(fmodf(360 - qglview->cam.object_rot.z(), 360)));
|
||||
top_ctx.set_variable("$vpr", Value(vpr));
|
||||
|
||||
top_ctx.set_variable("$vpd", Value(qglview->cam.viewer_distance));
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Update the viewport camera by evaluating the special variables. If they
|
||||
* are assigned on top-level, the values are used to change the camera
|
||||
* rotation, translation and distance.
|
||||
*/
|
||||
void MainWindow::updateCamera()
|
||||
{
|
||||
if (!root_module)
|
||||
return;
|
||||
|
||||
bool camera_set = false;
|
||||
double tx = qglview->cam.object_trans.x();
|
||||
double ty = qglview->cam.object_trans.y();
|
||||
double tz = qglview->cam.object_trans.z();
|
||||
double rx = qglview->cam.object_rot.x();
|
||||
double ry = qglview->cam.object_rot.y();
|
||||
double rz = qglview->cam.object_rot.z();
|
||||
double d = qglview->cam.viewer_distance;
|
||||
BOOST_FOREACH(const Assignment &a, root_module->scope.assignments) {
|
||||
double x, y, z;
|
||||
if ("$vpr" == a.first) {
|
||||
const Value vpr = a.second.get()->evaluate(&top_ctx);
|
||||
if (vpr.getVec3(x, y, z)) {
|
||||
rx = x;
|
||||
ry = y;
|
||||
rz = z;
|
||||
camera_set = true;
|
||||
}
|
||||
} else if ("$vpt" == a.first) {
|
||||
const Value vpt = a.second.get()->evaluate(&top_ctx);
|
||||
if (vpt.getVec3(x, y, z)) {
|
||||
tx = x;
|
||||
ty = y;
|
||||
tz = z;
|
||||
camera_set = true;
|
||||
}
|
||||
} else if ("$vpd" == a.first) {
|
||||
const Value vpd = a.second.get()->evaluate(&top_ctx);
|
||||
if (vpd.type() == Value::NUMBER) {
|
||||
d = vpd.toDouble();
|
||||
camera_set = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (camera_set) {
|
||||
std::vector<double> params;
|
||||
params.push_back(tx);
|
||||
params.push_back(ty);
|
||||
params.push_back(tz);
|
||||
params.push_back(rx);
|
||||
params.push_back(ry);
|
||||
params.push_back(rz);
|
||||
params.push_back(d);
|
||||
qglview->cam.setup(params);
|
||||
qglview->updateGL();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -1413,6 +1474,7 @@ void MainWindow::compileTopLevelDocument()
|
|||
QFileInfo(this->fileName).absolutePath().toLocal8Bit(),
|
||||
false);
|
||||
|
||||
updateCamera();
|
||||
}
|
||||
|
||||
void MainWindow::checkAutoReload()
|
||||
|
|
@ -2080,8 +2142,17 @@ void MainWindow::viewResetView()
|
|||
this->qglview->updateGL();
|
||||
}
|
||||
|
||||
void MainWindow::viewAll()
|
||||
{
|
||||
this->qglview->viewAll();
|
||||
this->qglview->updateGL();
|
||||
}
|
||||
|
||||
void MainWindow::on_editorDock_visibilityChanged(bool visible)
|
||||
{
|
||||
if (isClosing) {
|
||||
return;
|
||||
}
|
||||
QSettings settings;
|
||||
settings.setValue("view/hideEditor", !visible);
|
||||
editActionHide->setChecked(!visible);
|
||||
|
|
@ -2090,6 +2161,9 @@ void MainWindow::on_editorDock_visibilityChanged(bool visible)
|
|||
|
||||
void MainWindow::on_consoleDock_visibilityChanged(bool visible)
|
||||
{
|
||||
if (isClosing) {
|
||||
return;
|
||||
}
|
||||
QSettings settings;
|
||||
settings.setValue("view/hideConsole", !visible);
|
||||
viewActionHide->setChecked(!visible);
|
||||
|
|
@ -2257,6 +2331,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
|||
delete this->tempFile;
|
||||
this->tempFile = NULL;
|
||||
}
|
||||
isClosing = true;
|
||||
event->accept();
|
||||
} else {
|
||||
event->ignore();
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ static void help(const char *progname)
|
|||
"%2%[ --version ] [ --info ] \\\n"
|
||||
"%2%[ --camera=translatex,y,z,rotx,y,z,dist | \\\n"
|
||||
"%2% --camera=eyex,y,z,centerx,y,z ] \\\n"
|
||||
"%2%[ --viewall ] \\\n"
|
||||
"%2%[ --imgsize=width,height ] [ --projection=(o)rtho|(p)ersp] \\\n"
|
||||
"%2%[ --render | --preview[=throwntogether] ] \\\n"
|
||||
"%2%[ --csglimit=num ]"
|
||||
|
|
@ -172,6 +173,10 @@ Camera get_camera( po::variables_map vm )
|
|||
camera.gimbalDefaultTranslate();
|
||||
}
|
||||
|
||||
if (vm.count("viewall")) {
|
||||
camera.viewall = true;
|
||||
}
|
||||
|
||||
if (vm.count("projection")) {
|
||||
string proj = vm["projection"].as<string>();
|
||||
if (proj=="o" || proj=="ortho" || proj=="orthogonal")
|
||||
|
|
@ -430,7 +435,6 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
|||
} else {
|
||||
export_png_with_opencsg(tree, camera, fstream);
|
||||
}
|
||||
PRINTB("Camera eye: %f %f %f\n", camera.eye[0] % camera.eye[1] % camera.eye[2]);
|
||||
fstream.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -609,6 +613,7 @@ int main(int argc, char **argv)
|
|||
("preview", po::value<string>(), "if exporting a png image, do an OpenCSG(default) or ThrownTogether preview")
|
||||
("csglimit", po::value<unsigned int>(), "if exporting a png image, stop rendering at the given number of CSG elements")
|
||||
("camera", po::value<string>(), "parameters for camera when exporting png")
|
||||
("viewall", "adjust camera to fit object")
|
||||
("imgsize", po::value<string>(), "=width,height for exporting png")
|
||||
("projection", po::value<string>(), "(o)rtho or (p)erspective when exporting png")
|
||||
("debug", po::value<string>(), "special debug info")
|
||||
|
|
@ -713,7 +718,7 @@ int main(int argc, char **argv)
|
|||
|
||||
currentdir = boosty::stringy(fs::current_path());
|
||||
|
||||
Camera camera = get_camera( vm );
|
||||
Camera camera = get_camera(vm);
|
||||
|
||||
// Initialize global visitors
|
||||
NodeCache nodecache;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
/*******************************************************************************
|
||||
* *
|
||||
* Author : Angus Johnson *
|
||||
* Version : 6.1.2 *
|
||||
* Date : 15 December 2013 *
|
||||
* Version : 6.1.3a *
|
||||
* Date : 22 January 2014 *
|
||||
* Website : http://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2013 *
|
||||
* Copyright : Angus Johnson 2010-2014 *
|
||||
* *
|
||||
* License: *
|
||||
* Use, modification & distribution is subject to Boost Software License Ver 1. *
|
||||
|
|
@ -491,7 +491,52 @@ bool PointIsVertex(const IntPoint &Pt, OutPt *pp)
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int PointInPolygon (const IntPoint& pt, OutPt* op)
|
||||
int PointInPolygon (const IntPoint &pt, const Path &path)
|
||||
{
|
||||
//returns 0 if false, +1 if true, -1 if pt ON polygon boundary
|
||||
//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
|
||||
int result = 0;
|
||||
size_t cnt = path.size();
|
||||
if (cnt < 3) return 0;
|
||||
IntPoint ip = path[0];
|
||||
for(size_t i = 1; i <= cnt; ++i)
|
||||
{
|
||||
IntPoint ipNext = (i == cnt ? path[0] : path[i]);
|
||||
if (ipNext.Y == pt.Y)
|
||||
{
|
||||
if ((ipNext.X == pt.X) || (ip.Y == pt.Y &&
|
||||
((ipNext.X > pt.X) == (ip.X < pt.X)))) return -1;
|
||||
}
|
||||
if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y))
|
||||
{
|
||||
if (ip.X >= pt.X)
|
||||
{
|
||||
if (ipNext.X > pt.X) result = 1 - result;
|
||||
else
|
||||
{
|
||||
double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) -
|
||||
(double)(ipNext.X - pt.X) * (ip.Y - pt.Y);
|
||||
if (!d) return -1;
|
||||
if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result;
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (ipNext.X > pt.X)
|
||||
{
|
||||
double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) -
|
||||
(double)(ipNext.X - pt.X) * (ip.Y - pt.Y);
|
||||
if (!d) return -1;
|
||||
if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result;
|
||||
}
|
||||
}
|
||||
}
|
||||
ip = ipNext;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
int PointInPolygon (const IntPoint &pt, OutPt *op)
|
||||
{
|
||||
//returns 0 if false, +1 if true, -1 if pt ON polygon boundary
|
||||
//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
|
||||
|
|
@ -534,7 +579,7 @@ int PointInPolygon (const IntPoint& pt, OutPt* op)
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool Poly2ContainsPoly1(OutPt* OutPt1, OutPt* OutPt2)
|
||||
bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
|
||||
{
|
||||
OutPt* op = OutPt1;
|
||||
do
|
||||
|
|
@ -1126,11 +1171,9 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
|
|||
catch(...)
|
||||
{
|
||||
delete [] edges;
|
||||
return false; //almost certainly a vertex has exceeded range
|
||||
throw; //range test fails
|
||||
}
|
||||
|
||||
TEdge *eStart = &edges[0];
|
||||
if (!Closed) eStart->Prev->OutIdx = Skip;
|
||||
|
||||
//2. Remove duplicate vertices, and (when closed) collinear edges ...
|
||||
TEdge *E = eStart, *eLoopStop = eStart;
|
||||
|
|
@ -1171,7 +1214,11 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!Closed) m_HasOpenPaths = true;
|
||||
if (!Closed)
|
||||
{
|
||||
m_HasOpenPaths = true;
|
||||
eStart->Prev->OutIdx = Skip;
|
||||
}
|
||||
|
||||
//3. Do second stage of edge initialization ...
|
||||
E = eStart;
|
||||
|
|
@ -1431,21 +1478,12 @@ void Clipper::ZFillFunction(TZFillCallback zFillFunc)
|
|||
//------------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
void Clipper::Clear()
|
||||
{
|
||||
if (m_edges.empty()) return; //avoids problems with ClipperBase destructor
|
||||
DisposeAllOutRecs();
|
||||
ClipperBase::Clear();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void Clipper::Reset()
|
||||
{
|
||||
ClipperBase::Reset();
|
||||
m_Scanbeam.clear();
|
||||
m_ActiveEdges = 0;
|
||||
m_SortedEdges = 0;
|
||||
DisposeAllOutRecs();
|
||||
LocalMinima* lm = m_MinimaList;
|
||||
while (lm)
|
||||
{
|
||||
|
|
@ -1469,6 +1507,7 @@ bool Clipper::Execute(ClipType clipType, Paths &solution,
|
|||
m_UsingPolyTree = false;
|
||||
bool succeeded = ExecuteInternal();
|
||||
if (succeeded) BuildResult(solution);
|
||||
DisposeAllOutRecs();
|
||||
m_ExecuteLocked = false;
|
||||
return succeeded;
|
||||
}
|
||||
|
|
@ -1485,6 +1524,7 @@ bool Clipper::Execute(ClipType clipType, PolyTree& polytree,
|
|||
m_UsingPolyTree = true;
|
||||
bool succeeded = ExecuteInternal();
|
||||
if (succeeded) BuildResult2(polytree);
|
||||
DisposeAllOutRecs();
|
||||
m_ExecuteLocked = false;
|
||||
return succeeded;
|
||||
}
|
||||
|
|
@ -2674,12 +2714,13 @@ void Clipper::PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam)
|
|||
//First, match up overlapping horizontal edges (eg when one polygon's
|
||||
//intermediate horz edge overlaps an intermediate horz edge of another, or
|
||||
//when one polygon sits on top of another) ...
|
||||
for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i)
|
||||
{
|
||||
Join* j = m_GhostJoins[i];
|
||||
if (HorzSegmentsOverlap(j->OutPt1->Pt, j->OffPt, horzEdge->Bot, horzEdge->Top))
|
||||
AddJoin(j->OutPt1, outPt, j->OffPt);
|
||||
}
|
||||
//for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i)
|
||||
//{
|
||||
// Join* j = m_GhostJoins[i];
|
||||
// if (HorzSegmentsOverlap(j->OutPt1->Pt, j->OffPt, horzEdge->Bot, horzEdge->Top))
|
||||
// AddJoin(j->OutPt1, outPt, j->OffPt);
|
||||
//}
|
||||
|
||||
//Also, since horizontal edges at the top of one SB are often removed from
|
||||
//the AEL before we process the horizontal edges at the bottom of the next,
|
||||
//we need to create 'ghost' Join records of 'contrubuting' horizontals that
|
||||
|
|
@ -4255,6 +4296,15 @@ void ReversePaths(Paths& p)
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType)
|
||||
{
|
||||
Clipper c;
|
||||
c.StrictlySimple(true);
|
||||
c.AddPath(in_poly, ptSubject, true);
|
||||
c.Execute(ctUnion, out_polys, fillType, fillType);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType)
|
||||
{
|
||||
Clipper c;
|
||||
|
|
@ -4428,8 +4478,8 @@ void Minkowski(const Path& poly, const Path& path,
|
|||
|
||||
Paths quads;
|
||||
quads.reserve((pathCnt + delta) * (polyCnt + 1));
|
||||
for (size_t i = 0; i <= pathCnt - 2 + delta; ++i)
|
||||
for (size_t j = 0; j <= polyCnt - 1; ++j)
|
||||
for (size_t i = 0; i < pathCnt - 1 + delta; ++i)
|
||||
for (size_t j = 0; j < polyCnt; ++j)
|
||||
{
|
||||
Path quad;
|
||||
quad.reserve(4);
|
||||
|
|
@ -4447,15 +4497,30 @@ void Minkowski(const Path& poly, const Path& path,
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void MinkowskiSum(const Path& poly, const Path& path, Paths& solution, bool isClosed)
|
||||
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed)
|
||||
{
|
||||
Minkowski(poly, path, solution, true, isClosed);
|
||||
Minkowski(pattern, path, solution, true, pathIsClosed);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void MinkowskiDiff(const Path& poly, const Path& path, Paths& solution, bool isClosed)
|
||||
void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution,
|
||||
PolyFillType pathFillType, bool pathIsClosed)
|
||||
{
|
||||
Minkowski(poly, path, solution, false, isClosed);
|
||||
Clipper c;
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
{
|
||||
Paths tmp;
|
||||
Minkowski(pattern, paths[i], tmp, true, pathIsClosed);
|
||||
c.AddPaths(tmp, ptSubject, true);
|
||||
}
|
||||
if (pathIsClosed) c.AddPaths(paths, ptClip, true);
|
||||
c.Execute(ctUnion, solution, pathFillType, pathFillType);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution)
|
||||
{
|
||||
Minkowski(poly1, poly2, solution, false, true);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
/*******************************************************************************
|
||||
* *
|
||||
* Author : Angus Johnson *
|
||||
* Version : 6.1.2 *
|
||||
* Date : 15 December 2013 *
|
||||
* Version : 6.1.3a *
|
||||
* Date : 22 January 2014 *
|
||||
* Website : http://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2013 *
|
||||
* Copyright : Angus Johnson 2010-2014 *
|
||||
* *
|
||||
* License: *
|
||||
* Use, modification & distribution is subject to Boost Software License Ver 1. *
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
#ifndef clipper_hpp
|
||||
#define clipper_hpp
|
||||
|
||||
#define CLIPPER_VERSION "6.1.2"
|
||||
#define CLIPPER_VERSION "6.1.3"
|
||||
|
||||
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
|
||||
//improve performance but coordinate values are limited to the range +/- 46340
|
||||
|
|
@ -166,6 +166,7 @@ private:
|
|||
|
||||
bool Orientation(const Path &poly);
|
||||
double Area(const Path &poly);
|
||||
int PointInPolygon(const IntPoint &pt, const Path &path);
|
||||
|
||||
#ifdef use_deprecated
|
||||
void OffsetPaths(const Paths &in_polys, Paths &out_polys,
|
||||
|
|
@ -181,8 +182,10 @@ void CleanPolygon(Path& poly, double distance = 1.415);
|
|||
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415);
|
||||
void CleanPolygons(Paths& polys, double distance = 1.415);
|
||||
|
||||
void MinkowskiSum(const Path& poly, const Path& path, Paths& solution, bool isClosed);
|
||||
void MinkowskiDiff(const Path& poly, const Path& path, Paths& solution, bool isClosed);
|
||||
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
|
||||
void MinkowskiSum(const Path& pattern, const Paths& paths,
|
||||
Paths& solution, PolyFillType pathFillType, bool pathIsClosed);
|
||||
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);
|
||||
|
||||
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
|
||||
void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths);
|
||||
|
|
@ -259,7 +262,6 @@ public:
|
|||
PolyTree &polytree,
|
||||
PolyFillType subjFillType = pftEvenOdd,
|
||||
PolyFillType clipFillType = pftEvenOdd);
|
||||
void Clear();
|
||||
bool ReverseSolution() {return m_ReverseOutput;};
|
||||
void ReverseSolution(bool value) {m_ReverseOutput = value;};
|
||||
bool StrictlySimple() {return m_StrictSimple;};
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ class Renderer
|
|||
public:
|
||||
virtual ~Renderer() {}
|
||||
virtual void draw(bool showfaces, bool showedges) const = 0;
|
||||
|
||||
virtual BoundingBox getBoundingBox() const = 0;
|
||||
|
||||
#define CSGMODE_DIFFERENCE_FLAG 0x10
|
||||
enum csgmode_e {
|
||||
CSGMODE_NONE = 0x00,
|
||||
|
|
|
|||
|
|
@ -138,7 +138,6 @@ if(${CMAKE_CXX_COMPILER} MATCHES ".*clang.*")
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-variable")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++11-extensions")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sign-compare")
|
||||
endif()
|
||||
|
||||
|
|
@ -153,27 +152,34 @@ function(inclusion user_set_path found_paths)
|
|||
# their set_paths to be a priority.
|
||||
|
||||
if (DEBUG_OSCD)
|
||||
message(STATUS "inclusion ${user_set_path} ${found_paths}")
|
||||
message(STATUS "inclusion ${${user_set_path}} ${${found_paths}}")
|
||||
message(STATUS "inclusion:")
|
||||
message(STATUS " ${user_set_path}: ${${user_set_path}}")
|
||||
message(STATUS " ${found_paths}: ${${found_paths}}")
|
||||
endif()
|
||||
set( inclusion_match 0 )
|
||||
foreach( found_path ${${found_paths}} )
|
||||
if (${found_path} MATCHES ${${user_set_path}}.*)
|
||||
set( inclusion_match 1 )
|
||||
set(inclusion_match 0)
|
||||
if (${user_set_path})
|
||||
foreach(found_path ${${found_paths}})
|
||||
string(FIND ${found_path} ${${user_set_path}} INDEX)
|
||||
if (DEFINED INDEX)
|
||||
if (${INDEX} EQUAL 0)
|
||||
set(inclusion_match 1)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
if (inclusion_match)
|
||||
include_directories(BEFORE ${${found_paths}})
|
||||
if (DEBUG_OSCD)
|
||||
message(STATUS "inclusion prepend ${${found_paths}} for ${user_set_path}")
|
||||
endif()
|
||||
set(inclusion_match 0)
|
||||
endif()
|
||||
endforeach()
|
||||
if (user_set_path AND inclusion_match)
|
||||
include_directories(BEFORE ${${found_paths}})
|
||||
if (DEBUG_OSCD)
|
||||
message(STATUS "inclusion prepend ${${found_paths}} for ${user_set_path}")
|
||||
endif()
|
||||
else()
|
||||
endif()
|
||||
if (NOT inclusion_match)
|
||||
include_directories(AFTER ${${found_paths}})
|
||||
if (DEBUG_OSCD)
|
||||
message(STATUS "inclusion append ${${found_paths}} for ${user_set_path}")
|
||||
endif()
|
||||
endif()
|
||||
set( inclusion_match 0 )
|
||||
endfunction()
|
||||
|
||||
# Boost
|
||||
|
|
@ -208,14 +214,26 @@ if (NOT $ENV{BOOSTDIR} STREQUAL "")
|
|||
endif()
|
||||
|
||||
find_package( Boost 1.35.0 COMPONENTS thread program_options filesystem system regex REQUIRED)
|
||||
message(STATUS "Boost includes found: " ${Boost_INCLUDE_DIRS})
|
||||
message(STATUS "Boost ${Boost_VERSION} includes found: " ${Boost_INCLUDE_DIRS})
|
||||
message(STATUS "Boost libraries found:")
|
||||
foreach(boostlib ${Boost_LIBRARIES})
|
||||
message(STATUS " " ${boostlib})
|
||||
endforeach()
|
||||
|
||||
inclusion(BOOST_ROOT Boost_INCLUDE_DIRS)
|
||||
add_definitions(-DBOOST_FILESYSTEM_VERSION=3) # Use V3 for boost 1.44-1.45
|
||||
if (${Boost_VERSION} LESS 104600)
|
||||
add_definitions(-DBOOST_FILESYSTEM_VERSION=3) # Use V3 for boost 1.44-1.45
|
||||
endif()
|
||||
|
||||
# On Mac, we need to link against the correct C++ library. We choose the same one
|
||||
# as Boost uses.
|
||||
if(APPLE)
|
||||
execute_process(COMMAND grep -q __112basic_string ${Boost_LIBRARIES}
|
||||
RESULT_VARIABLE BOOST_USE_STDLIBCPP)
|
||||
if (NOT BOOST_USE_STDLIBCPP)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Mac OS X
|
||||
if(APPLE)
|
||||
|
|
@ -570,6 +588,7 @@ set(CORE_SOURCES
|
|||
../src/parsersettings.cc
|
||||
../src/mathc99.cc
|
||||
../src/linalg.cc
|
||||
../src/Camera.cc
|
||||
../src/handle_dep.cc
|
||||
../src/value.cc
|
||||
../src/calc.cc
|
||||
|
|
@ -1095,7 +1114,7 @@ add_cmdline_test(dumptest EXE ${OPENSCAD_BINPATH} ARGS -o SUFFIX csg FILES ${DUM
|
|||
add_cmdline_test(dumptest-examples EXE ${OPENSCAD_BINPATH} ARGS -o SUFFIX csg FILES ${EXAMPLE_FILES})
|
||||
add_cmdline_test(cgalpngtest EXE ${OPENSCAD_BINPATH} ARGS --render -o SUFFIX png FILES ${CGALPNGTEST_FILES})
|
||||
add_cmdline_test(opencsgtest EXE ${OPENSCAD_BINPATH} ARGS -o SUFFIX png FILES ${OPENCSGTEST_FILES})
|
||||
add_cmdline_test(csgpngtest EXE ${PYTHON_EXECUTABLE} SCRIPT csg-import-test.py ARGS ${OPENSCAD_BINPATH} EXPECTEDDIR cgalpngtest SUFFIX png FILES ${CGALPNGTEST_FILES})
|
||||
add_cmdline_test(csgpngtest EXE ${PYTHON_EXECUTABLE} SCRIPT ${CMAKE_SOURCE_DIR}/export_import_pngtest.py ARGS --openscad=${OPENSCAD_BINPATH} --format=csg EXPECTEDDIR cgalpngtest SUFFIX png FILES ${CGALPNGTEST_FILES})
|
||||
add_cmdline_test(throwntogethertest EXE ${OPENSCAD_BINPATH} ARGS --preview=throwntogether -o SUFFIX png FILES ${THROWNTOGETHERTEST_FILES})
|
||||
# FIXME: We don't actually need to compare the output of cgalstlsanitytest
|
||||
# with anything. It's self-contained and returns != 0 on error
|
||||
|
|
@ -1148,36 +1167,64 @@ add_cmdline_test(openscad-imgstretch2 EXE ${OPENSCAD_BINPATH}
|
|||
ARGS --imgsize 100,500 -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Perspective gimbal cam
|
||||
add_cmdline_test(openscad-camdist EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=0,0,0,90,0,90,300 -o
|
||||
ARGS --imgsize=500,500 --camera=0,0,0,90,0,90,100 -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Perspective gimbal cam
|
||||
add_cmdline_test(openscad-camrot EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=0,0,0,440,337.5,315,300 -o
|
||||
ARGS --imgsize=500,500 --camera=0,0,0,440,337.5,315,100 -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Perspective gimbal cam
|
||||
add_cmdline_test(openscad-camtrans EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=100,-20,-10,90,0,90,300 -o
|
||||
ARGS --imgsize=500,500 --camera=100,-20,-10,90,0,90,100 -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Perspective gimbal cam, viewall
|
||||
add_cmdline_test(openscad-camtrans-viewall EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=100,-20,-10,90,0,90,3000 --viewall -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Orthographic gimbal cam
|
||||
add_cmdline_test(openscad-camortho EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=100,-20,-10,90,0,90,300 --projection=o -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Orthographic gimbal cam viewall
|
||||
add_cmdline_test(openscad-camortho-viewall EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=100,-20,-10,90,0,90,3000 --viewall --projection=o -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Perspective vector cam
|
||||
add_cmdline_test(openscad-cameye EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=60,40,30,0,0,0 -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Perspective vector cam
|
||||
add_cmdline_test(openscad-cameye2 EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=160,140,130,0,0,0 -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Perspective vector cam
|
||||
add_cmdline_test(openscad-camcenter EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=60,40,30,20,10,30 -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Perspective vector cam viewall
|
||||
add_cmdline_test(openscad-camcenter-viewall EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=60,40,30,20,10,30 --viewall -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
# Orthographic vector cam
|
||||
add_cmdline_test(openscad-cameyeortho EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=160,140,130,0,0,0 --projection=o -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
add_cmdline_test(openscad-camcenter EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=60,40,30,20,10,30 -o
|
||||
# Orthographic vector cam viewall
|
||||
add_cmdline_test(openscad-cameyeortho-viewall EXE ${OPENSCAD_BINPATH}
|
||||
ARGS --imgsize=500,500 --camera=16,14,13,0,0,0 --viewall --projection=o -o
|
||||
SUFFIX png
|
||||
FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/camera-tests.scad)
|
||||
|
||||
|
|
@ -1187,3 +1234,5 @@ message("Available test configurations: ${TEST_CONFIGS}")
|
|||
#foreach(CONF ${TEST_CONFIGS})
|
||||
# message("${CONF}: ${${CONF}_TEST_CONFIG}")
|
||||
#endforeach()
|
||||
|
||||
message("CPPFLAGS: ${CMAKE_CXX_FLAGS}")
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys, os, re, subprocess
|
||||
|
||||
scad = sys.argv[1]
|
||||
bin = sys.argv[2]
|
||||
png = sys.argv[3]
|
||||
csg = re.sub(r"\.scad$", ".csg", scad)
|
||||
|
||||
print(bin, scad, csg, png);
|
||||
|
||||
subprocess.call([bin, scad, '-o', csg])
|
||||
subprocess.call([bin, csg, '--render', '-o', png])
|
||||
os.remove(csg);
|
||||
108
tests/export_import_pngtest.py
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Export-import test
|
||||
#
|
||||
#
|
||||
# Usage: <script> <inputfile> --openscad=<executable-path> --format=<format> file.png
|
||||
#
|
||||
#
|
||||
# step 1. If the input file is _not_ and .scad file, create a temporary .scad file importing the input file.
|
||||
# step 2. process the .scad file, output an export format (csg, stl, off, dxf, svg, amf)
|
||||
# step 3. If the export format is _not_ .csg, create a temporary new .scad file importing the exported file
|
||||
# step 4. render the .csg or .scad file to the given .png file
|
||||
# step 5. (done in CTest) - compare the generated .png file to expected output
|
||||
# of the original .scad file. they should be the same!
|
||||
#
|
||||
# This script should return 0 on success, not-0 on error.
|
||||
#
|
||||
# Authors: Torsten Paul, Don Bright, Marius Kintel
|
||||
|
||||
import sys, os, re, subprocess, argparse
|
||||
|
||||
def failquit(*args):
|
||||
if len(args)!=0: print(args)
|
||||
print('test_3d_export args:',str(sys.argv))
|
||||
print('exiting test_3d_export.py with failure')
|
||||
sys.exit(1)
|
||||
|
||||
def createImport(inputfile, scadfile):
|
||||
print ('createImport: ' + inputfile + " " + scadfile)
|
||||
outputdir = os.path.dirname(scadfile)
|
||||
try:
|
||||
if not os.path.exists(outputdir): os.mkdir(outputdir)
|
||||
f = open(scadfile,'w')
|
||||
f.write('import("'+inputfile+'");'+os.linesep)
|
||||
f.close()
|
||||
except:
|
||||
failquit('failure while opening/writing ' + scadfile)
|
||||
|
||||
|
||||
#
|
||||
# Parse arguments
|
||||
#
|
||||
formats = ['csg', 'stl','off', 'amf', 'dxf', 'svg']
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--openscad', required=True, help='Specify OpenSCAD executable')
|
||||
parser.add_argument('--format', required=True, choices=[item for sublist in [(f,f.upper()) for f in formats] for item in sublist], help='Specify 3d export format')
|
||||
args,remaining_args = parser.parse_known_args()
|
||||
|
||||
args.format = args.format.lower()
|
||||
inputfile = remaining_args[0] # Can be .scad file or a file to be imported
|
||||
pngfile = remaining_args[-1]
|
||||
remaining_args = remaining_args[1:-1] # Passed on to the OpenSCAD executable
|
||||
|
||||
if not os.path.exists(inputfile):
|
||||
failquit('cant find input file named: ' + inputfile)
|
||||
if not os.path.exists(args.openscad):
|
||||
failquit('cant find openscad executable named: ' + args.openscad)
|
||||
|
||||
outputdir = os.path.dirname(pngfile)
|
||||
inputpath, inputfilename = os.path.split(inputfile)
|
||||
inputbasename,inputsuffix = os.path.splitext(inputfilename)
|
||||
|
||||
if args.format == 'csg':
|
||||
# Must export to same folder for include/use/import to work
|
||||
exportfile = inputfile + '.' + args.format
|
||||
else:
|
||||
exportfile = os.path.join(outputdir, inputfilename)
|
||||
if args.format != inputsuffix[1:]: exportfile += '.' + args.format
|
||||
|
||||
# If we're not reading an .scad or .csg file, we need to import it.
|
||||
if inputsuffix != '.scad' and inputsuffix != '.csg':
|
||||
# FIXME: Remove tempfile if created
|
||||
tempfile = os.path.join(outputdir, inputfilename + '.scad')
|
||||
createImport(inputfile, tempfile)
|
||||
inputfile = tempfile
|
||||
|
||||
#
|
||||
# First run: Just export the given filetype
|
||||
#
|
||||
export_cmd = [args.openscad, inputfile, '-o', exportfile] + remaining_args
|
||||
print('Running OpenSCAD #1:')
|
||||
print(' '.join(export_cmd))
|
||||
result = subprocess.call(export_cmd)
|
||||
if result != 0:
|
||||
failquit('OpenSCAD #1 failed with return code ' + str(result))
|
||||
|
||||
|
||||
#
|
||||
# Second run: Import the exported file and render as png
|
||||
#
|
||||
newscadfile = exportfile
|
||||
# If we didn't export a .csg file, we need to import it
|
||||
if args.format != 'csg':
|
||||
newscadfile += '.scad'
|
||||
createImport(exportfile, newscadfile)
|
||||
|
||||
create_png_cmd = [args.openscad, newscadfile, '--render', '-o', pngfile] + remaining_args
|
||||
print('Running OpenSCAD #2:')
|
||||
print(' '.join(create_png_cmd))
|
||||
result = subprocess.call(create_png_cmd)
|
||||
if result != 0:
|
||||
failquit('OpenSCAD #2 failed with return code ' + str(result))
|
||||
|
||||
try: os.remove(exportfile)
|
||||
except: failquit('failure at os.remove('+exportfile+')')
|
||||
if newscadfile != exportfile:
|
||||
try: os.remove(newscadfile)
|
||||
except: failquit('failure at os.remove('+newscadfile+')')
|
||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |