mirror of https://github.com/vitalif/openscad
commit
398b44c82a
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
106
src/svg.cc
106
src/svg.cc
|
@ -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>";
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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 |
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 |
Loading…
Reference in New Issue