toxiclibs 0.2-java → 0.5.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +16 -0
- data/CHANGELOG.md +4 -0
- data/LICENSE +675 -0
- data/README.md +12 -5
- data/Rakefile +25 -82
- data/examples/attract_repel/attract_repel.rb +30 -0
- data/examples/attract_repel/attractor.rb +23 -0
- data/examples/attract_repel/particle.rb +27 -0
- data/examples/data/ti_yong.png +0 -0
- data/examples/force_directed/cluster.rb +76 -0
- data/examples/force_directed/force_directed_graph.rb +92 -0
- data/examples/force_directed/node.rb +26 -0
- data/examples/gray_scott_image.rb +75 -0
- data/examples/gray_scott_tone_map.rb +77 -0
- data/examples/implicit.rb +139 -0
- data/examples/inflate_mesh.rb +89 -0
- data/examples/model_align.rb +44 -0
- data/examples/povmesh/ftest.rb +46 -0
- data/examples/povmesh/tentacle.rb +73 -0
- data/examples/simple_cluster/cluster.rb +47 -0
- data/examples/simple_cluster/node.rb +27 -0
- data/examples/simple_cluster/simple_cluster.rb +60 -0
- data/examples/soft_body/blanket.rb +45 -0
- data/examples/soft_body/connection.rb +16 -0
- data/examples/soft_body/particle.rb +22 -0
- data/examples/soft_body/soft_body_square_adapted.rb +55 -0
- data/lib/toxiclibs.jar +0 -0
- data/lib/toxiclibs.rb +91 -32
- data/lib/toxiclibs/version.rb +1 -1
- data/pom.xml +122 -0
- data/src/com/toxi/net/ClientListener.java +41 -0
- data/src/com/toxi/net/ServerListener.java +70 -0
- data/src/com/toxi/net/ServerListenerAdapter.java +47 -0
- data/src/com/toxi/net/ServerState.java +18 -0
- data/src/com/toxi/net/UDPConnection.java +66 -0
- data/src/com/toxi/net/UDPSyncClient.java +81 -0
- data/src/com/toxi/net/UDPSyncServer.java +450 -0
- data/src/com/toxi/nio/UDPClient.java +121 -0
- data/src/com/toxi/nio/UDPClientState.java +32 -0
- data/src/com/toxi/nio/UDPServer.java +129 -0
- data/src/toxi/color/AccessCriteria.java +114 -0
- data/src/toxi/color/AlphaAccessor.java +67 -0
- data/src/toxi/color/CMYKAccessor.java +122 -0
- data/src/toxi/color/CMYKDistanceProxy.java +40 -0
- data/src/toxi/color/ColorGradient.java +260 -0
- data/src/toxi/color/ColorList.java +699 -0
- data/src/toxi/color/ColorRange.java +671 -0
- data/src/toxi/color/ColorTheme.java +163 -0
- data/src/toxi/color/DistanceProxy.java +44 -0
- data/src/toxi/color/HSVAccessor.java +113 -0
- data/src/toxi/color/HSVDistanceProxy.java +40 -0
- data/src/toxi/color/HistEntry.java +85 -0
- data/src/toxi/color/Histogram.java +185 -0
- data/src/toxi/color/Hue.java +249 -0
- data/src/toxi/color/LuminanceAccessor.java +78 -0
- data/src/toxi/color/NamedColor.java +935 -0
- data/src/toxi/color/ProximityComparator.java +70 -0
- data/src/toxi/color/RGBAccessor.java +113 -0
- data/src/toxi/color/RGBDistanceProxy.java +41 -0
- data/src/toxi/color/ReadonlyTColor.java +296 -0
- data/src/toxi/color/TColor.java +1677 -0
- data/src/toxi/color/TColorAdapter.java +68 -0
- data/src/toxi/color/ToneMap.java +218 -0
- data/src/toxi/color/theory/AnalogousStrategy.java +140 -0
- data/src/toxi/color/theory/ColorTheoryRegistry.java +139 -0
- data/src/toxi/color/theory/ColorTheoryStrategy.java +56 -0
- data/src/toxi/color/theory/ComplementaryStrategy.java +111 -0
- data/src/toxi/color/theory/CompoundTheoryStrategy.java +143 -0
- data/src/toxi/color/theory/LeftSplitComplementaryStrategy.java +82 -0
- data/src/toxi/color/theory/MonochromeTheoryStrategy.java +103 -0
- data/src/toxi/color/theory/RightSplitComplementaryStrategy.java +82 -0
- data/src/toxi/color/theory/SingleComplementStrategy.java +76 -0
- data/src/toxi/color/theory/SplitComplementaryStrategy.java +77 -0
- data/src/toxi/color/theory/TetradTheoryStrategy.java +114 -0
- data/src/toxi/color/theory/TriadTheoryStrategy.java +77 -0
- data/src/toxi/data/csv/CSVAdapter.java +74 -0
- data/src/toxi/data/csv/CSVFieldMapper.java +212 -0
- data/src/toxi/data/csv/CSVListener.java +61 -0
- data/src/toxi/data/csv/CSVParser.java +202 -0
- data/src/toxi/data/feeds/AtomAuthor.java +49 -0
- data/src/toxi/data/feeds/AtomContent.java +50 -0
- data/src/toxi/data/feeds/AtomEntry.java +111 -0
- data/src/toxi/data/feeds/AtomFeed.java +129 -0
- data/src/toxi/data/feeds/AtomLink.java +62 -0
- data/src/toxi/data/feeds/RSSChannel.java +88 -0
- data/src/toxi/data/feeds/RSSEnclosure.java +60 -0
- data/src/toxi/data/feeds/RSSFeed.java +99 -0
- data/src/toxi/data/feeds/RSSItem.java +104 -0
- data/src/toxi/data/feeds/util/EntityStripper.java +2480 -0
- data/src/toxi/data/feeds/util/Iso8601DateAdapter.java +101 -0
- data/src/toxi/data/feeds/util/Rfc822DateAdapter.java +93 -0
- data/src/toxi/geom/AABB.java +658 -0
- data/src/toxi/geom/Axis3D.java +116 -0
- data/src/toxi/geom/AxisAlignedCylinder.java +163 -0
- data/src/toxi/geom/BernsteinPolynomial.java +94 -0
- data/src/toxi/geom/BezierCurve2D.java +159 -0
- data/src/toxi/geom/BezierCurve3D.java +148 -0
- data/src/toxi/geom/BooleanShapeBuilder.java +185 -0
- data/src/toxi/geom/BoxIntersector.java +52 -0
- data/src/toxi/geom/Circle.java +230 -0
- data/src/toxi/geom/CircleIntersector.java +85 -0
- data/src/toxi/geom/Cone.java +150 -0
- data/src/toxi/geom/ConvexPolygonClipper.java +136 -0
- data/src/toxi/geom/CoordinateExtractor.java +16 -0
- data/src/toxi/geom/Ellipse.java +250 -0
- data/src/toxi/geom/GMatrix.java +2599 -0
- data/src/toxi/geom/GVector.java +833 -0
- data/src/toxi/geom/GlobalGridTesselator.java +54 -0
- data/src/toxi/geom/GridTesselator.java +108 -0
- data/src/toxi/geom/Intersector2D.java +49 -0
- data/src/toxi/geom/Intersector3D.java +51 -0
- data/src/toxi/geom/IsectData2D.java +103 -0
- data/src/toxi/geom/IsectData3D.java +103 -0
- data/src/toxi/geom/Line2D.java +534 -0
- data/src/toxi/geom/Line3D.java +471 -0
- data/src/toxi/geom/LineStrip2D.java +430 -0
- data/src/toxi/geom/LineStrip3D.java +230 -0
- data/src/toxi/geom/LocalGridTesselator.java +57 -0
- data/src/toxi/geom/Matrix3d.java +3048 -0
- data/src/toxi/geom/Matrix4f.java +3446 -0
- data/src/toxi/geom/Matrix4x4.java +1076 -0
- data/src/toxi/geom/MatrixSizeException.java +58 -0
- data/src/toxi/geom/OctreeVisitor.java +44 -0
- data/src/toxi/geom/Origin3D.java +148 -0
- data/src/toxi/geom/Plane.java +293 -0
- data/src/toxi/geom/PlaneIntersector.java +57 -0
- data/src/toxi/geom/PointCloud3D.java +253 -0
- data/src/toxi/geom/PointOctree.java +502 -0
- data/src/toxi/geom/PointQuadtree.java +375 -0
- data/src/toxi/geom/Polygon2D.java +1038 -0
- data/src/toxi/geom/PolygonClipper2D.java +45 -0
- data/src/toxi/geom/PolygonTesselator.java +20 -0
- data/src/toxi/geom/QuadtreeVisitor.java +44 -0
- data/src/toxi/geom/Quaternion.java +641 -0
- data/src/toxi/geom/Ray2D.java +146 -0
- data/src/toxi/geom/Ray3D.java +150 -0
- data/src/toxi/geom/Ray3DIntersector.java +75 -0
- data/src/toxi/geom/ReadonlyVec2D.java +575 -0
- data/src/toxi/geom/ReadonlyVec3D.java +628 -0
- data/src/toxi/geom/ReadonlyVec4D.java +431 -0
- data/src/toxi/geom/Rect.java +720 -0
- data/src/toxi/geom/Reflector3D.java +58 -0
- data/src/toxi/geom/Shape2D.java +94 -0
- data/src/toxi/geom/Shape3D.java +42 -0
- data/src/toxi/geom/SingularMatrixException.java +57 -0
- data/src/toxi/geom/SpatialBins.java +182 -0
- data/src/toxi/geom/SpatialIndex.java +61 -0
- data/src/toxi/geom/Sphere.java +224 -0
- data/src/toxi/geom/SphereIntersectorReflector.java +196 -0
- data/src/toxi/geom/Spline2D.java +349 -0
- data/src/toxi/geom/Spline3D.java +351 -0
- data/src/toxi/geom/SutherlandHodgemanClipper.java +151 -0
- data/src/toxi/geom/Triangle2D.java +422 -0
- data/src/toxi/geom/Triangle3D.java +456 -0
- data/src/toxi/geom/TriangleIntersector.java +105 -0
- data/src/toxi/geom/Vec2D.java +1328 -0
- data/src/toxi/geom/Vec3D.java +1832 -0
- data/src/toxi/geom/Vec4D.java +985 -0
- data/src/toxi/geom/VecMathUtil.java +100 -0
- data/src/toxi/geom/XAxisCylinder.java +64 -0
- data/src/toxi/geom/YAxisCylinder.java +65 -0
- data/src/toxi/geom/ZAxisCylinder.java +64 -0
- data/src/toxi/geom/mesh/BezierPatch.java +200 -0
- data/src/toxi/geom/mesh/BoxSelector.java +62 -0
- data/src/toxi/geom/mesh/DefaultSTLColorModel.java +67 -0
- data/src/toxi/geom/mesh/DefaultSelector.java +50 -0
- data/src/toxi/geom/mesh/Face.java +176 -0
- data/src/toxi/geom/mesh/LaplacianSmooth.java +80 -0
- data/src/toxi/geom/mesh/MaterialiseSTLColorModel.java +150 -0
- data/src/toxi/geom/mesh/Mesh3D.java +224 -0
- data/src/toxi/geom/mesh/MeshIntersector.java +91 -0
- data/src/toxi/geom/mesh/OBJWriter.java +194 -0
- data/src/toxi/geom/mesh/PLYWriter.java +167 -0
- data/src/toxi/geom/mesh/PlaneSelector.java +90 -0
- data/src/toxi/geom/mesh/STLColorModel.java +54 -0
- data/src/toxi/geom/mesh/STLReader.java +185 -0
- data/src/toxi/geom/mesh/STLWriter.java +323 -0
- data/src/toxi/geom/mesh/SphereFunction.java +156 -0
- data/src/toxi/geom/mesh/SphericalHarmonics.java +110 -0
- data/src/toxi/geom/mesh/SuperEllipsoid.java +110 -0
- data/src/toxi/geom/mesh/SurfaceFunction.java +75 -0
- data/src/toxi/geom/mesh/SurfaceMeshBuilder.java +149 -0
- data/src/toxi/geom/mesh/Terrain.java +451 -0
- data/src/toxi/geom/mesh/TriangleMesh.java +1201 -0
- data/src/toxi/geom/mesh/Vertex.java +78 -0
- data/src/toxi/geom/mesh/VertexSelector.java +193 -0
- data/src/toxi/geom/mesh/WEFace.java +100 -0
- data/src/toxi/geom/mesh/WEMeshFilterStrategy.java +51 -0
- data/src/toxi/geom/mesh/WETriangleMesh.java +761 -0
- data/src/toxi/geom/mesh/WEVertex.java +134 -0
- data/src/toxi/geom/mesh/WingedEdge.java +115 -0
- data/src/toxi/geom/mesh/subdiv/CentroidSubdiv.java +37 -0
- data/src/toxi/geom/mesh/subdiv/DisplacementSubdivision.java +85 -0
- data/src/toxi/geom/mesh/subdiv/DualDisplacementSubdivision.java +94 -0
- data/src/toxi/geom/mesh/subdiv/DualSubdivision.java +49 -0
- data/src/toxi/geom/mesh/subdiv/EdgeLengthComparator.java +50 -0
- data/src/toxi/geom/mesh/subdiv/FaceCountComparator.java +51 -0
- data/src/toxi/geom/mesh/subdiv/MidpointDisplacementSubdivision.java +80 -0
- data/src/toxi/geom/mesh/subdiv/MidpointSubdiv.java +42 -0
- data/src/toxi/geom/mesh/subdiv/MidpointSubdivision.java +48 -0
- data/src/toxi/geom/mesh/subdiv/NewSubdivStrategy.java +23 -0
- data/src/toxi/geom/mesh/subdiv/NormalDisplacementSubdivision.java +74 -0
- data/src/toxi/geom/mesh/subdiv/SubdivisionStrategy.java +83 -0
- data/src/toxi/geom/mesh/subdiv/TriSubdivision.java +51 -0
- data/src/toxi/geom/mesh2d/DelaunayTriangle.java +222 -0
- data/src/toxi/geom/mesh2d/DelaunayTriangulation.java +327 -0
- data/src/toxi/geom/mesh2d/DelaunayVertex.java +560 -0
- data/src/toxi/geom/mesh2d/Voronoi.java +149 -0
- data/src/toxi/geom/nurbs/BasicNurbsCurve.java +210 -0
- data/src/toxi/geom/nurbs/BasicNurbsSurface.java +233 -0
- data/src/toxi/geom/nurbs/ControlNet.java +148 -0
- data/src/toxi/geom/nurbs/CurveCreator.java +112 -0
- data/src/toxi/geom/nurbs/CurveUtils.java +259 -0
- data/src/toxi/geom/nurbs/InterpolationException.java +65 -0
- data/src/toxi/geom/nurbs/KnotVector.java +333 -0
- data/src/toxi/geom/nurbs/NurbsCreator.java +815 -0
- data/src/toxi/geom/nurbs/NurbsCurve.java +120 -0
- data/src/toxi/geom/nurbs/NurbsMeshCreator.java +145 -0
- data/src/toxi/geom/nurbs/NurbsSurface.java +147 -0
- data/src/toxi/image/util/Filter8bit.java +331 -0
- data/src/toxi/image/util/TiledFrameExporter.java +162 -0
- data/src/toxi/math/BezierInterpolation.java +102 -0
- data/src/toxi/math/CircularInterpolation.java +88 -0
- data/src/toxi/math/CosineInterpolation.java +51 -0
- data/src/toxi/math/DecimatedInterpolation.java +77 -0
- data/src/toxi/math/ExponentialInterpolation.java +68 -0
- data/src/toxi/math/InterpolateStrategy.java +60 -0
- data/src/toxi/math/Interpolation2D.java +93 -0
- data/src/toxi/math/LinearInterpolation.java +46 -0
- data/src/toxi/math/MathUtils.java +990 -0
- data/src/toxi/math/NonLinearScaleMap.java +101 -0
- data/src/toxi/math/ScaleMap.java +183 -0
- data/src/toxi/math/SigmoidInterpolation.java +78 -0
- data/src/toxi/math/SinCosLUT.java +141 -0
- data/src/toxi/math/ThresholdInterpolation.java +58 -0
- data/src/toxi/math/ZoomLensInterpolation.java +126 -0
- data/src/toxi/math/conversion/UnitTranslator.java +161 -0
- data/src/toxi/math/noise/PerlinNoise.java +281 -0
- data/src/toxi/math/noise/SimplexNoise.java +542 -0
- data/src/toxi/math/waves/AMFMSineWave.java +143 -0
- data/src/toxi/math/waves/AbstractWave.java +248 -0
- data/src/toxi/math/waves/ConstantWave.java +48 -0
- data/src/toxi/math/waves/FMHarmonicSquareWave.java +155 -0
- data/src/toxi/math/waves/FMSawtoothWave.java +144 -0
- data/src/toxi/math/waves/FMSineWave.java +142 -0
- data/src/toxi/math/waves/FMSquareWave.java +143 -0
- data/src/toxi/math/waves/FMTriangleWave.java +126 -0
- data/src/toxi/math/waves/SineWave.java +81 -0
- data/src/toxi/math/waves/Wave2D.java +68 -0
- data/src/toxi/math/waves/WaveState.java +69 -0
- data/src/toxi/music/scale/AbstractScale.java +117 -0
- data/src/toxi/music/scale/GenericScale.java +66 -0
- data/src/toxi/music/scale/MajorScale.java +41 -0
- data/src/toxi/newmesh/AttributedEdge.java +106 -0
- data/src/toxi/newmesh/AttributedFace.java +63 -0
- data/src/toxi/newmesh/IndexedTriangleMesh.java +809 -0
- data/src/toxi/newmesh/MeshAttributeCompiler.java +45 -0
- data/src/toxi/newmesh/MeshFaceNormalCompiler.java +52 -0
- data/src/toxi/newmesh/MeshUVCompiler.java +52 -0
- data/src/toxi/newmesh/MeshVertexColorCompiler.java +49 -0
- data/src/toxi/newmesh/MeshVertexCompiler.java +54 -0
- data/src/toxi/newmesh/MeshVertexNormalCompiler.java +55 -0
- data/src/toxi/newmesh/SpatialIndex.java +78 -0
- data/src/toxi/physics2d/ParticlePath2D.java +100 -0
- data/src/toxi/physics2d/ParticleString2D.java +184 -0
- data/src/toxi/physics2d/PullBackSpring2D.java +51 -0
- data/src/toxi/physics2d/VerletConstrainedSpring2D.java +89 -0
- data/src/toxi/physics2d/VerletMinDistanceSpring2D.java +57 -0
- data/src/toxi/physics2d/VerletParticle2D.java +457 -0
- data/src/toxi/physics2d/VerletPhysics2D.java +448 -0
- data/src/toxi/physics2d/VerletSpring2D.java +181 -0
- data/src/toxi/physics2d/behaviors/AttractionBehavior2D.java +212 -0
- data/src/toxi/physics2d/behaviors/ConstantForceBehavior2D.java +112 -0
- data/src/toxi/physics2d/behaviors/GravityBehavior2D.java +61 -0
- data/src/toxi/physics2d/behaviors/ParticleBehavior2D.java +66 -0
- data/src/toxi/physics2d/constraints/AngularConstraint.java +83 -0
- data/src/toxi/physics2d/constraints/AxisConstraint.java +71 -0
- data/src/toxi/physics2d/constraints/CircularConstraint.java +69 -0
- data/src/toxi/physics2d/constraints/MaxConstraint.java +66 -0
- data/src/toxi/physics2d/constraints/MinConstraint.java +66 -0
- data/src/toxi/physics2d/constraints/ParticleConstraint2D.java +47 -0
- data/src/toxi/physics2d/constraints/PolygonConstraint.java +93 -0
- data/src/toxi/physics2d/constraints/RectConstraint.java +114 -0
- data/src/toxi/physics3d/ParticlePath3D.java +100 -0
- data/src/toxi/physics3d/ParticleString3D.java +184 -0
- data/src/toxi/physics3d/PullBackSpring3D.java +50 -0
- data/src/toxi/physics3d/VerletConstrainedSpring3D.java +88 -0
- data/src/toxi/physics3d/VerletMinDistanceSpring3D.java +56 -0
- data/src/toxi/physics3d/VerletParticle3D.java +385 -0
- data/src/toxi/physics3d/VerletPhysics3D.java +417 -0
- data/src/toxi/physics3d/VerletSpring3D.java +180 -0
- data/src/toxi/physics3d/behaviors/AttractionBehavior3D.java +182 -0
- data/src/toxi/physics3d/behaviors/ConstantForceBehavior3D.java +92 -0
- data/src/toxi/physics3d/behaviors/GravityBehavior3D.java +61 -0
- data/src/toxi/physics3d/behaviors/ParticleBehavior3D.java +52 -0
- data/src/toxi/physics3d/constraints/AxisConstraint.java +68 -0
- data/src/toxi/physics3d/constraints/BoxConstraint.java +121 -0
- data/src/toxi/physics3d/constraints/CylinderConstraint.java +87 -0
- data/src/toxi/physics3d/constraints/MaxConstraint.java +65 -0
- data/src/toxi/physics3d/constraints/MinConstraint.java +65 -0
- data/src/toxi/physics3d/constraints/ParticleConstraint3D.java +49 -0
- data/src/toxi/physics3d/constraints/PlaneConstraint.java +78 -0
- data/src/toxi/physics3d/constraints/SoftBoxConstraint.java +87 -0
- data/src/toxi/physics3d/constraints/SphereConstraint.java +108 -0
- data/src/toxi/processing/ArrowModifier.java +116 -0
- data/src/toxi/processing/DashedLineModifier.java +48 -0
- data/src/toxi/processing/DeltaOrientationMapper.java +57 -0
- data/src/toxi/processing/Line2DRenderModifier.java +18 -0
- data/src/toxi/processing/MeshToVBO.java +94 -0
- data/src/toxi/processing/NormalMapper.java +18 -0
- data/src/toxi/processing/POVInterface.java +121 -0
- data/src/toxi/processing/POVMesh.java +219 -0
- data/src/toxi/processing/POVWriter.java +460 -0
- data/src/toxi/processing/RCOpaque.java +77 -0
- data/src/toxi/processing/RCTransp.java +78 -0
- data/src/toxi/processing/TextureBuilder.java +232 -0
- data/src/toxi/processing/Textures.java +110 -0
- data/src/toxi/processing/ToxiclibsSupport.java +1239 -0
- data/src/toxi/processing/Tracing.java +25 -0
- data/src/toxi/processing/XYZNormalMapper.java +30 -0
- data/src/toxi/sim/automata/CAMatrix.java +297 -0
- data/src/toxi/sim/automata/CARule.java +76 -0
- data/src/toxi/sim/automata/CARule2D.java +354 -0
- data/src/toxi/sim/automata/CAWolfram1D.java +309 -0
- data/src/toxi/sim/automata/EvolvableMatrix.java +61 -0
- data/src/toxi/sim/automata/MatrixEvolver.java +42 -0
- data/src/toxi/sim/dla/BottomUpOrder.java +76 -0
- data/src/toxi/sim/dla/DLA.java +497 -0
- data/src/toxi/sim/dla/DLAConfiguration.java +364 -0
- data/src/toxi/sim/dla/DLAEventAdapter.java +64 -0
- data/src/toxi/sim/dla/DLAEventListener.java +57 -0
- data/src/toxi/sim/dla/DLAGuideLines.java +219 -0
- data/src/toxi/sim/dla/DLAParticle.java +102 -0
- data/src/toxi/sim/dla/DLASegment.java +88 -0
- data/src/toxi/sim/dla/PipelineOrder.java +50 -0
- data/src/toxi/sim/dla/RadialDistanceOrder.java +92 -0
- data/src/toxi/sim/erosion/ErosionFunction.java +122 -0
- data/src/toxi/sim/erosion/TalusAngleErosion.java +145 -0
- data/src/toxi/sim/erosion/ThermalErosion.java +75 -0
- data/src/toxi/sim/fluids/FluidSolver2D.java +762 -0
- data/src/toxi/sim/fluids/FluidSolver3D.java +326 -0
- data/src/toxi/sim/grayscott/GrayScott.java +469 -0
- data/src/toxi/util/DateUtils.java +141 -0
- data/src/toxi/util/FileSequenceDescriptor.java +181 -0
- data/src/toxi/util/FileUtils.java +467 -0
- data/src/toxi/util/datatypes/ArraySet.java +128 -0
- data/src/toxi/util/datatypes/ArrayUtil.java +404 -0
- data/src/toxi/util/datatypes/BiasedDoubleRange.java +141 -0
- data/src/toxi/util/datatypes/BiasedFloatRange.java +141 -0
- data/src/toxi/util/datatypes/BiasedIntegerRange.java +141 -0
- data/src/toxi/util/datatypes/DoubleRange.java +251 -0
- data/src/toxi/util/datatypes/FloatRange.java +251 -0
- data/src/toxi/util/datatypes/GenericSet.java +215 -0
- data/src/toxi/util/datatypes/IntegerRange.java +247 -0
- data/src/toxi/util/datatypes/IntegerSet.java +149 -0
- data/src/toxi/util/datatypes/ItemIndex.java +72 -0
- data/src/toxi/util/datatypes/SingletonRegistry.java +91 -0
- data/src/toxi/util/datatypes/TypedProperties.java +291 -0
- data/src/toxi/util/datatypes/UndirectedGraph.java +134 -0
- data/src/toxi/util/datatypes/UniqueItemIndex.java +223 -0
- data/src/toxi/util/datatypes/WeightedRandomEntry.java +76 -0
- data/src/toxi/util/datatypes/WeightedRandomSet.java +125 -0
- data/src/toxi/util/events/EventDispatcher.java +86 -0
- data/src/toxi/volume/AdditiveBrush.java +19 -0
- data/src/toxi/volume/ArrayIsoSurface.java +297 -0
- data/src/toxi/volume/BoxBrush.java +100 -0
- data/src/toxi/volume/BrushMode.java +16 -0
- data/src/toxi/volume/HashIsoSurface.java +354 -0
- data/src/toxi/volume/IsoSurface.java +59 -0
- data/src/toxi/volume/MarchingCubesIndex.java +312 -0
- data/src/toxi/volume/MeshLatticeBuilder.java +358 -0
- data/src/toxi/volume/MeshVoxelizer.java +216 -0
- data/src/toxi/volume/MultiplyBrush.java +20 -0
- data/src/toxi/volume/PeakBrush.java +21 -0
- data/src/toxi/volume/ReplaceBrush.java +19 -0
- data/src/toxi/volume/RoundBrush.java +113 -0
- data/src/toxi/volume/VolumetricBrush.java +160 -0
- data/src/toxi/volume/VolumetricHashMap.java +179 -0
- data/src/toxi/volume/VolumetricSpace.java +195 -0
- data/src/toxi/volume/VolumetricSpaceArray.java +214 -0
- data/toxiclibs.gemspec +34 -0
- metadata +424 -27
|
@@ -0,0 +1,1201 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* __ .__ .__ ._____.
|
|
3
|
+
* _/ |_ _______ __|__| ____ | | |__\_ |__ ______
|
|
4
|
+
* \ __\/ _ \ \/ / |/ ___\| | | || __ \ / ___/
|
|
5
|
+
* | | ( <_> > <| \ \___| |_| || \_\ \\___ \
|
|
6
|
+
* |__| \____/__/\_ \__|\___ >____/__||___ /____ >
|
|
7
|
+
* \/ \/ \/ \/
|
|
8
|
+
*
|
|
9
|
+
* Copyright (c) 2006-2011 Karsten Schmidt
|
|
10
|
+
*
|
|
11
|
+
* This library is free software; you can redistribute it and/or
|
|
12
|
+
* modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
* License as published by the Free Software Foundation; either
|
|
14
|
+
* version 2.1 of the License, or (at your option) any later version.
|
|
15
|
+
*
|
|
16
|
+
* http://creativecommons.org/licenses/LGPL/2.1/
|
|
17
|
+
*
|
|
18
|
+
* This library is distributed in the hope that it will be useful,
|
|
19
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
21
|
+
* Lesser General Public License for more details.
|
|
22
|
+
*
|
|
23
|
+
* You should have received a copy of the GNU Lesser General Public
|
|
24
|
+
* License along with this library; if not, write to the Free Software
|
|
25
|
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
package toxi.geom.mesh;
|
|
29
|
+
|
|
30
|
+
import java.io.OutputStream;
|
|
31
|
+
import java.util.ArrayList;
|
|
32
|
+
import java.util.Collection;
|
|
33
|
+
import java.util.LinkedHashMap;
|
|
34
|
+
import java.util.List;
|
|
35
|
+
import java.util.logging.Level;
|
|
36
|
+
import java.util.logging.Logger;
|
|
37
|
+
|
|
38
|
+
import toxi.geom.AABB;
|
|
39
|
+
import toxi.geom.Intersector3D;
|
|
40
|
+
import toxi.geom.IsectData3D;
|
|
41
|
+
import toxi.geom.Matrix4x4;
|
|
42
|
+
import toxi.geom.Quaternion;
|
|
43
|
+
import toxi.geom.Ray3D;
|
|
44
|
+
import toxi.geom.ReadonlyVec3D;
|
|
45
|
+
import toxi.geom.Sphere;
|
|
46
|
+
import toxi.geom.Triangle3D;
|
|
47
|
+
import toxi.geom.TriangleIntersector;
|
|
48
|
+
import toxi.geom.Vec2D;
|
|
49
|
+
import toxi.geom.Vec3D;
|
|
50
|
+
import toxi.math.MathUtils;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* An extensible class to dynamically build, manipulate & export triangle
|
|
54
|
+
* meshes. Meshes are built face by face. This implementation automatically
|
|
55
|
+
* re-uses existing vertices and can generate smooth vertex normals. Vertice and
|
|
56
|
+
* face lists are directly accessible for speed & convenience.
|
|
57
|
+
*/
|
|
58
|
+
public class TriangleMesh implements Mesh3D, Intersector3D {
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Default size for vertex list
|
|
62
|
+
*/
|
|
63
|
+
public static final int DEFAULT_NUM_VERTICES = 1000;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Default size for face list
|
|
67
|
+
*/
|
|
68
|
+
public static final int DEFAULT_NUM_FACES = 3000;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Default stride setting used for serializing mesh properties into arrays.
|
|
72
|
+
*/
|
|
73
|
+
public static final int DEFAULT_STRIDE = 4;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
*
|
|
77
|
+
*/
|
|
78
|
+
protected static final Logger logger = Logger.getLogger(TriangleMesh.class
|
|
79
|
+
.getName());
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Mesh name
|
|
83
|
+
*/
|
|
84
|
+
public String name;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Vertex buffer & lookup index when adding new faces
|
|
88
|
+
*/
|
|
89
|
+
public LinkedHashMap<Vec3D, Vertex> vertices;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Face list
|
|
93
|
+
*/
|
|
94
|
+
public ArrayList<Face> faces;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
*/
|
|
99
|
+
protected AABB bounds;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
*
|
|
103
|
+
*/
|
|
104
|
+
protected Vec3D centroid = new Vec3D();
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
*
|
|
108
|
+
*/
|
|
109
|
+
protected int numVertices;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
*
|
|
113
|
+
*/
|
|
114
|
+
protected int numFaces;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
*
|
|
118
|
+
*/
|
|
119
|
+
protected Matrix4x4 matrix = new Matrix4x4();
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
*
|
|
123
|
+
*/
|
|
124
|
+
protected TriangleIntersector intersector = new TriangleIntersector();
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
*
|
|
128
|
+
*/
|
|
129
|
+
protected int uniqueVertexID;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
*
|
|
133
|
+
*/
|
|
134
|
+
public TriangleMesh() {
|
|
135
|
+
this("untitled");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Creates a new mesh instance with initial default buffer sizes.
|
|
140
|
+
*
|
|
141
|
+
* @param name
|
|
142
|
+
* mesh name
|
|
143
|
+
*/
|
|
144
|
+
public TriangleMesh(String name) {
|
|
145
|
+
this(name, DEFAULT_NUM_VERTICES, DEFAULT_NUM_FACES);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Creates a new mesh instance with the given initial buffer sizes. These
|
|
150
|
+
* numbers are no limits and the mesh can be smaller or grow later on.
|
|
151
|
+
* They're only used to initialise the underlying collections.
|
|
152
|
+
*
|
|
153
|
+
* @param name
|
|
154
|
+
* mesh name
|
|
155
|
+
* @param numV
|
|
156
|
+
* initial vertex buffer size
|
|
157
|
+
* @param numF
|
|
158
|
+
* initial face list size
|
|
159
|
+
*/
|
|
160
|
+
public TriangleMesh(String name, int numV, int numF) {
|
|
161
|
+
init(name, numV, numF);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@Override
|
|
165
|
+
public TriangleMesh addFace(Vec3D a, Vec3D b, Vec3D c) {
|
|
166
|
+
return addFace(a, b, c, null, null, null, null);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@Override
|
|
170
|
+
public TriangleMesh addFace(Vec3D a, Vec3D b, Vec3D c, Vec2D uvA,
|
|
171
|
+
Vec2D uvB, Vec2D uvC) {
|
|
172
|
+
return addFace(a, b, c, null, uvA, uvB, uvC);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
*
|
|
177
|
+
* @param a
|
|
178
|
+
* @param b
|
|
179
|
+
* @param c
|
|
180
|
+
* @param n
|
|
181
|
+
* @return
|
|
182
|
+
*/
|
|
183
|
+
@Override
|
|
184
|
+
public TriangleMesh addFace(Vec3D a, Vec3D b, Vec3D c, Vec3D n) {
|
|
185
|
+
return addFace(a, b, c, n, null, null, null);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
*
|
|
190
|
+
* @param a
|
|
191
|
+
* @param b
|
|
192
|
+
* @param c
|
|
193
|
+
* @param n
|
|
194
|
+
* @param uvA
|
|
195
|
+
* @param uvB
|
|
196
|
+
* @param uvC
|
|
197
|
+
* @return
|
|
198
|
+
*/
|
|
199
|
+
@Override
|
|
200
|
+
public TriangleMesh addFace(Vec3D a, Vec3D b, Vec3D c, Vec3D n, Vec2D uvA,
|
|
201
|
+
Vec2D uvB, Vec2D uvC) {
|
|
202
|
+
Vertex va = checkVertex(a);
|
|
203
|
+
Vertex vb = checkVertex(b);
|
|
204
|
+
Vertex vc = checkVertex(c);
|
|
205
|
+
if (va.id == vb.id || va.id == vc.id || vb.id == vc.id) {
|
|
206
|
+
if (logger.isLoggable(Level.FINE)) {
|
|
207
|
+
logger.log(Level.FINE, "ignorning invalid face: {0},{1},{2}", new Object[]{a, b, c});
|
|
208
|
+
}
|
|
209
|
+
} else {
|
|
210
|
+
if (n != null) {
|
|
211
|
+
Vec3D nc = va.sub(vc).crossSelf(va.sub(vb));
|
|
212
|
+
if (n.dot(nc) < 0) {
|
|
213
|
+
Vertex t = va;
|
|
214
|
+
va = vb;
|
|
215
|
+
vb = t;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
Face f = new Face(va, vb, vc, uvA, uvB, uvC);
|
|
219
|
+
faces.add(f);
|
|
220
|
+
numFaces++;
|
|
221
|
+
}
|
|
222
|
+
return this;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Adds all faces from the given mesh to this one.
|
|
227
|
+
*
|
|
228
|
+
* @param m
|
|
229
|
+
* source mesh instance
|
|
230
|
+
* @return
|
|
231
|
+
*/
|
|
232
|
+
@Override
|
|
233
|
+
public TriangleMesh addMesh(Mesh3D m) {
|
|
234
|
+
m.getFaces().stream().forEach((f) -> {
|
|
235
|
+
addFace(f.a, f.b, f.c, f.uvA, f.uvB, f.uvC);
|
|
236
|
+
});
|
|
237
|
+
return this;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@Override
|
|
241
|
+
public AABB center(ReadonlyVec3D origin) {
|
|
242
|
+
computeCentroid();
|
|
243
|
+
Vec3D delta = origin != null ? origin.sub(centroid) : centroid
|
|
244
|
+
.getInverted();
|
|
245
|
+
vertices.values().stream().forEach((v) -> {
|
|
246
|
+
v.addSelf(delta);
|
|
247
|
+
});
|
|
248
|
+
getBoundingBox();
|
|
249
|
+
return bounds;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private Vertex checkVertex(Vec3D v) {
|
|
253
|
+
Vertex vertex = vertices.get(v);
|
|
254
|
+
if (vertex == null) {
|
|
255
|
+
vertex = createVertex(v, uniqueVertexID++);
|
|
256
|
+
vertices.put(vertex, vertex);
|
|
257
|
+
numVertices++;
|
|
258
|
+
}
|
|
259
|
+
return vertex;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Clears all counters, and vertex & face buffers.
|
|
264
|
+
*/
|
|
265
|
+
@Override
|
|
266
|
+
public TriangleMesh clear() {
|
|
267
|
+
vertices.clear();
|
|
268
|
+
faces.clear();
|
|
269
|
+
bounds = null;
|
|
270
|
+
numVertices = 0;
|
|
271
|
+
numFaces = 0;
|
|
272
|
+
uniqueVertexID = 0;
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
@Override
|
|
277
|
+
public Vec3D computeCentroid() {
|
|
278
|
+
centroid.clear();
|
|
279
|
+
vertices.values().stream().forEach((v) -> {
|
|
280
|
+
centroid.addSelf(v);
|
|
281
|
+
});
|
|
282
|
+
return centroid.scaleSelf(1f / numVertices).copy();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Re-calculates all face normals.
|
|
287
|
+
*/
|
|
288
|
+
@Override
|
|
289
|
+
public TriangleMesh computeFaceNormals() {
|
|
290
|
+
faces.stream().forEach((f) -> {
|
|
291
|
+
f.computeNormal();
|
|
292
|
+
});
|
|
293
|
+
return this;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Computes the smooth vertex normals for the entire mesh.
|
|
298
|
+
*/
|
|
299
|
+
@Override
|
|
300
|
+
public TriangleMesh computeVertexNormals() {
|
|
301
|
+
vertices.values().stream().forEach((v) -> {
|
|
302
|
+
v.clearNormal();
|
|
303
|
+
});
|
|
304
|
+
faces.stream().map((f) -> {
|
|
305
|
+
f.a.addFaceNormal(f.normal);
|
|
306
|
+
return f;
|
|
307
|
+
}).map((f) -> {
|
|
308
|
+
f.b.addFaceNormal(f.normal);
|
|
309
|
+
return f;
|
|
310
|
+
}).forEach((f) -> {
|
|
311
|
+
f.c.addFaceNormal(f.normal);
|
|
312
|
+
});
|
|
313
|
+
vertices.values().stream().forEach((v) -> {
|
|
314
|
+
v.computeNormal();
|
|
315
|
+
});
|
|
316
|
+
return this;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Creates a deep clone of the mesh. The new mesh name will have "-copy" as
|
|
321
|
+
* suffix.
|
|
322
|
+
*
|
|
323
|
+
* @return new mesh instance
|
|
324
|
+
*/
|
|
325
|
+
public TriangleMesh copy() {
|
|
326
|
+
TriangleMesh m = new TriangleMesh(name + "-copy", numVertices, numFaces);
|
|
327
|
+
faces.stream().forEach((f) -> {
|
|
328
|
+
m.addFace(f.a, f.b, f.c, f.normal, f.uvA, f.uvB, f.uvC);
|
|
329
|
+
});
|
|
330
|
+
return m;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
*
|
|
335
|
+
* @param v
|
|
336
|
+
* @param id
|
|
337
|
+
* @return
|
|
338
|
+
*/
|
|
339
|
+
protected Vertex createVertex(Vec3D v, int id) {
|
|
340
|
+
return new Vertex(v, id);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
@Override
|
|
344
|
+
public TriangleMesh faceOutwards() {
|
|
345
|
+
computeCentroid();
|
|
346
|
+
faces.stream().forEach((f) -> {
|
|
347
|
+
Vec3D n = f.getCentroid().sub(centroid);
|
|
348
|
+
float dot = n.dot(f.normal);
|
|
349
|
+
if (dot < 0) {
|
|
350
|
+
f.flipVertexOrder();
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
return this;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
@Override
|
|
357
|
+
public TriangleMesh flipVertexOrder() {
|
|
358
|
+
faces.stream().map((f) -> {
|
|
359
|
+
Vertex t = f.a;
|
|
360
|
+
f.a = f.b;
|
|
361
|
+
f.b = t;
|
|
362
|
+
return f;
|
|
363
|
+
}).map((f) -> {
|
|
364
|
+
Vec2D tuv = f.uvA;
|
|
365
|
+
f.uvA = f.uvB;
|
|
366
|
+
f.uvB = tuv;
|
|
367
|
+
return f;
|
|
368
|
+
}).forEach((f) -> {
|
|
369
|
+
f.normal.invert();
|
|
370
|
+
});
|
|
371
|
+
return this;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
@Override
|
|
375
|
+
public TriangleMesh flipYAxis() {
|
|
376
|
+
transform(new Matrix4x4().scaleSelf(1, -1, 1));
|
|
377
|
+
flipVertexOrder();
|
|
378
|
+
return this;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
@Override
|
|
382
|
+
public AABB getBoundingBox() {
|
|
383
|
+
final Vec3D minBounds = Vec3D.MAX_VALUE.copy();
|
|
384
|
+
final Vec3D maxBounds = Vec3D.NEG_MAX_VALUE.copy();
|
|
385
|
+
vertices.values().stream().map((v) -> {
|
|
386
|
+
minBounds.minSelf(v);
|
|
387
|
+
return v;
|
|
388
|
+
}).forEach((v) -> {
|
|
389
|
+
maxBounds.maxSelf(v);
|
|
390
|
+
});
|
|
391
|
+
bounds = AABB.fromMinMax(minBounds, maxBounds);
|
|
392
|
+
return bounds;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
@Override
|
|
396
|
+
public Sphere getBoundingSphere() {
|
|
397
|
+
float radius = 0;
|
|
398
|
+
computeCentroid();
|
|
399
|
+
for (Vertex v : vertices.values()) {
|
|
400
|
+
radius = MathUtils.max(radius, v.distanceToSquared(centroid));
|
|
401
|
+
}
|
|
402
|
+
return new Sphere(centroid, (float) Math.sqrt(radius));
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
*
|
|
407
|
+
* @param p
|
|
408
|
+
* @return
|
|
409
|
+
*/
|
|
410
|
+
@Override
|
|
411
|
+
public Vertex getClosestVertexToPoint(ReadonlyVec3D p) {
|
|
412
|
+
Vertex closest = null;
|
|
413
|
+
float minDist = Float.MAX_VALUE;
|
|
414
|
+
for (Vertex v : vertices.values()) {
|
|
415
|
+
float d = v.distanceToSquared(p);
|
|
416
|
+
if (d < minDist) {
|
|
417
|
+
closest = v;
|
|
418
|
+
minDist = d;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return closest;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Creates an array of unravelled normal coordinates. For each vertex the
|
|
426
|
+
* normal vector of its parent face is used. This is a convienence
|
|
427
|
+
* invocation of {@link #getFaceNormalsAsArray(float[], int, int)} with a
|
|
428
|
+
* default stride = 4.
|
|
429
|
+
*
|
|
430
|
+
* @return array of xyz normal coords
|
|
431
|
+
*/
|
|
432
|
+
public float[] getFaceNormalsAsArray() {
|
|
433
|
+
return getFaceNormalsAsArray(null, 0, DEFAULT_STRIDE);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Creates an array of unravelled normal coordinates. For each vertex the
|
|
438
|
+
* normal vector of its parent face is used. This method can be used to
|
|
439
|
+
* translate the internal mesh data structure into a format suitable for
|
|
440
|
+
* OpenGL Vertex Buffer Objects (by choosing stride=4). For more detail,
|
|
441
|
+
* please see {@link #getMeshAsVertexArray(float[], int, int)}
|
|
442
|
+
*
|
|
443
|
+
* @see #getMeshAsVertexArray(float[], int, int)
|
|
444
|
+
*
|
|
445
|
+
* @param normals
|
|
446
|
+
* existing float array or null to automatically create one
|
|
447
|
+
* @param offset
|
|
448
|
+
* start index in array to place normals
|
|
449
|
+
* @param stride
|
|
450
|
+
* stride/alignment setting for individual coordinates (min value
|
|
451
|
+
* = 3)
|
|
452
|
+
* @return array of xyz normal coords
|
|
453
|
+
*/
|
|
454
|
+
public float[] getFaceNormalsAsArray(float[] normals, int offset, int stride) {
|
|
455
|
+
stride = MathUtils.max(stride, 3);
|
|
456
|
+
if (normals == null) {
|
|
457
|
+
normals = new float[faces.size() * 3 * stride];
|
|
458
|
+
}
|
|
459
|
+
int i = offset;
|
|
460
|
+
for (Face f : faces) {
|
|
461
|
+
normals[i] = f.normal.x;
|
|
462
|
+
normals[i + 1] = f.normal.y;
|
|
463
|
+
normals[i + 2] = f.normal.z;
|
|
464
|
+
i += stride;
|
|
465
|
+
normals[i] = f.normal.x;
|
|
466
|
+
normals[i + 1] = f.normal.y;
|
|
467
|
+
normals[i + 2] = f.normal.z;
|
|
468
|
+
i += stride;
|
|
469
|
+
normals[i] = f.normal.x;
|
|
470
|
+
normals[i + 1] = f.normal.y;
|
|
471
|
+
normals[i + 2] = f.normal.z;
|
|
472
|
+
i += stride;
|
|
473
|
+
}
|
|
474
|
+
return normals;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
*
|
|
479
|
+
* @return
|
|
480
|
+
*/
|
|
481
|
+
@Override
|
|
482
|
+
public List<Face> getFaces() {
|
|
483
|
+
return faces;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Builds an array of vertex indices of all faces. Each vertex ID
|
|
488
|
+
* corresponds to its position in the {@link #vertices} HashMap. The
|
|
489
|
+
* resulting array will be 3 times the face count.
|
|
490
|
+
*
|
|
491
|
+
* @return array of vertex indices
|
|
492
|
+
*/
|
|
493
|
+
public int[] getFacesAsArray() {
|
|
494
|
+
int[] faceList = new int[faces.size() * 3];
|
|
495
|
+
int i = 0;
|
|
496
|
+
for (Face f : faces) {
|
|
497
|
+
faceList[i++] = f.a.id;
|
|
498
|
+
faceList[i++] = f.b.id;
|
|
499
|
+
faceList[i++] = f.c.id;
|
|
500
|
+
}
|
|
501
|
+
return faceList;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
@Override
|
|
505
|
+
public IsectData3D getIntersectionData() {
|
|
506
|
+
return intersector.getIntersectionData();
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Creates an array of unravelled vertex coordinates for all faces using a
|
|
511
|
+
* stride setting of 4, resulting in a serialized version of all mesh vertex
|
|
512
|
+
* coordinates suitable for VBOs.
|
|
513
|
+
*
|
|
514
|
+
* @see #getMeshAsVertexArray(float[], int, int)
|
|
515
|
+
* @return float array of vertex coordinates
|
|
516
|
+
*/
|
|
517
|
+
public float[] getMeshAsVertexArray() {
|
|
518
|
+
return getMeshAsVertexArray(null, 0, DEFAULT_STRIDE);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Creates an array of unravelled vertex coordinates for all faces. This
|
|
523
|
+
* method can be used to translate the internal mesh data structure into a
|
|
524
|
+
* format suitable for OpenGL Vertex Buffer Objects (by choosing stride=4).
|
|
525
|
+
* The order of the array will be as follows:
|
|
526
|
+
*
|
|
527
|
+
* <ul>
|
|
528
|
+
* <li>Face 1:
|
|
529
|
+
* <ul>
|
|
530
|
+
* <li>Vertex #1
|
|
531
|
+
* <ul>
|
|
532
|
+
* <li>x</li>
|
|
533
|
+
* <li>y</li>
|
|
534
|
+
* <li>z</li>
|
|
535
|
+
* <li>[optional empty indices to match stride setting]</li>
|
|
536
|
+
* </ul>
|
|
537
|
+
* </li>
|
|
538
|
+
* <li>Vertex #2
|
|
539
|
+
* <ul>
|
|
540
|
+
* <li>x</li>
|
|
541
|
+
* <li>y</li>
|
|
542
|
+
* <li>z</li>
|
|
543
|
+
* <li>[optional empty indices to match stride setting]</li>
|
|
544
|
+
* </ul>
|
|
545
|
+
* </li>
|
|
546
|
+
* <li>Vertex #3
|
|
547
|
+
* <ul>
|
|
548
|
+
* <li>x</li>
|
|
549
|
+
* <li>y</li>
|
|
550
|
+
* <li>z</li>
|
|
551
|
+
* <li>[optional empty indices to match stride setting]</li>
|
|
552
|
+
* </ul>
|
|
553
|
+
* </li>
|
|
554
|
+
* </ul>
|
|
555
|
+
* <li>Face 2:
|
|
556
|
+
* <ul>
|
|
557
|
+
* <li>Vertex #1</li>
|
|
558
|
+
* <li>...etc.</li>
|
|
559
|
+
* </ul>
|
|
560
|
+
* </ul>
|
|
561
|
+
*
|
|
562
|
+
* @param verts
|
|
563
|
+
* an existing target array or null to automatically create one
|
|
564
|
+
* @param offset
|
|
565
|
+
* start index in arrtay to place vertices
|
|
566
|
+
* @param stride
|
|
567
|
+
* stride/alignment setting for individual coordinates
|
|
568
|
+
* @return array of xyz vertex coords
|
|
569
|
+
*/
|
|
570
|
+
public float[] getMeshAsVertexArray(float[] verts, int offset, int stride) {
|
|
571
|
+
stride = MathUtils.max(stride, 3);
|
|
572
|
+
if (verts == null) {
|
|
573
|
+
verts = new float[faces.size() * 3 * stride];
|
|
574
|
+
}
|
|
575
|
+
int i = offset;
|
|
576
|
+
for (Face f : faces) {
|
|
577
|
+
verts[i] = f.a.x;
|
|
578
|
+
verts[i + 1] = f.a.y;
|
|
579
|
+
verts[i + 2] = f.a.z;
|
|
580
|
+
i += stride;
|
|
581
|
+
verts[i] = f.b.x;
|
|
582
|
+
verts[i + 1] = f.b.y;
|
|
583
|
+
verts[i + 2] = f.b.z;
|
|
584
|
+
i += stride;
|
|
585
|
+
verts[i] = f.c.x;
|
|
586
|
+
verts[i + 1] = f.c.y;
|
|
587
|
+
verts[i + 2] = f.c.z;
|
|
588
|
+
i += stride;
|
|
589
|
+
}
|
|
590
|
+
return verts;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
*
|
|
595
|
+
* @return
|
|
596
|
+
*/
|
|
597
|
+
public float[] getNormalsForUniqueVerticesAsArray() {
|
|
598
|
+
float[] normals = new float[numVertices * 3];
|
|
599
|
+
int i = 0;
|
|
600
|
+
for (Vertex v : vertices.values()) {
|
|
601
|
+
normals[i++] = v.normal.x;
|
|
602
|
+
normals[i++] = v.normal.y;
|
|
603
|
+
normals[i++] = v.normal.z;
|
|
604
|
+
}
|
|
605
|
+
return normals;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
@Override
|
|
609
|
+
public int getNumFaces() {
|
|
610
|
+
return numFaces;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
@Override
|
|
614
|
+
public int getNumVertices() {
|
|
615
|
+
return numVertices;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
*
|
|
620
|
+
* @param axis
|
|
621
|
+
* @param theta
|
|
622
|
+
* @return
|
|
623
|
+
*/
|
|
624
|
+
public TriangleMesh getRotatedAroundAxis(Vec3D axis, float theta) {
|
|
625
|
+
return copy().rotateAroundAxis(axis, theta);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
*
|
|
630
|
+
* @param theta
|
|
631
|
+
* @return
|
|
632
|
+
*/
|
|
633
|
+
public TriangleMesh getRotatedX(float theta) {
|
|
634
|
+
return copy().rotateX(theta);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
*
|
|
639
|
+
* @param theta
|
|
640
|
+
* @return
|
|
641
|
+
*/
|
|
642
|
+
public TriangleMesh getRotatedY(float theta) {
|
|
643
|
+
return copy().rotateY(theta);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
*
|
|
648
|
+
* @param theta
|
|
649
|
+
* @return
|
|
650
|
+
*/
|
|
651
|
+
public TriangleMesh getRotatedZ(float theta) {
|
|
652
|
+
return copy().rotateZ(theta);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
*
|
|
657
|
+
* @param scale
|
|
658
|
+
* @return
|
|
659
|
+
*/
|
|
660
|
+
public TriangleMesh getScaled(float scale) {
|
|
661
|
+
return copy().scale(scale);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
*
|
|
666
|
+
* @param scale
|
|
667
|
+
* @return
|
|
668
|
+
*/
|
|
669
|
+
public TriangleMesh getScaled(Vec3D scale) {
|
|
670
|
+
return copy().scale(scale);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
*
|
|
675
|
+
* @param trans
|
|
676
|
+
* @return
|
|
677
|
+
*/
|
|
678
|
+
public TriangleMesh getTranslated(Vec3D trans) {
|
|
679
|
+
return copy().translate(trans);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
*
|
|
684
|
+
* @return
|
|
685
|
+
*/
|
|
686
|
+
public float[] getUniqueVerticesAsArray() {
|
|
687
|
+
float[] verts = new float[numVertices * 3];
|
|
688
|
+
int i = 0;
|
|
689
|
+
for (Vertex v : vertices.values()) {
|
|
690
|
+
verts[i++] = v.x;
|
|
691
|
+
verts[i++] = v.y;
|
|
692
|
+
verts[i++] = v.z;
|
|
693
|
+
}
|
|
694
|
+
return verts;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
*
|
|
699
|
+
* @param v
|
|
700
|
+
* @return
|
|
701
|
+
*/
|
|
702
|
+
public Vertex getVertexAtPoint(Vec3D v) {
|
|
703
|
+
return vertices.get(v);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
*
|
|
708
|
+
* @param id
|
|
709
|
+
* @return
|
|
710
|
+
*/
|
|
711
|
+
public Vertex getVertexForID(int id) {
|
|
712
|
+
Vertex vertex = null;
|
|
713
|
+
for (Vertex v : vertices.values()) {
|
|
714
|
+
if (v.id == id) {
|
|
715
|
+
vertex = v;
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return vertex;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Creates an array of unravelled vertex normal coordinates for all faces.
|
|
724
|
+
* Uses default stride = 4.
|
|
725
|
+
*
|
|
726
|
+
* @see #getVertexNormalsAsArray(float[], int, int)
|
|
727
|
+
* @return array of xyz normal coords
|
|
728
|
+
*/
|
|
729
|
+
public float[] getVertexNormalsAsArray() {
|
|
730
|
+
return getVertexNormalsAsArray(null, 0, DEFAULT_STRIDE);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Creates an array of unravelled vertex normal coordinates for all faces.
|
|
735
|
+
* This method can be used to translate the internal mesh data structure
|
|
736
|
+
* into a format suitable for OpenGL Vertex Buffer Objects (by choosing
|
|
737
|
+
* stride=4). For more detail, please see
|
|
738
|
+
* {@link #getMeshAsVertexArray(float[], int, int)}
|
|
739
|
+
*
|
|
740
|
+
* @see #getMeshAsVertexArray(float[], int, int)
|
|
741
|
+
*
|
|
742
|
+
* @param normals
|
|
743
|
+
* existing float array or null to automatically create one
|
|
744
|
+
* @param offset
|
|
745
|
+
* start index in array to place normals
|
|
746
|
+
* @param stride
|
|
747
|
+
* stride/alignment setting for individual coordinates (min value
|
|
748
|
+
* = 3)
|
|
749
|
+
* @return array of xyz normal coords
|
|
750
|
+
*/
|
|
751
|
+
public float[] getVertexNormalsAsArray(float[] normals, int offset,
|
|
752
|
+
int stride) {
|
|
753
|
+
stride = MathUtils.max(stride, 3);
|
|
754
|
+
if (normals == null) {
|
|
755
|
+
normals = new float[faces.size() * 3 * stride];
|
|
756
|
+
}
|
|
757
|
+
int i = offset;
|
|
758
|
+
for (Face f : faces) {
|
|
759
|
+
normals[i] = f.a.normal.x;
|
|
760
|
+
normals[i + 1] = f.a.normal.y;
|
|
761
|
+
normals[i + 2] = f.a.normal.z;
|
|
762
|
+
i += stride;
|
|
763
|
+
normals[i] = f.b.normal.x;
|
|
764
|
+
normals[i + 1] = f.b.normal.y;
|
|
765
|
+
normals[i + 2] = f.b.normal.z;
|
|
766
|
+
i += stride;
|
|
767
|
+
normals[i] = f.c.normal.x;
|
|
768
|
+
normals[i + 1] = f.c.normal.y;
|
|
769
|
+
normals[i + 2] = f.c.normal.z;
|
|
770
|
+
i += stride;
|
|
771
|
+
}
|
|
772
|
+
return normals;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
*
|
|
777
|
+
* @return
|
|
778
|
+
*/
|
|
779
|
+
@Override
|
|
780
|
+
public Collection<Vertex> getVertices() {
|
|
781
|
+
return vertices.values();
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
*
|
|
786
|
+
* @param stl
|
|
787
|
+
* @param useFlippedY
|
|
788
|
+
*/
|
|
789
|
+
protected void handleSaveAsSTL(STLWriter stl, boolean useFlippedY) {
|
|
790
|
+
if (useFlippedY) {
|
|
791
|
+
stl.setScale(new Vec3D(1, -1, 1));
|
|
792
|
+
faces.stream().forEach((f) -> {
|
|
793
|
+
stl.face(f.a, f.b, f.c, f.normal, STLWriter.DEFAULT_RGB);
|
|
794
|
+
});
|
|
795
|
+
} else {
|
|
796
|
+
faces.stream().forEach((f) -> {
|
|
797
|
+
stl.face(f.b, f.a, f.c, f.normal, STLWriter.DEFAULT_RGB);
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
stl.endSave();
|
|
801
|
+
logger.log(Level.INFO, "{0} faces written", numFaces);
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
*
|
|
806
|
+
* @param name
|
|
807
|
+
* @param numV
|
|
808
|
+
* @param numF
|
|
809
|
+
* @return
|
|
810
|
+
*/
|
|
811
|
+
@Override
|
|
812
|
+
public TriangleMesh init(String name, int numV, int numF) {
|
|
813
|
+
setName(name);
|
|
814
|
+
vertices = new LinkedHashMap<>(numV, 1.5f, false);
|
|
815
|
+
faces = new ArrayList<>(numF);
|
|
816
|
+
return this;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
@Override
|
|
820
|
+
public boolean intersectsRay(Ray3D ray) {
|
|
821
|
+
Triangle3D tri = intersector.getTriangle();
|
|
822
|
+
return faces.stream().map((f) -> {
|
|
823
|
+
tri.set(f.a, f.b, f.c);
|
|
824
|
+
return f;
|
|
825
|
+
}).anyMatch((_item) -> (intersector.intersectsRay(ray)));
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
*
|
|
830
|
+
* @param f
|
|
831
|
+
* @param size
|
|
832
|
+
* @return
|
|
833
|
+
*/
|
|
834
|
+
public Triangle3D perforateFace(Face f, float size) {
|
|
835
|
+
Vec3D centrd = f.getCentroid();
|
|
836
|
+
float d = 1 - size;
|
|
837
|
+
Vec3D a2 = f.a.interpolateTo(centrd, d);
|
|
838
|
+
Vec3D b2 = f.b.interpolateTo(centrd, d);
|
|
839
|
+
Vec3D c2 = f.c.interpolateTo(centrd, d);
|
|
840
|
+
removeFace(f);
|
|
841
|
+
addFace(f.a, b2, a2);
|
|
842
|
+
addFace(f.a, f.b, b2);
|
|
843
|
+
addFace(f.b, c2, b2);
|
|
844
|
+
addFace(f.b, f.c, c2);
|
|
845
|
+
addFace(f.c, a2, c2);
|
|
846
|
+
addFace(f.c, f.a, a2);
|
|
847
|
+
return new Triangle3D(a2, b2, c2);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Rotates the mesh in such a way so that its "forward" axis is aligned with
|
|
852
|
+
* the given direction. This version uses the positive Z-axis as default
|
|
853
|
+
* forward direction.
|
|
854
|
+
*
|
|
855
|
+
* @param dir
|
|
856
|
+
* new target direction to point in
|
|
857
|
+
* @return itself
|
|
858
|
+
*/
|
|
859
|
+
public TriangleMesh pointTowards(ReadonlyVec3D dir) {
|
|
860
|
+
return transform(Quaternion.getAlignmentQuat(dir, Vec3D.Z_AXIS)
|
|
861
|
+
.toMatrix4x4(matrix), true);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Rotates the mesh in such a way so that its "forward" axis is aligned with
|
|
866
|
+
* the given direction. This version allows to specify the forward
|
|
867
|
+
* direction.
|
|
868
|
+
*
|
|
869
|
+
* @param dir
|
|
870
|
+
* new target direction to point in
|
|
871
|
+
* @param forward
|
|
872
|
+
* current forward axis
|
|
873
|
+
* @return itself
|
|
874
|
+
*/
|
|
875
|
+
public TriangleMesh pointTowards(ReadonlyVec3D dir, ReadonlyVec3D forward) {
|
|
876
|
+
return transform(
|
|
877
|
+
Quaternion.getAlignmentQuat(dir, forward).toMatrix4x4(matrix),
|
|
878
|
+
true);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
*
|
|
883
|
+
* @param f
|
|
884
|
+
*/
|
|
885
|
+
public void removeFace(Face f) {
|
|
886
|
+
faces.remove(f);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
*
|
|
891
|
+
* @param axis
|
|
892
|
+
* @param theta
|
|
893
|
+
* @return
|
|
894
|
+
*/
|
|
895
|
+
public TriangleMesh rotateAroundAxis(Vec3D axis, float theta) {
|
|
896
|
+
return transform(matrix.identity().rotateAroundAxis(axis, theta));
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/**
|
|
900
|
+
*
|
|
901
|
+
* @param theta
|
|
902
|
+
* @return
|
|
903
|
+
*/
|
|
904
|
+
public TriangleMesh rotateX(float theta) {
|
|
905
|
+
return transform(matrix.identity().rotateX(theta));
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
/**
|
|
909
|
+
*
|
|
910
|
+
* @param theta
|
|
911
|
+
* @return
|
|
912
|
+
*/
|
|
913
|
+
public TriangleMesh rotateY(float theta) {
|
|
914
|
+
return transform(matrix.identity().rotateY(theta));
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
/**
|
|
918
|
+
*
|
|
919
|
+
* @param theta
|
|
920
|
+
* @return
|
|
921
|
+
*/
|
|
922
|
+
public TriangleMesh rotateZ(float theta) {
|
|
923
|
+
return transform(matrix.identity().rotateZ(theta));
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* Saves the mesh as OBJ format by appending it to the given mesh
|
|
928
|
+
* {@link OBJWriter} instance.
|
|
929
|
+
*
|
|
930
|
+
* @param obj
|
|
931
|
+
*/
|
|
932
|
+
public void saveAsOBJ(OBJWriter obj) {
|
|
933
|
+
saveAsOBJ(obj, true);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
*
|
|
938
|
+
* @param obj
|
|
939
|
+
* @param saveNormals
|
|
940
|
+
*/
|
|
941
|
+
public void saveAsOBJ(OBJWriter obj, boolean saveNormals) {
|
|
942
|
+
int vOffset = obj.getCurrVertexOffset() + 1;
|
|
943
|
+
int nOffset = obj.getCurrNormalOffset() + 1;
|
|
944
|
+
logger.log(Level.INFO, "writing OBJMesh: {0}", this.toString());
|
|
945
|
+
obj.newObject(name);
|
|
946
|
+
// vertices
|
|
947
|
+
vertices.values().stream().forEach((v) -> {
|
|
948
|
+
obj.vertex(v);
|
|
949
|
+
});
|
|
950
|
+
// faces
|
|
951
|
+
if (saveNormals) {
|
|
952
|
+
// normals
|
|
953
|
+
vertices.values().stream().forEach((v) -> {
|
|
954
|
+
obj.normal(v.normal);
|
|
955
|
+
});
|
|
956
|
+
faces.stream().forEach((f) -> {
|
|
957
|
+
obj.faceWithNormals(f.b.id + vOffset, f.a.id + vOffset, f.c.id
|
|
958
|
+
+ vOffset, f.b.id + nOffset, f.a.id + nOffset, f.c.id
|
|
959
|
+
+ nOffset);
|
|
960
|
+
});
|
|
961
|
+
} else {
|
|
962
|
+
faces.stream().forEach((f) -> {
|
|
963
|
+
obj.face(f.b.id + vOffset, f.a.id + vOffset, f.c.id + vOffset);
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* Saves the mesh as OBJ format to the given {@link OutputStream}. Currently
|
|
970
|
+
* no texture coordinates are supported or written.
|
|
971
|
+
*
|
|
972
|
+
* @param stream
|
|
973
|
+
*/
|
|
974
|
+
public void saveAsOBJ(OutputStream stream) {
|
|
975
|
+
OBJWriter obj = new OBJWriter();
|
|
976
|
+
obj.beginSave(stream);
|
|
977
|
+
saveAsOBJ(obj);
|
|
978
|
+
obj.endSave();
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* Saves the mesh as OBJ format to the given file path. Existing files will
|
|
983
|
+
* be overwritten.
|
|
984
|
+
*
|
|
985
|
+
* @param path
|
|
986
|
+
*/
|
|
987
|
+
public void saveAsOBJ(String path) {
|
|
988
|
+
saveAsOBJ(path, true);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
*
|
|
993
|
+
* @param path
|
|
994
|
+
* @param saveNormals
|
|
995
|
+
*/
|
|
996
|
+
public void saveAsOBJ(String path, boolean saveNormals) {
|
|
997
|
+
OBJWriter obj = new OBJWriter();
|
|
998
|
+
obj.beginSave(path);
|
|
999
|
+
saveAsOBJ(obj, saveNormals);
|
|
1000
|
+
obj.endSave();
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Saves the mesh as binary STL format to the given {@link OutputStream}.
|
|
1005
|
+
*
|
|
1006
|
+
* @param stream
|
|
1007
|
+
* @see #saveAsSTL(OutputStream, boolean)
|
|
1008
|
+
*/
|
|
1009
|
+
public final void saveAsSTL(OutputStream stream) {
|
|
1010
|
+
saveAsSTL(stream, false);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/**
|
|
1014
|
+
* Saves the mesh as binary STL format to the given {@link OutputStream}.
|
|
1015
|
+
* The exported mesh can optionally have it's Y axis flipped by setting the
|
|
1016
|
+
* useFlippedY flag to true.
|
|
1017
|
+
*
|
|
1018
|
+
* @param stream
|
|
1019
|
+
* @param useFlippedY
|
|
1020
|
+
*/
|
|
1021
|
+
public final void saveAsSTL(OutputStream stream, boolean useFlippedY) {
|
|
1022
|
+
STLWriter stl = new STLWriter();
|
|
1023
|
+
stl.beginSave(stream, numFaces);
|
|
1024
|
+
handleSaveAsSTL(stl, useFlippedY);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* Saves the mesh as binary STL format to the given {@link OutputStream} and
|
|
1029
|
+
* using the supplied {@link STLWriter} instance. Use this method to export
|
|
1030
|
+
* data in a custom {@link STLColorModel}. The exported mesh can optionally
|
|
1031
|
+
* have it's Y axis flipped by setting the useFlippedY flag to true.
|
|
1032
|
+
*
|
|
1033
|
+
* @param stream
|
|
1034
|
+
* @param stl
|
|
1035
|
+
* @param useFlippedY
|
|
1036
|
+
*/
|
|
1037
|
+
public final void saveAsSTL(OutputStream stream, STLWriter stl,
|
|
1038
|
+
boolean useFlippedY) {
|
|
1039
|
+
stl.beginSave(stream, numFaces);
|
|
1040
|
+
handleSaveAsSTL(stl, useFlippedY);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* Saves the mesh as binary STL format to the given file path. Existing
|
|
1045
|
+
* files will be overwritten.
|
|
1046
|
+
*
|
|
1047
|
+
* @param fileName
|
|
1048
|
+
*/
|
|
1049
|
+
public final void saveAsSTL(String fileName) {
|
|
1050
|
+
saveAsSTL(fileName, false);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* Saves the mesh as binary STL format to the given file path. The exported
|
|
1055
|
+
* mesh can optionally have it's Y axis flipped by setting the useFlippedY
|
|
1056
|
+
* flag to true. Existing files will be overwritten.
|
|
1057
|
+
*
|
|
1058
|
+
* @param fileName
|
|
1059
|
+
* @param useFlippedY
|
|
1060
|
+
*/
|
|
1061
|
+
public final void saveAsSTL(String fileName, boolean useFlippedY) {
|
|
1062
|
+
saveAsSTL(fileName, new STLWriter(), useFlippedY);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
*
|
|
1067
|
+
* @param fileName
|
|
1068
|
+
* @param stl
|
|
1069
|
+
* @param useFlippedY
|
|
1070
|
+
*/
|
|
1071
|
+
public final void saveAsSTL(String fileName, STLWriter stl,
|
|
1072
|
+
boolean useFlippedY) {
|
|
1073
|
+
stl.beginSave(fileName, numFaces);
|
|
1074
|
+
handleSaveAsSTL(stl, useFlippedY);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
*
|
|
1079
|
+
* @param scale
|
|
1080
|
+
* @return
|
|
1081
|
+
*/
|
|
1082
|
+
public TriangleMesh scale(float scale) {
|
|
1083
|
+
return transform(matrix.identity().scaleSelf(scale));
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
*
|
|
1088
|
+
* @param x
|
|
1089
|
+
* @param y
|
|
1090
|
+
* @param z
|
|
1091
|
+
* @return
|
|
1092
|
+
*/
|
|
1093
|
+
public TriangleMesh scale(float x, float y, float z) {
|
|
1094
|
+
return transform(matrix.identity().scaleSelf(x, y, z));
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
*
|
|
1099
|
+
* @param scale
|
|
1100
|
+
* @return
|
|
1101
|
+
*/
|
|
1102
|
+
public TriangleMesh scale(Vec3D scale) {
|
|
1103
|
+
return transform(matrix.identity().scaleSelf(scale));
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
/**
|
|
1107
|
+
*
|
|
1108
|
+
* @param name
|
|
1109
|
+
* @return
|
|
1110
|
+
*/
|
|
1111
|
+
@Override
|
|
1112
|
+
public TriangleMesh setName(String name) {
|
|
1113
|
+
this.name = name;
|
|
1114
|
+
return this;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
/**
|
|
1118
|
+
*
|
|
1119
|
+
* @return
|
|
1120
|
+
*/
|
|
1121
|
+
@Override
|
|
1122
|
+
public String toString() {
|
|
1123
|
+
return "TriangleMesh: " + name + " vertices: " + getNumVertices()
|
|
1124
|
+
+ " faces: " + getNumFaces();
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
/**
|
|
1128
|
+
*
|
|
1129
|
+
* @return
|
|
1130
|
+
*/
|
|
1131
|
+
public WETriangleMesh toWEMesh() {
|
|
1132
|
+
return new WETriangleMesh(name, vertices.size(), faces.size())
|
|
1133
|
+
.addMesh(this);
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Applies the given matrix transform to all mesh vertices and updates all
|
|
1138
|
+
* face normals.
|
|
1139
|
+
*
|
|
1140
|
+
* @param mat
|
|
1141
|
+
* @return itself
|
|
1142
|
+
*/
|
|
1143
|
+
public TriangleMesh transform(Matrix4x4 mat) {
|
|
1144
|
+
return transform(mat, true);
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/**
|
|
1148
|
+
* Applies the given matrix transform to all mesh vertices. If the
|
|
1149
|
+
* updateNormals flag is true, all face normals are updated automatically,
|
|
1150
|
+
* however vertex normals need a manual update.
|
|
1151
|
+
*
|
|
1152
|
+
* @param mat
|
|
1153
|
+
* @param updateNormals
|
|
1154
|
+
* @return itself
|
|
1155
|
+
*/
|
|
1156
|
+
public TriangleMesh transform(Matrix4x4 mat, boolean updateNormals) {
|
|
1157
|
+
vertices.values().stream().forEach((v) -> {
|
|
1158
|
+
v.set(mat.applyTo(v));
|
|
1159
|
+
});
|
|
1160
|
+
if (updateNormals) {
|
|
1161
|
+
computeFaceNormals();
|
|
1162
|
+
}
|
|
1163
|
+
return this;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
/**
|
|
1167
|
+
*
|
|
1168
|
+
* @param x
|
|
1169
|
+
* @param y
|
|
1170
|
+
* @param z
|
|
1171
|
+
* @return
|
|
1172
|
+
*/
|
|
1173
|
+
public TriangleMesh translate(float x, float y, float z) {
|
|
1174
|
+
return transform(matrix.identity().translateSelf(x, y, z));
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
/**
|
|
1178
|
+
*
|
|
1179
|
+
* @param trans
|
|
1180
|
+
* @return
|
|
1181
|
+
*/
|
|
1182
|
+
public TriangleMesh translate(Vec3D trans) {
|
|
1183
|
+
return transform(matrix.identity().translateSelf(trans));
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
*
|
|
1188
|
+
* @param orig
|
|
1189
|
+
* @param newPos
|
|
1190
|
+
* @return
|
|
1191
|
+
*/
|
|
1192
|
+
public TriangleMesh updateVertex(Vec3D orig, Vec3D newPos) {
|
|
1193
|
+
Vertex v = vertices.get(orig);
|
|
1194
|
+
if (v != null) {
|
|
1195
|
+
vertices.remove(v);
|
|
1196
|
+
v.set(newPos);
|
|
1197
|
+
vertices.put(v, v);
|
|
1198
|
+
}
|
|
1199
|
+
return this;
|
|
1200
|
+
}
|
|
1201
|
+
}
|