Merge pull request #311 from openscad/resize5

Resize5
felipesanches-svg
Marius Kintel 2013-03-18 12:04:04 -07:00
commit 398b44c82a
23 changed files with 934 additions and 218 deletions

View File

@ -7,6 +7,7 @@ o Added basic syntax highlighting in the editor
o Mac: Added document icon
o Mac: Added auto-update check
o Commandline output to PNG, with various camera and rendering settings
o resize() command introduced
o Regression test now creates single monolithic .html file for easier uploading
o value reassignment is now less strict

View File

@ -179,6 +179,64 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
return N;
}
CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
{
// Based on resize() in Giles Bathgate's RapCAD (but not exactly)
CGAL_Nef_polyhedron N;
N = applyToChildren(node, CGE_UNION);
if ( N.isNull() || N.isEmpty() ) return N;
for (int i=0;i<3;i++) {
if (node.newsize[i]<0) {
PRINT("WARNING: Cannot resize to sizes less than 0.");
return N;
}
}
CGAL_Iso_cuboid_3 bb;
if ( N.dim == 2 ) {
CGAL_Iso_rectangle_2e bbox = bounding_box( *N.p2 );
CGAL_Point_2e min2(bbox.min()), max2(bbox.max());
CGAL_Point_3 min3(min2.x(),min2.y(),0), max3(max2.x(),max2.y(),0);
bb = CGAL_Iso_cuboid_3( min3, max3 );
}
else {
bb = bounding_box( *N.p3 );
}
Eigen::Matrix<NT,3,1> scale, bbox_size;
scale << 1,1,1;
bbox_size << bb.xmax()-bb.xmin(), bb.ymax()-bb.ymin(), bb.zmax()-bb.zmin();
for (int i=0;i<3;i++) {
if (node.newsize[i]) {
if (bbox_size[i]==NT(0)) {
PRINT("WARNING: Cannot resize in direction normal to flat object");
return N;
}
else {
scale[i] = NT(node.newsize[i]) / bbox_size[i];
}
}
}
NT autoscale = scale.maxCoeff();
for (int i=0;i<3;i++) {
if (node.autosize[i]) scale[i] = autoscale;
}
Eigen::Matrix4d t;
t << CGAL::to_double(scale[0]), 0, 0, 0,
0, CGAL::to_double(scale[1]), 0, 0,
0, 0, CGAL::to_double(scale[2]), 0,
0, 0, 0, 1;
N.transform( Transform3d( t ) );
return N;
}
/*
Typical visitor behavior:
o In prefix: Check if we're cached -> prune
@ -253,57 +311,7 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
PRINT("Warning: Transformation matrix contains Not-a-Number and/or Infinity - removing object.");
N.reset();
}
// Then apply transform
// If there is no geometry under the transform, N will be empty
// just silently ignore such nodes
if (!N.isNull()) {
if (N.dim == 2) {
// Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2
// objects. So we convert in to our internal 2d data format, transform it,
// tesselate it and create a new CGAL_Nef_polyhedron2 from it.. What a hack!
Eigen::Matrix2f testmat;
testmat << node.matrix(0,0), node.matrix(0,1), node.matrix(1,0), node.matrix(1,1);
if (testmat.determinant() == 0) {
PRINT("Warning: Scaling a 2D object with 0 - removing object");
N.reset();
}
else {
CGAL_Aff_transformation2 t(
node.matrix(0,0), node.matrix(0,1), node.matrix(0,3),
node.matrix(1,0), node.matrix(1,1), node.matrix(1,3), node.matrix(3,3));
DxfData *dd = N.convertToDxfData();
for (size_t i=0; i < dd->points.size(); i++) {
CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]);
p = t.transform(p);
dd->points[i][0] = to_double(p.x());
dd->points[i][1] = to_double(p.y());
}
PolySet ps;
ps.is2d = true;
dxf_tesselate(&ps, *dd, 0, true, false, 0);
N = evaluateCGALMesh(ps);
delete dd;
}
}
else if (N.dim == 3) {
if (node.matrix.matrix().determinant() == 0) {
PRINT("Warning: Scaling a 3D object with 0 - removing object");
N.reset();
}
else {
CGAL_Aff_transformation t(
node.matrix(0,0), node.matrix(0,1), node.matrix(0,2), node.matrix(0,3),
node.matrix(1,0), node.matrix(1,1), node.matrix(1,2), node.matrix(1,3),
node.matrix(2,0), node.matrix(2,1), node.matrix(2,2), node.matrix(2,3), node.matrix(3,3));
N.p3->transform(t);
}
}
}
N.transform( node.matrix );
}
else {
N = CGALCache::instance()->get(this->tree.getIdString(node));
@ -358,6 +366,9 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
case HULL:
N = applyHull(node);
break;
case RESIZE:
N = applyResize(node);
break;
}
}
else {

View File

@ -34,6 +34,7 @@ private:
void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op);
CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op);
CGAL_Nef_polyhedron applyHull(const CgaladvNode &node);
CGAL_Nef_polyhedron applyResize(const CgaladvNode &node);
std::string currindent;
typedef std::pair<const AbstractNode *, CGAL_Nef_polyhedron> ChildItem;

View File

@ -4,6 +4,7 @@
#include "cgalfwd.h"
#include "memory.h"
#include <string>
#include "linalg.h"
class CGAL_Nef_polyhedron
{
@ -27,7 +28,7 @@ public:
int weight() const;
class PolySet *convertToPolyset();
class DxfData *convertToDxfData() const;
void transform( const Transform3d &matrix );
int dim;
shared_ptr<CGAL_Nef_polyhedron2> p2;
shared_ptr<CGAL_Nef_polyhedron3> p3;

View File

@ -29,7 +29,11 @@
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
#include "cgalutils.h"
#include "svg.h"
#include <boost/variant.hpp>
#include "polyset.h"
#include "dxftess.h"
#include "CGALEvaluator.h"
#include "Tree.h"
#ifdef ENABLE_CGAL
@ -89,4 +93,59 @@ std::string CGAL_Nef_polyhedron::dump() const
return std::string("Nef Polyhedron with dimension != 2 or 3");
}
void CGAL_Nef_polyhedron::transform( const Transform3d &matrix )
{
if (!this->isNull()) {
if (this->dim == 2) {
// Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2
// objects. So we convert in to our internal 2d data format, transform it,
// tesselate it and create a new CGAL_Nef_polyhedron2 from it.. What a hack!
Eigen::Matrix2f testmat;
testmat << matrix(0,0), matrix(0,1), matrix(1,0), matrix(1,1);
if (testmat.determinant() == 0) {
PRINT("Warning: Scaling a 2D object with 0 - removing object");
this->reset();
return;
}
else {
CGAL_Aff_transformation2 t(
matrix(0,0), matrix(0,1), matrix(0,3),
matrix(1,0), matrix(1,1), matrix(1,3), matrix(3,3));
DxfData *dd = this->convertToDxfData();
for (size_t i=0; i < dd->points.size(); i++) {
CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]);
p = t.transform(p);
dd->points[i][0] = to_double(p.x());
dd->points[i][1] = to_double(p.y());
}
PolySet ps;
ps.is2d = true;
dxf_tesselate(&ps, *dd, 0, true, false, 0);
Tree nulltree;
CGALEvaluator tmpeval(nulltree);
CGAL_Nef_polyhedron N = tmpeval.evaluateCGALMesh(ps);
if ( N.p2 ) this->p2.reset( new CGAL_Nef_polyhedron2( *N.p2 ) );
delete dd;
}
}
else if (this->dim == 3) {
if (matrix.matrix().determinant() == 0) {
PRINT("Warning: Scaling a 3D object with 0 - removing object");
this->reset();
}
else {
CGAL_Aff_transformation t(
matrix(0,0), matrix(0,1), matrix(0,2), matrix(0,3),
matrix(1,0), matrix(1,1), matrix(1,2), matrix(1,3),
matrix(2,0), matrix(2,1), matrix(2,2), matrix(2,3), matrix(3,3));
this->p3->transform(t);
}
}
}
}
#endif // ENABLE_CGAL

View File

@ -57,7 +57,7 @@ public:
if (this->root_norm_term) {
this->root_chain = new CSGChain();
this->root_chain->import(this->root_norm_term);
fprintf(stderr, "Normalized CSG tree has %d elements", int(this->root_chain->polysets.size()));
PRINTB("Normalized CSG tree has %d elements", int(this->root_chain->polysets.size()));
}
else {
this->root_chain = NULL;

View File

@ -6,6 +6,7 @@
#include <string.h>
#include <cstdlib>
#include <sstream>
#include "printutils.h"
OffscreenView::OffscreenView(size_t width, size_t height)
{
@ -23,7 +24,7 @@ OffscreenView::~OffscreenView()
#ifdef ENABLE_OPENCSG
void OffscreenView::display_opencsg_warning()
{
fprintf(stderr, "OpenSCAD recommended OpenGL version is 2.0. \n");
PRINT("OpenSCAD recommended OpenGL version is 2.0.");
}
#endif

View File

@ -20,104 +20,6 @@
#include <boost/foreach.hpp>
#include <vector>
/*
ZRemover
This class converts one or more already 'flat' Nef3 polyhedra into a Nef2
polyhedron by stripping off the 'z' coordinates from the vertices. The
resulting Nef2 poly is accumulated in the 'output_nefpoly2d' member variable.
The 'z' coordinates will either be all 0s, for an xy-plane intersected Nef3,
or, they will be a mixture of -eps and +eps, for a thin-box intersected Nef3.
Notes on CGAL's Nef Polyhedron2:
1. The 'mark' on a 2d Nef face is important when doing unions/intersections.
If the 'mark' of a face is wrong the resulting nef2 poly will be unexpected.
2. The 'mark' can be dependent on the points fed to the Nef2 constructor.
This is why we iterate through the 3d faces using the halfedge cycle
source()->target() instead of the ordinary source()->source(). The
the latter can generate sequences of points that will fail the
the CGAL::is_simple_2() test, resulting in improperly marked nef2 polys.
3. 3d facets have 'two sides'. we throw out the 'down' side to prevent dups.
The class uses the 'visitor' pattern from the CGAL manual. See also
http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html
http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3_ref/Class_Nef_polyhedron3.html
OGL_helper.h
*/
class ZRemover {
public:
logstream log;
CGAL_Nef_polyhedron2::Boundary boundary;
shared_ptr<CGAL_Nef_polyhedron2> tmpnef2d;
shared_ptr<CGAL_Nef_polyhedron2> output_nefpoly2d;
CGAL::Direction_3<CGAL_Kernel3> up;
ZRemover()
{
output_nefpoly2d.reset( new CGAL_Nef_polyhedron2() );
boundary = CGAL_Nef_polyhedron2::INCLUDED;
up = CGAL::Direction_3<CGAL_Kernel3>(0,0,1);
log = logstream(5);
}
void visit( CGAL_Nef_polyhedron3::Vertex_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::Halfedge_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::SHalfedge_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::SHalfloop_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::SFace_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet ) {
log << " <!-- Halffacet visit. Mark: " << hfacet->mark() << " -->\n";
if ( hfacet->plane().orthogonal_direction() != this->up ) {
log << " <!-- down-facing half-facet. skipping -->\n";
log << " <!-- Halffacet visit end-->\n";
return;
}
// possible optimization - throw out facets that are 'side facets' between
// the top & bottom of the big thin box. (i.e. mixture of z=-eps and z=eps)
CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator fci;
int contour_counter = 0;
CGAL_forall_facet_cycles_of( fci, hfacet ) {
if ( fci.is_shalfedge() ) {
CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(fci), cend(c1);
std::vector<CGAL_Nef_polyhedron2::Explorer::Point> contour;
CGAL_For_all( c1, cend ) {
CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->target()->point();
CGAL_Nef_polyhedron2::Explorer::Point point2d( point3d.x(), point3d.y() );
contour.push_back( point2d );
}
if (contour.size()==0) continue;
log << " <!-- is_simple_2:" << CGAL::is_simple_2( contour.begin(), contour.end() ) << " --> \n";
tmpnef2d.reset( new CGAL_Nef_polyhedron2( contour.begin(), contour.end(), boundary ) );
if ( contour_counter == 0 ) {
log << " <!-- contour is a body. make union(). " << contour.size() << " points. -->\n" ;
*(output_nefpoly2d) += *(tmpnef2d);
} else {
log << " <!-- contour is a hole. make intersection(). " << contour.size() << " points. -->\n";
*(output_nefpoly2d) *= *(tmpnef2d);
}
log << "\n<!-- ======== output tmp nef: ==== -->\n"
<< OpenSCAD::dump_svg( *tmpnef2d ) << "\n"
<< "\n<!-- ======== output accumulator: ==== -->\n"
<< OpenSCAD::dump_svg( *output_nefpoly2d ) << "\n";
contour_counter++;
} else {
log << " <!-- trivial facet cycle skipped -->\n";
}
} // next facet cycle (i.e. next contour)
log << " <!-- Halffacet visit end -->\n";
} // visit()
};
PolySetCGALEvaluator::PolySetCGALEvaluator(CGALEvaluator &cgalevaluator)
: PolySetEvaluator(cgalevaluator.getTree()), cgalevaluator(cgalevaluator)
{
@ -186,24 +88,23 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
return NULL;
}
// remove z coordinates to make CGAL_Nef_polyhedron2
log << OpenSCAD::svg_header( 480, 100000 ) << "\n";
try {
ZRemover zremover;
CGAL_Nef_polyhedron3::Volume_const_iterator i;
CGAL_Nef_polyhedron3::Shell_entry_const_iterator j;
CGAL_Nef_polyhedron3::SFace_const_handle sface_handle;
for ( i = sum.p3->volumes_begin(); i != sum.p3->volumes_end(); ++i ) {
log << "<!-- volume. mark: " << i->mark() << " -->\n";
for ( j = i->shells_begin(); j != i->shells_end(); ++j ) {
log << "<!-- shell. mark: " << i->mark() << " -->\n";
sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j );
sum.p3->visit_shell_objects( sface_handle , zremover );
log << "<!-- shell. end. -->\n";
}
log << "<!-- volume end. -->\n";
}
nef_poly.p2 = zremover.output_nefpoly2d;
ZRemover zremover;
CGAL_Nef_polyhedron3::Volume_const_iterator i;
CGAL_Nef_polyhedron3::Shell_entry_const_iterator j;
CGAL_Nef_polyhedron3::SFace_const_handle sface_handle;
for ( i = sum.p3->volumes_begin(); i != sum.p3->volumes_end(); ++i ) {
log << "<!-- volume. mark: " << i->mark() << " -->\n";
for ( j = i->shells_begin(); j != i->shells_end(); ++j ) {
log << "<!-- shell. mark: " << i->mark() << " -->\n";
sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j );
sum.p3->visit_shell_objects( sface_handle , zremover );
log << "<!-- shell. end. -->\n";
}
log << "<!-- volume end. -->\n";
}
nef_poly.p2 = zremover.output_nefpoly2d;
} catch (const CGAL::Failure_exception &e) {
PRINTB("CGAL error in projection node while flattening: %s", e.what());
}

View File

@ -58,6 +58,9 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat
if (type == SUBDIV)
argnames += "type", "level", "convexity";
if (type == RESIZE)
argnames += "newsize", "auto";
Context c(ctx);
c.args(argnames, argexpr, inst->argnames, inst->argvalues);
@ -78,6 +81,28 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat
level = c.lookup_variable("level", true);
}
if (type == RESIZE) {
Value ns = c.lookup_variable("newsize");
node->newsize << 0,0,0;
if ( ns.type() == Value::VECTOR ) {
Value::VectorType vs = ns.toVector();
if ( vs.size() >= 1 ) node->newsize[0] = vs[0].toDouble();
if ( vs.size() >= 2 ) node->newsize[1] = vs[1].toDouble();
if ( vs.size() >= 3 ) node->newsize[2] = vs[2].toDouble();
}
Value autosize = c.lookup_variable("auto");
node->autosize << false, false, false;
if ( autosize.type() == Value::VECTOR ) {
Value::VectorType va = autosize.toVector();
if ( va.size() >= 1 ) node->autosize[0] = va[0].toBool();
if ( va.size() >= 2 ) node->autosize[1] = va[1].toBool();
if ( va.size() >= 3 ) node->autosize[2] = va[2].toBool();
}
else if ( autosize.type() == Value::BOOL ) {
node->autosize << true, true, true;
}
}
node->convexity = (int)convexity.toDouble();
node->path = path;
node->subdiv_type = subdiv_type.toString();
@ -112,6 +137,9 @@ std::string CgaladvNode::name() const
case HULL:
return "hull";
break;
case RESIZE:
return "resize";
break;
default:
assert(false);
}
@ -135,6 +163,13 @@ std::string CgaladvNode::toString() const
case HULL:
stream << "()";
break;
case RESIZE:
stream << "(newsize = ["
<< this->newsize[0] << "," << this->newsize[1] << "," << this->newsize[2] << "]"
<< ", auto = ["
<< this->autosize[0] << "," << this->autosize[1] << "," << this->autosize[2] << "]"
<< ")";
break;
default:
assert(false);
}
@ -148,4 +183,5 @@ void register_builtin_cgaladv()
Builtins::init("glide", new CgaladvModule(GLIDE));
Builtins::init("subdiv", new CgaladvModule(SUBDIV));
Builtins::init("hull", new CgaladvModule(HULL));
Builtins::init("resize", new CgaladvModule(RESIZE));
}

View File

@ -4,12 +4,14 @@
#include "node.h"
#include "visitor.h"
#include "value.h"
#include "linalg.h"
enum cgaladv_type_e {
MINKOWSKI,
GLIDE,
SUBDIV,
HULL
HULL,
RESIZE
};
class CgaladvNode : public AbstractNode
@ -29,6 +31,8 @@ public:
Value path;
std::string subdiv_type;
int convexity, level;
Vector3d newsize;
Eigen::Matrix<bool,3,1> autosize;
cgaladv_type_e type;
};

View File

@ -147,7 +147,7 @@ CGAL_Polyhedron *createPolyhedronFromPolySet(const PolySet &ps)
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N )
{
CGAL_Iso_cuboid_3 result(-1,-1,-1,1,1,1);
CGAL_Iso_cuboid_3 result(0,0,0,0,0,0);
CGAL_Nef_polyhedron3::Vertex_const_iterator vi;
std::vector<CGAL_Nef_polyhedron3::Point_3> points;
// can be optimized by rewriting bounding_box to accept vertices
@ -160,7 +160,7 @@ CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N )
CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N )
{
CGAL_Iso_rectangle_2e result(-1,-1,1,1);
CGAL_Iso_rectangle_2e result(0,0,0,0);
CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator vi;
std::vector<CGAL_Point_2e> points;
@ -173,5 +173,56 @@ CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N )
return result;
}
void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
{
log << " <!-- ZRemover Halffacet visit. Mark: " << hfacet->mark() << " -->\n";
if ( hfacet->plane().orthogonal_direction() != this->up ) {
log << " <!-- ZRemover down-facing half-facet. skipping -->\n";
log << " <!-- ZRemover Halffacet visit end-->\n";
return;
}
// possible optimization - throw out facets that are vertically oriented
CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator fci;
int contour_counter = 0;
CGAL_forall_facet_cycles_of( fci, hfacet ) {
if ( fci.is_shalfedge() ) {
log << " <!-- ZRemover Halffacet cycle begin -->\n";
CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(fci), cend(c1);
std::vector<CGAL_Nef_polyhedron2::Explorer::Point> contour;
CGAL_For_all( c1, cend ) {
CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->target()->point();
CGAL_Nef_polyhedron2::Explorer::Point point2d( point3d.x(), point3d.y() );
contour.push_back( point2d );
}
if (contour.size()==0) continue;
log << " <!-- is_simple_2:" << CGAL::is_simple_2( contour.begin(), contour.end() ) << " --> \n";
tmpnef2d.reset( new CGAL_Nef_polyhedron2( contour.begin(), contour.end(), boundary ) );
if ( contour_counter == 0 ) {
log << " <!-- contour is a body. make union(). " << contour.size() << " points. -->\n" ;
*(output_nefpoly2d) += *(tmpnef2d);
} else {
log << " <!-- contour is a hole. make intersection(). " << contour.size() << " points. -->\n";
*(output_nefpoly2d) *= *(tmpnef2d);
}
/*log << "\n<!-- ======== output tmp nef: ==== -->\n"
<< OpenSCAD::dump_svg( *tmpnef2d ) << "\n"
<< "\n<!-- ======== output accumulator: ==== -->\n"
<< OpenSCAD::dump_svg( *output_nefpoly2d ) << "\n";*/
contour_counter++;
} else {
log << " <!-- ZRemover trivial facet cycle skipped -->\n";
}
log << " <!-- ZRemover Halffacet cycle end -->\n";
}
log << " <!-- ZRemover Halffacet visit end -->\n";
}
#endif /* ENABLE_CGAL */

View File

@ -2,10 +2,63 @@
#define CGALUTILS_H_
#include <cgalfwd.h>
class PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p);
CGAL_Polyhedron *createPolyhedronFromPolySet(const class PolySet &ps);
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N );
CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N );
#include "svg.h"
#include "printutils.h"
/*
ZRemover
This class converts one or more Nef3 polyhedra into a Nef2 polyhedron by
stripping off the 'z' coordinates from the vertices. The resulting Nef2
poly is accumulated in the 'output_nefpoly2d' member variable.
The 'z' coordinates will either be all 0s, for an xy-plane intersected Nef3,
or, they will be a mixture of -eps and +eps, for a thin-box intersected Nef3.
Notes on CGAL's Nef Polyhedron2:
1. The 'mark' on a 2d Nef face is important when doing unions/intersections.
If the 'mark' of a face is wrong the resulting nef2 poly will be unexpected.
2. The 'mark' can be dependent on the points fed to the Nef2 constructor.
This is why we iterate through the 3d faces using the halfedge cycle
source()->target() instead of the ordinary source()->source(). The
the latter can generate sequences of points that will fail the
the CGAL::is_simple_2() test, resulting in improperly marked nef2 polys.
3. 3d facets have 'two sides'. we throw out the 'down' side to prevent dups.
The class uses the 'visitor' pattern from the CGAL manual. See also
http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html
http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3_ref/Class_Nef_polyhedron3.html
OGL_helper.h
*/
class ZRemover {
public:
logstream log;
CGAL_Nef_polyhedron2::Boundary boundary;
boost::shared_ptr<CGAL_Nef_polyhedron2> tmpnef2d;
boost::shared_ptr<CGAL_Nef_polyhedron2> output_nefpoly2d;
CGAL::Direction_3<CGAL_Kernel3> up;
ZRemover()
{
output_nefpoly2d.reset( new CGAL_Nef_polyhedron2() );
boundary = CGAL_Nef_polyhedron2::INCLUDED;
up = CGAL::Direction_3<CGAL_Kernel3>(0,0,1);
log = logstream(5);
}
void visit( CGAL_Nef_polyhedron3::Vertex_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::Halfedge_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::SHalfedge_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::SHalfloop_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::SFace_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet );
};
#endif

View File

@ -2,13 +2,13 @@
#include "cgalutils.h"
#include "svg.h"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <map>
namespace OpenSCAD {
// SVG code
// currently for debugging, not necessarily pretty or useful for users. (yet)
int svg_cursor_py = 0;
int svg_px_width = SVG_PXW;
int svg_px_height = SVG_PXH;
@ -27,6 +27,26 @@ std::string svg_label(std::string s)
return out.str();
}
std::string svg_styleblock(std::string strokewidth)
{
std::stringstream out;
// halfedge: f1/f0 = face mark, b1/b0 = body or hole, m1/m0 = halfedge mark
out << "\
<style type='text/css'>\n\
.halfedge_f0_b1_m0 { stroke: gold; stroke-width: __STROKEW__px } \n\
.halfedge_f0_b1_m1 { stroke: gold; stroke-width: __STROKEW__px } \n\
.halfedge_f0_b0_m0 { stroke: green; stroke-width: __STROKEW__px } \n\
.halfedge_f0_b0_m1 { stroke: green; stroke-width: __STROKEW__px } \n\
.halfedge_f1_b1_m0 { stroke: gold; stroke-width: __STROKEW__px } \n\
.halfedge_f1_b1_m1 { stroke: gold; stroke-width: __STROKEW__px } \n\
.halfedge_f1_b0_m0 { stroke: green; stroke-width: __STROKEW__px } \n\
.halfedge_f1_b0_m1 { stroke: green; stroke-width: __STROKEW__px } \n\
</style>";
std::string tmp = out.str();
boost::replace_all( tmp, "__STROKEW__", strokewidth );
return tmp;
}
std::string svg_border()
{
std::stringstream out;
@ -93,36 +113,27 @@ std::string dump_cgal_nef_polyhedron2_face_svg(
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1,
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c2,
CGAL_Nef_polyhedron2::Explorer explorer,
std::string color,
bool mark,
CGAL_Iso_rectangle_2e bbox )
bool facemark, bool body )
{
std::stringstream style;
style << "halfedge_f" << facemark << "_b" << body << "_m";
std::string styleclass = style.str();
std::stringstream out;
CGAL_For_all(c1, c2) {
if ( explorer.is_standard( explorer.target(c1) ) ) {
CGAL_Point_2e source = explorer.point( explorer.source( c1 ) );
CGAL_Point_2e target = explorer.point( explorer.target( c1 ) );
CGAL_Point_2e tp1 = project_svg_2to2( source, bbox );
CGAL_Point_2e tp2 = project_svg_2to2( target, bbox );
double mod=0;
if (color=="green") mod=10;
out << " <!-- Halfedge. Mark: " << c1->mark() << " -->\n";
out << " <line"
<< " x1='" << CGAL::to_double(tp1.x()) + mod << "'"
<< " y1='" << CGAL::to_double(tp1.y()) - mod << "'"
<< " x2='" << CGAL::to_double(tp2.x()) + mod << "'"
<< " y2='" << CGAL::to_double(tp2.y()) - mod << "'"
<< " stroke='" << color << "'";
if (!mark) out << " stroke-dasharray='4 4' />\n";
else out << " />\n";
// crude "arrowhead" to indicate directionality
out << " <circle"
<< " cx='" << CGAL::to_double(tp1.x()+ (tp2.x()-tp1.x())* 7/8) + mod << "'"
<< " cy='" << CGAL::to_double(tp1.y()+ (tp2.y()-tp1.y())* 7/8) - mod << "'"
<< " r='2'"
<< " fill='" << color << "' stroke='" << color << "' />\n";
out << " <!-- Halfedge. Mark: " << c1->mark() << " -->\n";
std::string he_mark = boost::lexical_cast<std::string>(c1->mark());
out << " <line"
<< " x1='" << CGAL::to_double(source.x()) << "'"
<< " y1='" << CGAL::to_double(source.y()) << "'"
<< " x2='" << CGAL::to_double(target.x()) << "'"
<< " y2='" << CGAL::to_double(target.y()) << "'"
<< " class='" << styleclass + he_mark << "' />\n";
} else {
out << " <!-- 2d Nef Rays - not implemented -->\n";
out << " <!-- 2d Nef Rays - not implemented -->\n";
}
}
return out.str();
@ -132,27 +143,27 @@ std::string dump_svg( const CGAL_Nef_polyhedron2 &N )
{
std::stringstream out;
CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
CGAL_Iso_rectangle_2e bbox = bounding_box( N );
CGAL_Nef_polyhedron2::Explorer::Face_const_iterator i;
out << " <svg y='" << svg_cursor_py << "' width='" << svg_px_width
<< "' height='" << svg_px_height
<< "' xmlns='http://www.w3.org/2000/svg' version='1.1'>\n";
out << svg_border() << "\n" << svg_axes() << "\n";
svg_cursor_py += svg_px_height;
std::string linewidth = "0.05";
out << "<!--CGAL_Nef_polyhedron2 dump begin-->\n";
out << svg_header() << "\n" << svg_styleblock( linewidth ) << "\n";
for ( i = explorer.faces_begin(); i!= explorer.faces_end(); ++i ) {
out << " <!-- face begin. mark: " << i->mark() << " -->\n";
out << " <!-- body begin -->\n";
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1
= explorer.face_cycle( i ), c2 ( c1 );
out << dump_cgal_nef_polyhedron2_face_svg( c1, c2, explorer, "red", i->mark(), bbox );
out << dump_cgal_nef_polyhedron2_face_svg( c1, c2, explorer, i->mark(), true );
out << " <!-- body end -->\n";
CGAL_Nef_polyhedron2::Explorer::Hole_const_iterator j;
for ( j = explorer.holes_begin( i ); j!= explorer.holes_end( i ); ++j ) {
out << " <!-- hole begin. mark: " << j->mark() << " -->\n";
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c3( j ), c4 ( c3 );
out << dump_cgal_nef_polyhedron2_face_svg( c3, c4, explorer, "green", j->mark(), bbox );
out << dump_cgal_nef_polyhedron2_face_svg( c3, c4, explorer, "green", j->mark() );
out << " <!-- hole end -->\n";
}
out << " <!-- face end -->\n";
@ -182,13 +193,13 @@ public:
void visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
{
int contour_count = 0;
out << " <!-- Halffacet. Mark: " << (*hfacet).mark() << " -->\n";
out << " <!-- Halffacet visit. Mark: " << (*hfacet).mark() << " -->\n";
std::string color = "gold";
if (!(*hfacet).mark()) color = "green";
CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator i;
CGAL_forall_facet_cycles_of( i, hfacet ) {
CGAL_Nef_polyhedron3::SHalfloop_const_handle shl_handle;
out << " <!-- Halffacet cycle: -->\n";
out << " <!-- Halffacet cycle begin: -->\n";
if ( contour_count == 0 ) {
out << " <!-- Body contour:--> \n";
} else {
@ -196,13 +207,15 @@ public:
}
CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(i), c2(c1);
CGAL_For_all( c1, c2 ) {
out << " <line";
// don't know why we use source()->source(), except thats what CGAL does internally
CGAL_Point_3 source = c1->source()->source()->point();
CGAL_Point_3 target = c1->source()->target()->point();
CGAL_Point_2e tp1 = project_svg_3to2 ( source, bbox );
CGAL_Point_2e tp2 = project_svg_3to2 ( target, bbox );
out << " "
out << " <!-- " << CGAL::to_double(source.x()) << ","
<< CGAL::to_double(source.y()) << ","
<< CGAL::to_double(source.z()) << " -->\n";
out << " <line "
<< "x1='" << CGAL::to_double(tp1.x()) << "' "
<< "y1='" << CGAL::to_double(tp1.y()) << "' "
<< "x2='" << CGAL::to_double(tp2.x()) << "' "
@ -212,31 +225,34 @@ public:
else out << " />\n";
}
contour_count++;
} // next facet cycle (i.e. next contour)
} // visit()
out << " <!-- Halffacet cycle end -->\n";
}
out << " <!-- Halffacet visit end -->\n";
}
};
std::string dump_svg( const CGAL_Nef_polyhedron3 &N )
{
std::stringstream out;
out << svg_header() << "\n" << svg_border() << "\n" << svg_axes() << "\n";
std::string linewidth = "0.05";
out << "<!--CGAL_Nef_polyhedron3 dump begin-->\n";
out << svg_header() << "\n" << svg_border() << "\n";
out << svg_styleblock( linewidth ) << "\n" << svg_axes() << "\n";
CGAL_Nef_polyhedron3::Volume_const_iterator c;
CGAL_forall_volumes(c,N) {
out << " <!--Processing volume...-->\n";
out << " <!--Volume begin-->\n";
out << " <!--Mark: " << (*c).mark() << "-->\n";
CGAL_Nef_polyhedron3::Shell_entry_const_iterator it;
CGAL_forall_shells_of(it,c) {
out << " <!--Processing shell...-->\n";
out << " <!--Shell begin-->\n";
NefPoly3_dumper_svg dumper_svg(N);
N.visit_shell_objects(CGAL_Nef_polyhedron3::SFace_const_handle(it), dumper_svg );
out << dumper_svg.out.str();
out << " <!--Processing shell end-->\n";
out << " <!--Shell end-->\n";
}
out << " <!--Processing volume end-->\n";
out << " <!--Volume end-->\n";
}
out << "<!--CGAL_Nef_polyhedron3 dump end-->\n";
out << "</svg>";

View File

@ -0,0 +1,55 @@
// red = reference
// gold = basic resize
// green = auto resize
// pink = errors, wrong syntax, trying to resize in 3rd dimension, etc
$fn=10;
// two simple holes
module shape(){
difference() {
square([5,5]);
translate([1,1]) square();
translate([3,3]) circle();
}
}
// holes that have problems (duplicate vertex)
module shape2(){
difference() {
square([5,5]);
translate([1,1]) square();
translate([2,2]) square();
}
}
// one square split into two by another
module shape3(){
difference() {
square([5,5]);
translate([0,2.5]) square([5,1]);
}
}
color("red") {
translate([-16,0]) scale([3,3]) shape();
translate([-16,16]) scale([3,3]) shape2();
translate([-16,32]) scale([3,3]) shape3();
}
translate([0,0]) resize([15,15]) shape();
translate([0,16]) resize([15,15,0]) shape2();
translate([0,32]) resize([15,15]) shape3();
color("green"){
translate([16,0]) resize([15,0],auto=true) shape();
translate([16,16]) resize([0,15],auto=true) shape2();
translate([16,32]) resize([0,15],auto=[true,false]) shape3();
}
color("pink"){
translate([32,0]) resize([0,0],auto=[false,true]) shape();
translate([32,16]) resize([0,0,15],auto=true) shape2();
translate([32,32]) resize([0,0,15]) shape3();
}

View File

@ -0,0 +1,81 @@
// bottom row (red) = reference
// middle row (gold) = should match reference
// top row (blue) = should be 'spherical' versions of gold row,
// and should be inscribed in gold row in 'top' view
// back row (green) = should be all cubes auto-scaled up
// back top (purple) = uses 'auto' feature
// pink = recursive resize, negative, <1, wrong syntax, etc
$fn=8;
color("red") {
translate([0, 0,-10]) cube();
translate([0,10,-10]) cube([5,1,1]);
translate([0,20,-10]) cube([1,6,1]);
translate([0,30,-10]) cube([1,1,7]);
translate([0,40,-10]) cube([5,6,1]);
translate([0,60,-10]) cube([1,6,7]);
translate([0,50,-10]) cube([5,1,7]);
translate([0,70,-10]) cube([8,9,1]);
translate([0,80,-10]) cube([9,1,1]);
translate([0,90,-10]) cube([5,6,7]);
}
translate([0, 0,0]) cube();
translate([0,10,0]) resize([5,0,0]) cube();
translate([0,20,0]) resize([0,6,0]) cube();
translate([0,30,0]) resize([0,0,7]) cube();
translate([0,40,0]) resize([5,6,0]) cube();
translate([0,60,0]) resize([0,6,7]) cube();
translate([0,50,0]) resize([5,0,7]) cube();
translate([0,70,0]) resize([8,9]) cube();
translate([0,80,0]) resize([9]) cube();
translate([0,90,0]) resize([5,6,7]) cube();
color("blue"){
translate([0, 0,10]) cube();
translate([2.5,10.5,10]) resize([5,0,0]) sphere(0.5);
translate([0.5,23,10]) resize([0,6,0]) sphere(0.5);
translate([0.5,30.5,10]) resize([0,0,7]) sphere(0.5);
translate([2.5,43,10]) resize([5,6,0]) sphere(0.5);
translate([2.5,50.5,10]) resize([5,0,7]) sphere(0.5);
translate([0.5,63,10]) resize([0,6,7]) sphere(0.5);
translate([4,74.5,10]) resize([8,9]) sphere(0.5);
translate([4.5,80.5,10]) resize([9]) sphere(0.5);
translate([2.5,93,10]) resize([5,6,7]) sphere(0.5);
}
color("green"){
translate([10, 0, 0]) cube();
translate([10,10,0]) resize([5,0,0],auto=true) cube();
translate([10,20,0]) resize([0,6,0],auto=true) cube();
translate([10,30,0]) resize([0,0,7],auto=true) cube();
translate([10,40,0]) resize([5,6,0],true) cube();
translate([10,50,0]) resize([5,0,7],true) cube();
translate([10,60,0]) resize([0,6,7],auto=true) cube();
translate([10,70,0]) resize([8,9],auto=true) cube();
translate([10,80,0]) resize([9],true) cube();
translate([10,90,0]) resize([5,6,7],auto=true) cube();
}
color("purple"){
translate([10, 0, 10]) cube();
translate([10,10,10]) resize([5,0,0],auto=[true,true,false]) cube();
translate([10,20,10]) resize([6,0,0],auto=[true,true,true]) cube();
translate([13.5,33.5,10]) resize([7,0,0],auto=[true,false,false]) sphere();
translate([10,40,10]) resize([6,0,0],auto=[true,false,true]) cube();
translate([10,50,10]) resize([7,0,7],auto=[false,true,true]) cube();
translate([13.5,63.5,10]) resize([7,0,0],auto=[false,true,false]) sphere(); translate([10,70,10]) resize([8,0,0],auto=[false,false,false]) cube();
translate([10,80,10]) resize([9,0,0],auto=[false,false,true]) cube();
translate([10,90,10]) resize([0,0,7],auto=[true,true,false]) cube();
}
color("pink"){
translate([10,0,-10]) resize([4,4,4]) resize([5000,100,1000]) cube();
translate([10,10,-10]) resize([-5,0,0]) cube();
translate([10,20,-10]) resize([-5,0,0],auto=3) cube();
translate([10,30,-10]) resize(-5,0,0,auto=3) cube();
translate([10,40,-10]) resize(5,0,0) cube();
translate([10,50,-10]) resize([0.5,0,7]) cube([0.5,1,1000]);
translate([10,60,-10]) resize([0,0,0.5]) cube([6,6,10000000000]);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,175 @@
color([1, 0, 0, 1]) {
multmatrix([[1, 0, 0, -16], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
multmatrix([[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
multmatrix([[1, 0, 0, 3], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) {
circle($fn = 10, $fa = 12, $fs = 2, r = 1);
}
}
}
}
}
multmatrix([[1, 0, 0, -16], [0, 1, 0, 16], [0, 0, 1, 0], [0, 0, 0, 1]]) {
multmatrix([[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
multmatrix([[1, 0, 0, 2], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
}
}
}
}
multmatrix([[1, 0, 0, -16], [0, 1, 0, 32], [0, 0, 1, 0], [0, 0, 0, 1]]) {
multmatrix([[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 0], [0, 1, 0, 2.5], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [5, 1], center = false);
}
}
}
}
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [15,15,0], auto = [0,0,0]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
multmatrix([[1, 0, 0, 3], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) {
circle($fn = 10, $fa = 12, $fs = 2, r = 1);
}
}
}
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 16], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [15,15,0], auto = [0,0,0]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
multmatrix([[1, 0, 0, 2], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
}
}
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 32], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [15,15,0], auto = [0,0,0]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 0], [0, 1, 0, 2.5], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [5, 1], center = false);
}
}
}
}
}
color([0, 0.501961, 0, 1]) {
multmatrix([[1, 0, 0, 16], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [15,0,0], auto = [1,1,1]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
multmatrix([[1, 0, 0, 3], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) {
circle($fn = 10, $fa = 12, $fs = 2, r = 1);
}
}
}
}
}
multmatrix([[1, 0, 0, 16], [0, 1, 0, 16], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,15,0], auto = [1,1,1]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
multmatrix([[1, 0, 0, 2], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
}
}
}
}
multmatrix([[1, 0, 0, 16], [0, 1, 0, 32], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,15,0], auto = [1,0,0]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 0], [0, 1, 0, 2.5], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [5, 1], center = false);
}
}
}
}
}
}
color([1, 0.752941, 0.796078, 1]) {
multmatrix([[1, 0, 0, 32], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,0,0], auto = [0,1,0]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
multmatrix([[1, 0, 0, 3], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) {
circle($fn = 10, $fa = 12, $fs = 2, r = 1);
}
}
}
}
}
multmatrix([[1, 0, 0, 32], [0, 1, 0, 16], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,0,15], auto = [1,1,1]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
multmatrix([[1, 0, 0, 2], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [1, 1], center = false);
}
}
}
}
}
multmatrix([[1, 0, 0, 32], [0, 1, 0, 32], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,0,15], auto = [0,0,0]) {
group() {
difference() {
square(size = [5, 5], center = false);
multmatrix([[1, 0, 0, 0], [0, 1, 0, 2.5], [0, 0, 1, 0], [0, 0, 0, 1]]) {
square(size = [5, 1], center = false);
}
}
}
}
}
}

View File

@ -0,0 +1,270 @@
color([1, 0, 0, 1]) {
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, -10], [0, 0, 0, 1]]) {
cube(size = [1, 1, 1], center = false);
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 10], [0, 0, 1, -10], [0, 0, 0, 1]]) {
cube(size = [5, 1, 1], center = false);
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 20], [0, 0, 1, -10], [0, 0, 0, 1]]) {
cube(size = [1, 6, 1], center = false);
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 30], [0, 0, 1, -10], [0, 0, 0, 1]]) {
cube(size = [1, 1, 7], center = false);
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 40], [0, 0, 1, -10], [0, 0, 0, 1]]) {
cube(size = [5, 6, 1], center = false);
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 60], [0, 0, 1, -10], [0, 0, 0, 1]]) {
cube(size = [1, 6, 7], center = false);
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 50], [0, 0, 1, -10], [0, 0, 0, 1]]) {
cube(size = [5, 1, 7], center = false);
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 70], [0, 0, 1, -10], [0, 0, 0, 1]]) {
cube(size = [8, 9, 1], center = false);
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 80], [0, 0, 1, -10], [0, 0, 0, 1]]) {
cube(size = [9, 1, 1], center = false);
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 90], [0, 0, 1, -10], [0, 0, 0, 1]]) {
cube(size = [5, 6, 7], center = false);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
cube(size = [1, 1, 1], center = false);
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 10], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [5,0,0], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,6,0], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 30], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,0,7], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 40], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [5,6,0], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,6,7], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [5,0,7], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 70], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [8,9,0], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 80], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [9,0,0], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 0], [0, 1, 0, 90], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [5,6,7], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
color([0, 0, 1, 1]) {
multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 10], [0, 0, 0, 1]]) {
cube(size = [1, 1, 1], center = false);
}
multmatrix([[1, 0, 0, 2.5], [0, 1, 0, 10.5], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [5,0,0], auto = [0,0,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5);
}
}
multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 23], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [0,6,0], auto = [0,0,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5);
}
}
multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 30.5], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [0,0,7], auto = [0,0,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5);
}
}
multmatrix([[1, 0, 0, 2.5], [0, 1, 0, 43], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [5,6,0], auto = [0,0,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5);
}
}
multmatrix([[1, 0, 0, 2.5], [0, 1, 0, 50.5], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [5,0,7], auto = [0,0,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5);
}
}
multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 63], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [0,6,7], auto = [0,0,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5);
}
}
multmatrix([[1, 0, 0, 4], [0, 1, 0, 74.5], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [8,9,0], auto = [0,0,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5);
}
}
multmatrix([[1, 0, 0, 4.5], [0, 1, 0, 80.5], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [9,0,0], auto = [0,0,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5);
}
}
multmatrix([[1, 0, 0, 2.5], [0, 1, 0, 93], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [5,6,7], auto = [0,0,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5);
}
}
}
color([0, 0.501961, 0, 1]) {
multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
cube(size = [1, 1, 1], center = false);
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 10], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [5,0,0], auto = [1,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,6,0], auto = [1,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 30], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,0,7], auto = [1,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 40], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [5,6,0], auto = [1,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [5,0,7], auto = [1,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [0,6,7], auto = [1,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 70], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [8,9,0], auto = [1,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 80], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [9,0,0], auto = [1,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 90], [0, 0, 1, 0], [0, 0, 0, 1]]) {
resize(newsize = [5,6,7], auto = [1,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
}
color([0.501961, 0, 0.501961, 1]) {
multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 10], [0, 0, 0, 1]]) {
cube(size = [1, 1, 1], center = false);
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 10], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [5,0,0], auto = [1,1,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 20], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [6,0,0], auto = [1,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 13.5], [0, 1, 0, 33.5], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [7,0,0], auto = [1,0,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 1);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 40], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [6,0,0], auto = [1,0,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 50], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [7,0,7], auto = [0,1,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 13.5], [0, 1, 0, 63.5], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [7,0,0], auto = [0,1,0]) {
sphere($fn = 8, $fa = 12, $fs = 2, r = 1);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 70], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [8,0,0], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 80], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [9,0,0], auto = [0,0,1]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 90], [0, 0, 1, 10], [0, 0, 0, 1]]) {
resize(newsize = [0,0,7], auto = [1,1,0]) {
cube(size = [1, 1, 1], center = false);
}
}
}
color([1, 0.752941, 0.796078, 1]) {
multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, -10], [0, 0, 0, 1]]) {
resize(newsize = [4,4,4], auto = [0,0,0]) {
resize(newsize = [5000,100,1000], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 10], [0, 0, 1, -10], [0, 0, 0, 1]]) {
resize(newsize = [-5,0,0], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 20], [0, 0, 1, -10], [0, 0, 0, 1]]) {
resize(newsize = [-5,0,0], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 30], [0, 0, 1, -10], [0, 0, 0, 1]]) {
resize(newsize = [0,0,0], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 40], [0, 0, 1, -10], [0, 0, 0, 1]]) {
resize(newsize = [0,0,0], auto = [0,0,0]) {
cube(size = [1, 1, 1], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 50], [0, 0, 1, -10], [0, 0, 0, 1]]) {
resize(newsize = [0.5,0,7], auto = [0,0,0]) {
cube(size = [0.5, 1, 1000], center = false);
}
}
multmatrix([[1, 0, 0, 10], [0, 1, 0, 60], [0, 0, 1, -10], [0, 0, 0, 1]]) {
resize(newsize = [0,0,0.5], auto = [0,0,0]) {
cube(size = [6, 6, 1e+10], center = false);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB