diff options
author | smcauliffe <smcauliffe> | 2006-11-20 08:11:25 +0000 |
---|---|---|
committer | smcauliffe <smcauliffe@cb376a5e-1013-0410-a455-b6b1f9ac8223> | 2006-11-20 08:11:25 +0000 |
commit | 24cdea1f00ab54eaba0e50bcabb44cefe5bda499 (patch) | |
tree | cdc4c4176c9654364935055287c7534c4dab4cfb | |
parent | fe9e4a644092216bec1d0ead425583d2222b574f (diff) | |
download | reprap-24cdea1f00ab54eaba0e50bcabb44cefe5bda499.tar.gz reprap-24cdea1f00ab54eaba0e50bcabb44cefe5bda499.zip |
Start on a tesselation scheme
git-svn-id: https://reprap.svn.sourceforge.net/svnroot/reprap@446 cb376a5e-1013-0410-a455-b6b1f9ac8223
-rwxr-xr-x | trunk/users/sai/tessel/Dipyramid Crystalize.bsh | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/trunk/users/sai/tessel/Dipyramid Crystalize.bsh b/trunk/users/sai/tessel/Dipyramid Crystalize.bsh new file mode 100755 index 00000000..fe483f8c --- /dev/null +++ b/trunk/users/sai/tessel/Dipyramid Crystalize.bsh @@ -0,0 +1,201 @@ +/* +<?xml version='1.0' standalone='yes' ?> + +<script> + <name>Triangular Dipyramid Crystalization of a solid</name> + <author>Simon McAuliffe</author> + <version>0.1</version> + <date>19/11/2006</date> + <description> +This script removes material from an object so that the outer shape is +maintained but is much lighter weight. + +This is accomplished by removing triangular bipyramids from the solid. + +It was built for the RepRap project +http://reprap.org/ + </description> +</script> +*/ + +/* Copyright (C) 2006 by Simon McAuliffe + + This program is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + PARTICULAR PURPOSE. See the GNU General Public License for more details. +*/ + +double Tolerance = 0.0; + +// Global base coordinate system +CoordinateSystem cs = new CoordinateSystem(); +ObjectInfo allParts = null; + +scene = window.getScene(); + +maxDim = new ValueField(32, ValueField.NONNEGATIVE); +minDim = new ValueField(4, ValueField.NONNEGATIVE); +maxAngle = new ValueField(30, ValueField.NONNEGATIVE); + +dlg = new ComponentsDialog(window, "RepRap Tetrahedral Crystalization" , + new Widget [] { maxDim, minDim, maxAngle }, + new String [] { "Maximum crystal size:", "Minimum crystal size:", "Maximum angle (degrees):" } +); + +if (!dlg.clickedOk()) return; + +// Make a crystal. +// It should be centered about x/y/z based on its bounding box +ObjectInfo makeCrystal(double size, double x, double y, double z) { + vertices = new Vec3[4]; + vertices[0] = new Vec3(x, y, z + size * 0.5); + vertices[1] = new Vec3(x + size * 3 * Math.sqrt(2)/8, y, z + size * -0.5); + vertices[2] = new Vec3(x + size * -3 * Math.sqrt(2)/8, + y + size * Math.sqrt(6)/4, z + size * -0.5); + vertices[3] = new Vec3(x + size * -3 * Math.sqrt(2)/8, + y + size * -Math.sqrt(6)/4, z + size * -0.5); + int[][] faces = {{0, 1, 2}, {0, 2, 3}, {0, 3, 1}, {1, 3, 2}}; + mesh = new TriangleMesh(vertices, faces); + return new ObjectInfo(mesh, cs, "crystal"); +} + +boolean intersects(Object3D o1, Object3D o2) { + ObjectInfo oi1 = new ObjectInfo(o1, cs, "object"); + ObjectInfo oi2 = new ObjectInfo(o2, cs, "object"); + return intersects(oi1, oi2); +} + +// True is there is anything common between oi1 and oi2 +boolean intersects(ObjectInfo oi1, ObjectInfo oi2) { + CSGObject intersect = new CSGObject(oi1, oi2, CSGObject.INTERSECTION); + int canConvert = intersect.canConvertToTriangleMesh(); + if (canConvert != Object3D.EXACTLY) { + print("Cannot convert to mesh as expected"); + return false; + } + TriangleMesh mesh = intersect.convertToTriangleMesh(Tolerance); + return mesh.getEdges().length > 0; +} + +// True is oi1 is fully contained within oi2 +// Turns out this isn't quite correct. Not sure why. Maybe AoI tolerance. +boolean within(ObjectInfo oi1, ObjectInfo oi2) { + CSGObject diff = new CSGObject(oi1, oi2, CSGObject.DIFFERENCE12); + int canConvert = diff.canConvertToTriangleMesh(); + if (canConvert != Object3D.EXACTLY) { + print("Cannot convert to mesh as expected"); + return false; + } + TriangleMesh mesh = diff.convertToTriangleMesh(Tolerance); + return mesh.getEdges().length == 0; +} + +// Approximately find the smallest crystal that contains our object +ObjectInfo findContainingCrystal(ObjectInfo obj) { + BoundingBox box = obj.object.getBounds(); + + double size = 1.0; + + // First pass, get something definitely bigger + for(int maxiter = 0; maxiter < 10; maxiter++) { + ObjectInfo candidate = makeCrystal(size, + (box.minx + box.maxx)/2.0, + (box.miny + box.maxy)/2.0, + (box.minz + box.maxz)/2.0); + if (within(obj, candidate)) + break; + size *= 5.0; + } + + double lowerbound = 0; + double upperbound = size; + + // Search between bounds to find smallest containing crystal + size = (lowerbound + upperbound) / 2; + for(int maxiter = 0; maxiter < 20; maxiter++) { + ObjectInfo candidate = makeCrystal(size, + (box.minx + box.maxx)/2.0, + (box.miny + box.maxy)/2.0, + (box.minz + box.maxz)/2.0); + boolean isWithin = within(obj, candidate); + if (upperbound - lowerbound < 0.1 && isWithin) + return candidate; + if (!isWithin) { + lowerbound = size; + size = (size + upperbound) / 2; + } else { + upperbound = size; + size = (size + lowerbound) / 2; + } + } + return null; +} + +// Given a parent crystal, subdivide into smaller crystals +ObjectInfo [] subdivide(ObjectInfo parent) { + BoundingBox bounds = parent.object.getBounds(); + + // Use height as our base unit + double height = bounds.maxz - bounds.minz; + ObjectInfo [] subs = new ObjectInfo[4]; + double scale = height / 2.0; + double x = (bounds.minx + bounds.maxx) / 2.0; + double y = (bounds.miny + bounds.maxy) / 2.0; + double z = (bounds.minz + bounds.maxz) / 2.0; + subs[0] = makeCrystal(scale, x - scale * 3 * Math.sqrt(2)/8, + y + scale * Math.sqrt(6)/4, z - scale * 0.5); + subs[1] = makeCrystal(scale, x - scale * 3 * Math.sqrt(2)/8, + y - scale * Math.sqrt(6)/4, z - scale * 0.5); + subs[2] = makeCrystal(scale, x + scale * 3 * Math.sqrt(2)/8, y, + z - scale * 0.5); + subs[3] = makeCrystal(scale, x, y, z + scale * 0.5); + + // Special case: + // For tetrahedra, there is also a square bi-pyramid in the middle + // that we need to fill in + //subs[4] = null; + + return subs; +} + +void crystalize(ObjectInfo obj, ObjectInfo container) { + if (!intersects(obj, container)) + return; + + BoundingBox bounds = container.object.getBounds(); + double height = bounds.maxz - bounds.minz; + + print("Size is " + height); + + // We're done if it's small enough + if (height < 0.1) { + if (within(container, obj)) { + if (allParts == null) + allParts = container; + else + allParts = new ObjectInfo( + new CSGObject(container, allParts, CSGObject.UNION), + cs, "join"); + } + return; + } + + // Otherwise subdivide further + ObjectInfo [] subs = subdivide(container); + for(int i = 0; i < subs.length; i++) { + crystalize(obj, subs[i]); + } +} + +ObjectInfo obj = new ObjectInfo(new Cube(0.5, 0.5, 0.5), cs, "cube"); + +ObjectInfo rootCrystal = findContainingCrystal(obj); + +window.addObject(obj, null); +crystalize(obj, rootCrystal); + +window.addObject(allParts, null); |