toxiclibs 0.4.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (404) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +16 -0
  3. data/.mvn/extensions.xml +8 -0
  4. data/.mvn/wrapper/maven-wrapper.properties +1 -0
  5. data/.travis.yml +23 -0
  6. data/CHANGELOG.md +7 -0
  7. data/COPYING.md +14 -0
  8. data/Gemfile +10 -0
  9. data/LICENSE +675 -0
  10. data/README.md +9 -7
  11. data/Rakefile +25 -81
  12. data/examples/README.md +5 -0
  13. data/examples/attract_repel/attract_repel.rb +30 -0
  14. data/examples/attract_repel/attractor.rb +23 -0
  15. data/examples/attract_repel/particle.rb +27 -0
  16. data/examples/data/ReplicaBold.ttf +0 -0
  17. data/examples/data/ti_yong.png +0 -0
  18. data/examples/force_directed/cluster.rb +76 -0
  19. data/examples/force_directed/force_directed_graph.rb +92 -0
  20. data/examples/force_directed/node.rb +26 -0
  21. data/examples/gray_scott_image.rb +74 -0
  22. data/examples/gray_scott_tone_map.rb +77 -0
  23. data/examples/implicit.rb +139 -0
  24. data/examples/inflate_mesh.rb +89 -0
  25. data/examples/model_align.rb +43 -0
  26. data/examples/physics_type.rb +77 -0
  27. data/examples/povmesh/data/mask.jpg +0 -0
  28. data/examples/povmesh/ftest.rb +59 -0
  29. data/examples/povmesh/mesh_align.rb +47 -0
  30. data/examples/povmesh/tentacle.rb +71 -0
  31. data/examples/simple_cluster/cluster.rb +47 -0
  32. data/examples/simple_cluster/node.rb +27 -0
  33. data/examples/simple_cluster/simple_cluster.rb +60 -0
  34. data/examples/soft_body/blanket.rb +45 -0
  35. data/examples/soft_body/connection.rb +16 -0
  36. data/examples/soft_body/particle.rb +22 -0
  37. data/examples/soft_body/soft_body_square_adapted.rb +55 -0
  38. data/examples/spherical_harmonics_mesh.rb +50 -0
  39. data/examples/test_rect.rb +32 -0
  40. data/lib/toxiclibs.jar +0 -0
  41. data/lib/toxiclibs.rb +72 -22
  42. data/lib/toxiclibs/version.rb +1 -1
  43. data/pom.rb +63 -0
  44. data/pom.xml +124 -0
  45. data/src/com/toxi/net/ClientListener.java +41 -0
  46. data/src/com/toxi/net/ServerListener.java +70 -0
  47. data/src/com/toxi/net/ServerListenerAdapter.java +47 -0
  48. data/src/com/toxi/net/ServerState.java +18 -0
  49. data/src/com/toxi/net/UDPConnection.java +66 -0
  50. data/src/com/toxi/net/UDPSyncClient.java +81 -0
  51. data/src/com/toxi/net/UDPSyncServer.java +450 -0
  52. data/src/com/toxi/nio/UDPClient.java +121 -0
  53. data/src/com/toxi/nio/UDPClientState.java +32 -0
  54. data/src/com/toxi/nio/UDPServer.java +129 -0
  55. data/src/toxi/audio/AudioBuffer.java +229 -0
  56. data/src/toxi/audio/AudioSource.java +288 -0
  57. data/src/toxi/audio/DecompressInputStream.java +159 -0
  58. data/src/toxi/audio/IIRFilter.java +197 -0
  59. data/src/toxi/audio/JOALUtil.java +388 -0
  60. data/src/toxi/audio/MultiTimbralManager.java +162 -0
  61. data/src/toxi/audio/SoundListener.java +154 -0
  62. data/src/toxi/audio/SynthUtil.java +109 -0
  63. data/src/toxi/color/AccessCriteria.java +114 -0
  64. data/src/toxi/color/AlphaAccessor.java +67 -0
  65. data/src/toxi/color/CMYKAccessor.java +122 -0
  66. data/src/toxi/color/CMYKDistanceProxy.java +40 -0
  67. data/src/toxi/color/ColorGradient.java +260 -0
  68. data/src/toxi/color/ColorList.java +699 -0
  69. data/src/toxi/color/ColorRange.java +671 -0
  70. data/src/toxi/color/ColorTheme.java +163 -0
  71. data/src/toxi/color/DistanceProxy.java +44 -0
  72. data/src/toxi/color/HSVAccessor.java +113 -0
  73. data/src/toxi/color/HSVDistanceProxy.java +40 -0
  74. data/src/toxi/color/HistEntry.java +85 -0
  75. data/src/toxi/color/Histogram.java +185 -0
  76. data/src/toxi/color/Hue.java +249 -0
  77. data/src/toxi/color/LuminanceAccessor.java +78 -0
  78. data/src/toxi/color/NamedColor.java +935 -0
  79. data/src/toxi/color/ProximityComparator.java +70 -0
  80. data/src/toxi/color/RGBAccessor.java +113 -0
  81. data/src/toxi/color/RGBDistanceProxy.java +41 -0
  82. data/src/toxi/color/ReadonlyTColor.java +296 -0
  83. data/src/toxi/color/TColor.java +1677 -0
  84. data/src/toxi/color/TColorAdapter.java +68 -0
  85. data/src/toxi/color/ToneMap.java +218 -0
  86. data/src/toxi/color/theory/AnalogousStrategy.java +140 -0
  87. data/src/toxi/color/theory/ColorTheoryRegistry.java +139 -0
  88. data/src/toxi/color/theory/ColorTheoryStrategy.java +56 -0
  89. data/src/toxi/color/theory/ComplementaryStrategy.java +111 -0
  90. data/src/toxi/color/theory/CompoundTheoryStrategy.java +143 -0
  91. data/src/toxi/color/theory/LeftSplitComplementaryStrategy.java +82 -0
  92. data/src/toxi/color/theory/MonochromeTheoryStrategy.java +103 -0
  93. data/src/toxi/color/theory/RightSplitComplementaryStrategy.java +82 -0
  94. data/src/toxi/color/theory/SingleComplementStrategy.java +76 -0
  95. data/src/toxi/color/theory/SplitComplementaryStrategy.java +77 -0
  96. data/src/toxi/color/theory/TetradTheoryStrategy.java +114 -0
  97. data/src/toxi/color/theory/TriadTheoryStrategy.java +77 -0
  98. data/src/toxi/data/csv/CSVAdapter.java +74 -0
  99. data/src/toxi/data/csv/CSVFieldMapper.java +212 -0
  100. data/src/toxi/data/csv/CSVListener.java +61 -0
  101. data/src/toxi/data/csv/CSVParser.java +202 -0
  102. data/src/toxi/data/feeds/AtomAuthor.java +49 -0
  103. data/src/toxi/data/feeds/AtomContent.java +50 -0
  104. data/src/toxi/data/feeds/AtomEntry.java +111 -0
  105. data/src/toxi/data/feeds/AtomFeed.java +129 -0
  106. data/src/toxi/data/feeds/AtomLink.java +62 -0
  107. data/src/toxi/data/feeds/RSSChannel.java +88 -0
  108. data/src/toxi/data/feeds/RSSEnclosure.java +60 -0
  109. data/src/toxi/data/feeds/RSSFeed.java +99 -0
  110. data/src/toxi/data/feeds/RSSItem.java +104 -0
  111. data/src/toxi/data/feeds/util/EntityStripper.java +2480 -0
  112. data/src/toxi/data/feeds/util/Iso8601DateAdapter.java +101 -0
  113. data/src/toxi/data/feeds/util/Rfc822DateAdapter.java +93 -0
  114. data/src/toxi/geom/AABB.java +658 -0
  115. data/src/toxi/geom/Axis3D.java +116 -0
  116. data/src/toxi/geom/AxisAlignedCylinder.java +163 -0
  117. data/src/toxi/geom/BernsteinPolynomial.java +94 -0
  118. data/src/toxi/geom/BezierCurve2D.java +159 -0
  119. data/src/toxi/geom/BezierCurve3D.java +148 -0
  120. data/src/toxi/geom/BooleanShapeBuilder.java +185 -0
  121. data/src/toxi/geom/BoxIntersector.java +52 -0
  122. data/src/toxi/geom/Circle.java +230 -0
  123. data/src/toxi/geom/CircleIntersector.java +85 -0
  124. data/src/toxi/geom/Cone.java +150 -0
  125. data/src/toxi/geom/ConvexPolygonClipper.java +136 -0
  126. data/src/toxi/geom/CoordinateExtractor.java +16 -0
  127. data/src/toxi/geom/Ellipse.java +250 -0
  128. data/src/toxi/geom/GMatrix.java +2599 -0
  129. data/src/toxi/geom/GVector.java +833 -0
  130. data/src/toxi/geom/GlobalGridTesselator.java +54 -0
  131. data/src/toxi/geom/GridTesselator.java +108 -0
  132. data/src/toxi/geom/Intersector2D.java +49 -0
  133. data/src/toxi/geom/Intersector3D.java +51 -0
  134. data/src/toxi/geom/IsectData2D.java +103 -0
  135. data/src/toxi/geom/IsectData3D.java +103 -0
  136. data/src/toxi/geom/Line2D.java +534 -0
  137. data/src/toxi/geom/Line3D.java +471 -0
  138. data/src/toxi/geom/LineStrip2D.java +430 -0
  139. data/src/toxi/geom/LineStrip3D.java +230 -0
  140. data/src/toxi/geom/LocalGridTesselator.java +57 -0
  141. data/src/toxi/geom/Matrix3d.java +3048 -0
  142. data/src/toxi/geom/Matrix4f.java +3446 -0
  143. data/src/toxi/geom/Matrix4x4.java +1076 -0
  144. data/src/toxi/geom/MatrixSizeException.java +58 -0
  145. data/src/toxi/geom/OctreeVisitor.java +44 -0
  146. data/src/toxi/geom/Origin3D.java +148 -0
  147. data/src/toxi/geom/Plane.java +293 -0
  148. data/src/toxi/geom/PlaneIntersector.java +57 -0
  149. data/src/toxi/geom/PointCloud3D.java +253 -0
  150. data/src/toxi/geom/PointOctree.java +502 -0
  151. data/src/toxi/geom/PointQuadtree.java +375 -0
  152. data/src/toxi/geom/Polygon2D.java +1038 -0
  153. data/src/toxi/geom/PolygonClipper2D.java +45 -0
  154. data/src/toxi/geom/PolygonTesselator.java +20 -0
  155. data/src/toxi/geom/QuadtreeVisitor.java +44 -0
  156. data/src/toxi/geom/Quaternion.java +641 -0
  157. data/src/toxi/geom/Ray2D.java +146 -0
  158. data/src/toxi/geom/Ray3D.java +150 -0
  159. data/src/toxi/geom/Ray3DIntersector.java +75 -0
  160. data/src/toxi/geom/ReadonlyVec2D.java +575 -0
  161. data/src/toxi/geom/ReadonlyVec3D.java +628 -0
  162. data/src/toxi/geom/ReadonlyVec4D.java +431 -0
  163. data/src/toxi/geom/Rect.java +720 -0
  164. data/src/toxi/geom/Reflector3D.java +58 -0
  165. data/src/toxi/geom/Shape2D.java +94 -0
  166. data/src/toxi/geom/Shape3D.java +42 -0
  167. data/src/toxi/geom/SingularMatrixException.java +57 -0
  168. data/src/toxi/geom/SpatialBins.java +182 -0
  169. data/src/toxi/geom/SpatialIndex.java +61 -0
  170. data/src/toxi/geom/Sphere.java +224 -0
  171. data/src/toxi/geom/SphereIntersectorReflector.java +196 -0
  172. data/src/toxi/geom/Spline2D.java +349 -0
  173. data/src/toxi/geom/Spline3D.java +351 -0
  174. data/src/toxi/geom/SutherlandHodgemanClipper.java +151 -0
  175. data/src/toxi/geom/Triangle2D.java +422 -0
  176. data/src/toxi/geom/Triangle3D.java +456 -0
  177. data/src/toxi/geom/TriangleIntersector.java +105 -0
  178. data/src/toxi/geom/Vec2D.java +1328 -0
  179. data/src/toxi/geom/Vec3D.java +1832 -0
  180. data/src/toxi/geom/Vec4D.java +985 -0
  181. data/src/toxi/geom/VecMathUtil.java +100 -0
  182. data/src/toxi/geom/XAxisCylinder.java +64 -0
  183. data/src/toxi/geom/YAxisCylinder.java +65 -0
  184. data/src/toxi/geom/ZAxisCylinder.java +64 -0
  185. data/src/toxi/geom/mesh/BezierPatch.java +200 -0
  186. data/src/toxi/geom/mesh/BoxSelector.java +62 -0
  187. data/src/toxi/geom/mesh/DefaultSTLColorModel.java +67 -0
  188. data/src/toxi/geom/mesh/DefaultSelector.java +50 -0
  189. data/src/toxi/geom/mesh/Face.java +176 -0
  190. data/src/toxi/geom/mesh/LaplacianSmooth.java +80 -0
  191. data/src/toxi/geom/mesh/MaterialiseSTLColorModel.java +150 -0
  192. data/src/toxi/geom/mesh/Mesh3D.java +224 -0
  193. data/src/toxi/geom/mesh/MeshIntersector.java +91 -0
  194. data/src/toxi/geom/mesh/OBJWriter.java +194 -0
  195. data/src/toxi/geom/mesh/PLYWriter.java +167 -0
  196. data/src/toxi/geom/mesh/PlaneSelector.java +90 -0
  197. data/src/toxi/geom/mesh/STLColorModel.java +54 -0
  198. data/src/toxi/geom/mesh/STLReader.java +185 -0
  199. data/src/toxi/geom/mesh/STLWriter.java +323 -0
  200. data/src/toxi/geom/mesh/SphereFunction.java +156 -0
  201. data/src/toxi/geom/mesh/SphericalHarmonics.java +110 -0
  202. data/src/toxi/geom/mesh/SuperEllipsoid.java +110 -0
  203. data/src/toxi/geom/mesh/SurfaceFunction.java +75 -0
  204. data/src/toxi/geom/mesh/SurfaceMeshBuilder.java +149 -0
  205. data/src/toxi/geom/mesh/Terrain.java +451 -0
  206. data/src/toxi/geom/mesh/TriangleMesh.java +1201 -0
  207. data/src/toxi/geom/mesh/Vertex.java +78 -0
  208. data/src/toxi/geom/mesh/VertexSelector.java +193 -0
  209. data/src/toxi/geom/mesh/WEFace.java +100 -0
  210. data/src/toxi/geom/mesh/WEMeshFilterStrategy.java +51 -0
  211. data/src/toxi/geom/mesh/WETriangleMesh.java +761 -0
  212. data/src/toxi/geom/mesh/WEVertex.java +134 -0
  213. data/src/toxi/geom/mesh/WingedEdge.java +115 -0
  214. data/src/toxi/geom/mesh/subdiv/CentroidSubdiv.java +37 -0
  215. data/src/toxi/geom/mesh/subdiv/DisplacementSubdivision.java +85 -0
  216. data/src/toxi/geom/mesh/subdiv/DualDisplacementSubdivision.java +94 -0
  217. data/src/toxi/geom/mesh/subdiv/DualSubdivision.java +49 -0
  218. data/src/toxi/geom/mesh/subdiv/EdgeLengthComparator.java +50 -0
  219. data/src/toxi/geom/mesh/subdiv/FaceCountComparator.java +51 -0
  220. data/src/toxi/geom/mesh/subdiv/MidpointDisplacementSubdivision.java +80 -0
  221. data/src/toxi/geom/mesh/subdiv/MidpointSubdiv.java +42 -0
  222. data/src/toxi/geom/mesh/subdiv/MidpointSubdivision.java +48 -0
  223. data/src/toxi/geom/mesh/subdiv/NewSubdivStrategy.java +23 -0
  224. data/src/toxi/geom/mesh/subdiv/NormalDisplacementSubdivision.java +74 -0
  225. data/src/toxi/geom/mesh/subdiv/SubdivisionStrategy.java +83 -0
  226. data/src/toxi/geom/mesh/subdiv/TriSubdivision.java +51 -0
  227. data/src/toxi/geom/mesh2d/DelaunayTriangle.java +222 -0
  228. data/src/toxi/geom/mesh2d/DelaunayTriangulation.java +327 -0
  229. data/src/toxi/geom/mesh2d/DelaunayVertex.java +560 -0
  230. data/src/toxi/geom/mesh2d/Voronoi.java +149 -0
  231. data/src/toxi/geom/nurbs/BasicNurbsCurve.java +210 -0
  232. data/src/toxi/geom/nurbs/BasicNurbsSurface.java +233 -0
  233. data/src/toxi/geom/nurbs/ControlNet.java +148 -0
  234. data/src/toxi/geom/nurbs/CurveCreator.java +112 -0
  235. data/src/toxi/geom/nurbs/CurveUtils.java +259 -0
  236. data/src/toxi/geom/nurbs/InterpolationException.java +65 -0
  237. data/src/toxi/geom/nurbs/KnotVector.java +333 -0
  238. data/src/toxi/geom/nurbs/NurbsCreator.java +815 -0
  239. data/src/toxi/geom/nurbs/NurbsCurve.java +120 -0
  240. data/src/toxi/geom/nurbs/NurbsMeshCreator.java +145 -0
  241. data/src/toxi/geom/nurbs/NurbsSurface.java +147 -0
  242. data/src/toxi/image/util/Filter8bit.java +331 -0
  243. data/src/toxi/image/util/TiledFrameExporter.java +162 -0
  244. data/src/toxi/math/BezierInterpolation.java +102 -0
  245. data/src/toxi/math/CircularInterpolation.java +88 -0
  246. data/src/toxi/math/CosineInterpolation.java +51 -0
  247. data/src/toxi/math/DecimatedInterpolation.java +77 -0
  248. data/src/toxi/math/ExponentialInterpolation.java +68 -0
  249. data/src/toxi/math/InterpolateStrategy.java +60 -0
  250. data/src/toxi/math/Interpolation2D.java +93 -0
  251. data/src/toxi/math/LinearInterpolation.java +46 -0
  252. data/src/toxi/math/MathUtils.java +990 -0
  253. data/src/toxi/math/NonLinearScaleMap.java +101 -0
  254. data/src/toxi/math/ScaleMap.java +183 -0
  255. data/src/toxi/math/SigmoidInterpolation.java +78 -0
  256. data/src/toxi/math/SinCosLUT.java +141 -0
  257. data/src/toxi/math/ThresholdInterpolation.java +58 -0
  258. data/src/toxi/math/ZoomLensInterpolation.java +126 -0
  259. data/src/toxi/math/conversion/UnitTranslator.java +161 -0
  260. data/src/toxi/math/noise/PerlinNoise.java +281 -0
  261. data/src/toxi/math/noise/SimplexNoise.java +542 -0
  262. data/src/toxi/math/waves/AMFMSineWave.java +143 -0
  263. data/src/toxi/math/waves/AbstractWave.java +248 -0
  264. data/src/toxi/math/waves/ConstantWave.java +48 -0
  265. data/src/toxi/math/waves/FMHarmonicSquareWave.java +155 -0
  266. data/src/toxi/math/waves/FMSawtoothWave.java +144 -0
  267. data/src/toxi/math/waves/FMSineWave.java +142 -0
  268. data/src/toxi/math/waves/FMSquareWave.java +143 -0
  269. data/src/toxi/math/waves/FMTriangleWave.java +126 -0
  270. data/src/toxi/math/waves/SineWave.java +81 -0
  271. data/src/toxi/math/waves/Wave2D.java +68 -0
  272. data/src/toxi/math/waves/WaveState.java +69 -0
  273. data/src/toxi/music/scale/AbstractScale.java +117 -0
  274. data/src/toxi/music/scale/GenericScale.java +66 -0
  275. data/src/toxi/music/scale/MajorScale.java +41 -0
  276. data/src/toxi/newmesh/AttributedEdge.java +106 -0
  277. data/src/toxi/newmesh/AttributedFace.java +63 -0
  278. data/src/toxi/newmesh/IndexedTriangleMesh.java +809 -0
  279. data/src/toxi/newmesh/MeshAttributeCompiler.java +45 -0
  280. data/src/toxi/newmesh/MeshFaceNormalCompiler.java +52 -0
  281. data/src/toxi/newmesh/MeshUVCompiler.java +52 -0
  282. data/src/toxi/newmesh/MeshVertexColorCompiler.java +49 -0
  283. data/src/toxi/newmesh/MeshVertexCompiler.java +54 -0
  284. data/src/toxi/newmesh/MeshVertexNormalCompiler.java +55 -0
  285. data/src/toxi/newmesh/SpatialIndex.java +78 -0
  286. data/src/toxi/physics2d/ParticlePath2D.java +100 -0
  287. data/src/toxi/physics2d/ParticleString2D.java +184 -0
  288. data/src/toxi/physics2d/PullBackSpring2D.java +51 -0
  289. data/src/toxi/physics2d/VerletConstrainedSpring2D.java +89 -0
  290. data/src/toxi/physics2d/VerletMinDistanceSpring2D.java +57 -0
  291. data/src/toxi/physics2d/VerletParticle2D.java +457 -0
  292. data/src/toxi/physics2d/VerletPhysics2D.java +448 -0
  293. data/src/toxi/physics2d/VerletSpring2D.java +181 -0
  294. data/src/toxi/physics2d/behaviors/AttractionBehavior2D.java +212 -0
  295. data/src/toxi/physics2d/behaviors/ConstantForceBehavior2D.java +112 -0
  296. data/src/toxi/physics2d/behaviors/GravityBehavior2D.java +61 -0
  297. data/src/toxi/physics2d/behaviors/ParticleBehavior2D.java +66 -0
  298. data/src/toxi/physics2d/constraints/AngularConstraint.java +83 -0
  299. data/src/toxi/physics2d/constraints/AxisConstraint.java +71 -0
  300. data/src/toxi/physics2d/constraints/CircularConstraint.java +69 -0
  301. data/src/toxi/physics2d/constraints/MaxConstraint.java +66 -0
  302. data/src/toxi/physics2d/constraints/MinConstraint.java +66 -0
  303. data/src/toxi/physics2d/constraints/ParticleConstraint2D.java +47 -0
  304. data/src/toxi/physics2d/constraints/PolygonConstraint.java +93 -0
  305. data/src/toxi/physics2d/constraints/RectConstraint.java +114 -0
  306. data/src/toxi/physics3d/ParticlePath3D.java +100 -0
  307. data/src/toxi/physics3d/ParticleString3D.java +184 -0
  308. data/src/toxi/physics3d/PullBackSpring3D.java +50 -0
  309. data/src/toxi/physics3d/VerletConstrainedSpring3D.java +88 -0
  310. data/src/toxi/physics3d/VerletMinDistanceSpring3D.java +56 -0
  311. data/src/toxi/physics3d/VerletParticle3D.java +385 -0
  312. data/src/toxi/physics3d/VerletPhysics3D.java +417 -0
  313. data/src/toxi/physics3d/VerletSpring3D.java +180 -0
  314. data/src/toxi/physics3d/behaviors/AttractionBehavior3D.java +182 -0
  315. data/src/toxi/physics3d/behaviors/ConstantForceBehavior3D.java +92 -0
  316. data/src/toxi/physics3d/behaviors/GravityBehavior3D.java +61 -0
  317. data/src/toxi/physics3d/behaviors/ParticleBehavior3D.java +52 -0
  318. data/src/toxi/physics3d/constraints/AxisConstraint.java +68 -0
  319. data/src/toxi/physics3d/constraints/BoxConstraint.java +121 -0
  320. data/src/toxi/physics3d/constraints/CylinderConstraint.java +87 -0
  321. data/src/toxi/physics3d/constraints/MaxConstraint.java +65 -0
  322. data/src/toxi/physics3d/constraints/MinConstraint.java +65 -0
  323. data/src/toxi/physics3d/constraints/ParticleConstraint3D.java +49 -0
  324. data/src/toxi/physics3d/constraints/PlaneConstraint.java +78 -0
  325. data/src/toxi/physics3d/constraints/SoftBoxConstraint.java +87 -0
  326. data/src/toxi/physics3d/constraints/SphereConstraint.java +108 -0
  327. data/src/toxi/processing/ArrowModifier.java +116 -0
  328. data/src/toxi/processing/DashedLineModifier.java +48 -0
  329. data/src/toxi/processing/DeltaOrientationMapper.java +57 -0
  330. data/src/toxi/processing/Line2DRenderModifier.java +18 -0
  331. data/src/toxi/processing/MeshToVBO.java +127 -0
  332. data/src/toxi/processing/NormalMapper.java +18 -0
  333. data/src/toxi/processing/POVInterface.java +121 -0
  334. data/src/toxi/processing/POVMesh.java +219 -0
  335. data/src/toxi/processing/POVWriter.java +460 -0
  336. data/src/toxi/processing/RCOpaque.java +77 -0
  337. data/src/toxi/processing/RCTransp.java +78 -0
  338. data/src/toxi/processing/TextureBuilder.java +232 -0
  339. data/src/toxi/processing/Textures.java +110 -0
  340. data/src/toxi/processing/ToxiclibsSupport.java +1239 -0
  341. data/src/toxi/processing/Tracing.java +25 -0
  342. data/src/toxi/processing/XYZNormalMapper.java +30 -0
  343. data/src/toxi/sim/automata/CAMatrix.java +297 -0
  344. data/src/toxi/sim/automata/CARule.java +76 -0
  345. data/src/toxi/sim/automata/CARule2D.java +354 -0
  346. data/src/toxi/sim/automata/CAWolfram1D.java +309 -0
  347. data/src/toxi/sim/automata/EvolvableMatrix.java +61 -0
  348. data/src/toxi/sim/automata/MatrixEvolver.java +42 -0
  349. data/src/toxi/sim/dla/BottomUpOrder.java +76 -0
  350. data/src/toxi/sim/dla/DLA.java +497 -0
  351. data/src/toxi/sim/dla/DLAConfiguration.java +364 -0
  352. data/src/toxi/sim/dla/DLAEventAdapter.java +64 -0
  353. data/src/toxi/sim/dla/DLAEventListener.java +57 -0
  354. data/src/toxi/sim/dla/DLAGuideLines.java +219 -0
  355. data/src/toxi/sim/dla/DLAParticle.java +102 -0
  356. data/src/toxi/sim/dla/DLASegment.java +88 -0
  357. data/src/toxi/sim/dla/PipelineOrder.java +50 -0
  358. data/src/toxi/sim/dla/RadialDistanceOrder.java +92 -0
  359. data/src/toxi/sim/erosion/ErosionFunction.java +122 -0
  360. data/src/toxi/sim/erosion/TalusAngleErosion.java +145 -0
  361. data/src/toxi/sim/erosion/ThermalErosion.java +75 -0
  362. data/src/toxi/sim/fluids/FluidSolver2D.java +762 -0
  363. data/src/toxi/sim/fluids/FluidSolver3D.java +326 -0
  364. data/src/toxi/sim/grayscott/GrayScott.java +469 -0
  365. data/src/toxi/util/DateUtils.java +141 -0
  366. data/src/toxi/util/FileSequenceDescriptor.java +181 -0
  367. data/src/toxi/util/FileUtils.java +467 -0
  368. data/src/toxi/util/datatypes/ArraySet.java +128 -0
  369. data/src/toxi/util/datatypes/ArrayUtil.java +404 -0
  370. data/src/toxi/util/datatypes/BiasedDoubleRange.java +141 -0
  371. data/src/toxi/util/datatypes/BiasedFloatRange.java +141 -0
  372. data/src/toxi/util/datatypes/BiasedIntegerRange.java +141 -0
  373. data/src/toxi/util/datatypes/DoubleRange.java +251 -0
  374. data/src/toxi/util/datatypes/FloatRange.java +251 -0
  375. data/src/toxi/util/datatypes/GenericSet.java +215 -0
  376. data/src/toxi/util/datatypes/IntegerRange.java +247 -0
  377. data/src/toxi/util/datatypes/IntegerSet.java +149 -0
  378. data/src/toxi/util/datatypes/ItemIndex.java +72 -0
  379. data/src/toxi/util/datatypes/SingletonRegistry.java +91 -0
  380. data/src/toxi/util/datatypes/TypedProperties.java +291 -0
  381. data/src/toxi/util/datatypes/UndirectedGraph.java +134 -0
  382. data/src/toxi/util/datatypes/UniqueItemIndex.java +223 -0
  383. data/src/toxi/util/datatypes/WeightedRandomEntry.java +76 -0
  384. data/src/toxi/util/datatypes/WeightedRandomSet.java +125 -0
  385. data/src/toxi/util/events/EventDispatcher.java +86 -0
  386. data/src/toxi/volume/AdditiveBrush.java +19 -0
  387. data/src/toxi/volume/ArrayIsoSurface.java +297 -0
  388. data/src/toxi/volume/BoxBrush.java +100 -0
  389. data/src/toxi/volume/BrushMode.java +16 -0
  390. data/src/toxi/volume/HashIsoSurface.java +354 -0
  391. data/src/toxi/volume/IsoSurface.java +59 -0
  392. data/src/toxi/volume/MarchingCubesIndex.java +312 -0
  393. data/src/toxi/volume/MeshLatticeBuilder.java +358 -0
  394. data/src/toxi/volume/MeshVoxelizer.java +216 -0
  395. data/src/toxi/volume/MultiplyBrush.java +20 -0
  396. data/src/toxi/volume/PeakBrush.java +21 -0
  397. data/src/toxi/volume/ReplaceBrush.java +19 -0
  398. data/src/toxi/volume/RoundBrush.java +113 -0
  399. data/src/toxi/volume/VolumetricBrush.java +160 -0
  400. data/src/toxi/volume/VolumetricHashMap.java +179 -0
  401. data/src/toxi/volume/VolumetricSpace.java +195 -0
  402. data/src/toxi/volume/VolumetricSpaceArray.java +214 -0
  403. data/toxiclibs.gemspec +28 -0
  404. metadata +442 -31
@@ -0,0 +1,2599 @@
1
+ /*
2
+ * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
3
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
+ *
5
+ * This code is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU General Public License version 2 only, as
7
+ * published by the Free Software Foundation. Sun designates this
8
+ * particular file as subject to the "Classpath" exception as provided
9
+ * by Sun in the LICENSE file that accompanied this code.
10
+ *
11
+ * This code is distributed in the hope that it will be useful, but WITHOUT
12
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
+ * version 2 for more details (a copy is included in the LICENSE file that
15
+ * accompanied this code).
16
+ *
17
+ * You should have received a copy of the GNU General Public License version
18
+ * 2 along with this work; if not, write to the Free Software Foundation,
19
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
+ *
21
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22
+ * CA 95054 USA or visit www.sun.com if you need additional information or
23
+ * have any questions.
24
+ */
25
+ package toxi.geom;
26
+
27
+ import java.util.Arrays;
28
+ import toxi.math.MathUtils;
29
+
30
+ /**
31
+ * A double precision, row major, general and dynamically-resizable,
32
+ * two-dimensional matrix class. Row and column numbering begins with zero.
33
+ */
34
+ public class GMatrix implements java.io.Serializable, Cloneable {
35
+
36
+ static final long serialVersionUID = 1L;
37
+
38
+ /**
39
+ * Solves a set of linear equations. The input parameters "matrix1", and
40
+ * "row_perm" come from luDecompostion and do not change here. The parameter
41
+ * "matrix2" is a set of column vectors assembled into a nxn matrix of
42
+ * floating-point values. The procedure takes each column of "matrix2" in
43
+ * turn and treats it as the right-hand side of the matrix equation Ax = LUx
44
+ * = b. The solution vector replaces the original column of the matrix.
45
+ *
46
+ * If "matrix2" is the identity matrix, the procedure replaces its contents
47
+ * with the inverse of the matrix from which "matrix1" was originally
48
+ * derived.
49
+ *
50
+ * @param dim
51
+ * @param matrix1
52
+ * @param row_perm
53
+ * @param matrix2
54
+ */
55
+ //
56
+ // Reference: Press, Flannery, Teukolsky, Vetterling,
57
+ // _Numerical_Recipes_in_C_, Cambridge University Press,
58
+ // 1988, pp 44-45.
59
+ //
60
+ public static void backSubstituteLU(int dim, double[] matrix1,
61
+ int[] row_perm, double[] matrix2) {
62
+
63
+ int i, ii, ip, j, k;
64
+ int rp;
65
+ int cv, rv, ri;
66
+ double tt;
67
+
68
+ // rp = row_perm;
69
+ rp = 0;
70
+
71
+ // For each column vector of matrix2 ...
72
+ for (k = 0; k < dim; k++) {
73
+ // cv = &(matrix2[0][k]);
74
+ cv = k;
75
+ ii = -1;
76
+
77
+ // Forward substitution
78
+ for (i = 0; i < dim; i++) {
79
+ double sum;
80
+
81
+ ip = row_perm[rp + i];
82
+ sum = matrix2[cv + dim * ip];
83
+ matrix2[cv + dim * ip] = matrix2[cv + dim * i];
84
+ if (ii >= 0) {
85
+ // rv = &(matrix1[i][0]);
86
+ rv = i * dim;
87
+ for (j = ii; j <= i - 1; j++) {
88
+ sum -= matrix1[rv + j] * matrix2[cv + dim * j];
89
+ }
90
+ } else if (sum != 0.0) {
91
+ ii = i;
92
+ }
93
+ matrix2[cv + dim * i] = sum;
94
+ }
95
+
96
+ // Backsubstitution
97
+ for (i = 0; i < dim; i++) {
98
+ ri = (dim - 1 - i);
99
+ rv = dim * (ri);
100
+ tt = 0.0;
101
+ for (j = 1; j <= i; j++) {
102
+ tt += matrix1[rv + dim - j] * matrix2[cv + dim * (dim - j)];
103
+ }
104
+ matrix2[cv + dim * ri] = (matrix2[cv + dim * ri] - tt)
105
+ / matrix1[rv + ri];
106
+ }
107
+ }
108
+ }
109
+
110
+ private static void chase_across(double[] s, double[] e, int k, GMatrix u) {
111
+ double f, g, r;
112
+ double[] cosl = new double[1];
113
+ double[] sinl = new double[1];
114
+ int i;
115
+ GMatrix t = new GMatrix(u.nRow, u.nCol);
116
+ GMatrix m = new GMatrix(u.nRow, u.nCol);
117
+
118
+ g = e[k];
119
+ f = s[k + 1];
120
+
121
+ for (i = k; i < u.nCol - 2; i++) {
122
+ r = compute_rot(f, g, sinl, cosl);
123
+ g = -e[i + 1] * sinl[0];
124
+ f = s[i + 2];
125
+ s[i + 1] = r;
126
+ e[i + 1] = e[i + 1] * cosl[0];
127
+ update_u_split(k, i + 1, u, cosl, sinl, t, m);
128
+ }
129
+
130
+ s[i + 1] = compute_rot(f, g, sinl, cosl);
131
+ update_u_split(k, i + 1, u, cosl, sinl, t, m);
132
+ }
133
+
134
+ private static void chase_up(double[] s, double[] e, int k, GMatrix v) {
135
+ double f, g, r;
136
+ double[] cosr = new double[1];
137
+ double[] sinr = new double[1];
138
+ int i;
139
+ GMatrix t = new GMatrix(v.nRow, v.nCol);
140
+ GMatrix m = new GMatrix(v.nRow, v.nCol);
141
+
142
+ f = e[k];
143
+ g = s[k];
144
+
145
+ for (i = k; i > 0; i--) {
146
+ r = compute_rot(f, g, sinr, cosr);
147
+ f = -e[i - 1] * sinr[0];
148
+ g = s[i - 1];
149
+ s[i] = r;
150
+ e[i - 1] = e[i - 1] * cosr[0];
151
+ update_v_split(i, k + 1, v, cosr, sinr, t, m);
152
+ }
153
+
154
+ s[i + 1] = compute_rot(f, g, sinr, cosr);
155
+ update_v_split(i, k + 1, v, cosr, sinr, t, m);
156
+ }
157
+
158
+ private static void checkMatrix(GMatrix m) {
159
+ int i, j;
160
+
161
+ for (i = 0; i < m.nRow; i++) {
162
+ for (j = 0; j < m.nCol; j++) {
163
+ if (MathUtils.abs(m.values[i][j]) < 0.0000000001) {
164
+ System.out.print(" 0.0 ");
165
+ } else {
166
+ System.out.print(" " + m.values[i][j]);
167
+ }
168
+ }
169
+ System.out.print("\n");
170
+ }
171
+ }
172
+
173
+ private static int compute_2X2(double f, double g, double h,
174
+ double[] single_values, double[] snl, double[] csl, double[] snr,
175
+ double[] csr, int index) {
176
+
177
+ double c_b3 = 2.0;
178
+ double c_b4 = 1.0;
179
+
180
+ double d__1;
181
+ int pmax;
182
+ double temp;
183
+ boolean swap;
184
+ double a, d, l, m, r, s, t, tsign, fa, ga, ha;
185
+ double ft, gt, ht, mm;
186
+ boolean gasmal;
187
+ double tt, clt, crt, slt, srt;
188
+ double ssmin, ssmax;
189
+
190
+ ssmax = single_values[0];
191
+ ssmin = single_values[1];
192
+ clt = 0.0;
193
+ crt = 0.0;
194
+ slt = 0.0;
195
+ srt = 0.0;
196
+ tsign = 0.0;
197
+
198
+ ft = f;
199
+ fa = MathUtils.abs(ft);
200
+ ht = h;
201
+ ha = MathUtils.abs(h);
202
+
203
+ pmax = 1;
204
+ swap = ha > fa;
205
+
206
+ if (swap) {
207
+ pmax = 3;
208
+ temp = ft;
209
+ ft = ht;
210
+ ht = temp;
211
+ temp = fa;
212
+ fa = ha;
213
+ ha = temp;
214
+
215
+ }
216
+
217
+ gt = g;
218
+ ga = MathUtils.abs(gt);
219
+ if (ga == 0.0) {
220
+ single_values[1] = ha;
221
+ single_values[0] = fa;
222
+ clt = 1.0;
223
+ crt = 1.0;
224
+ slt = 0.0;
225
+ srt = 0.0;
226
+ } else {
227
+ gasmal = true;
228
+ if (ga > fa) {
229
+ pmax = 2;
230
+ if (fa / ga < EPS) {
231
+ gasmal = false;
232
+ ssmax = ga;
233
+
234
+ if (ha > 1.0) {
235
+ ssmin = fa / (ga / ha);
236
+ } else {
237
+ ssmin = fa / ga * ha;
238
+ }
239
+ clt = 1.0;
240
+ slt = ht / gt;
241
+ srt = 1.0;
242
+ crt = ft / gt;
243
+ }
244
+ }
245
+ if (gasmal) {
246
+ d = fa - ha;
247
+ if (d == fa) {
248
+
249
+ l = 1.0;
250
+ } else {
251
+ l = d / fa;
252
+ }
253
+
254
+ m = gt / ft;
255
+ t = 2.0 - l;
256
+ mm = m * m;
257
+ tt = t * t;
258
+ s = Math.sqrt(tt + mm);
259
+
260
+ if (l == 0.0) {
261
+ r = MathUtils.abs(m);
262
+ } else {
263
+ r = Math.sqrt(l * l + mm);
264
+ }
265
+
266
+ a = (s + r) * 0.5;
267
+ if (ga > fa) {
268
+ pmax = 2;
269
+ if (fa / ga < EPS) {
270
+ gasmal = false;
271
+ ssmax = ga;
272
+ if (ha > 1.0) {
273
+ ssmin = fa / (ga / ha);
274
+ } else {
275
+ ssmin = fa / ga * ha;
276
+ }
277
+ clt = 1.0;
278
+ slt = ht / gt;
279
+ srt = 1.0;
280
+ crt = ft / gt;
281
+ }
282
+ }
283
+ if (gasmal) {
284
+ d = fa - ha;
285
+ if (d == fa) {
286
+ l = 1.0;
287
+ } else {
288
+ l = d / fa;
289
+ }
290
+
291
+ m = gt / ft;
292
+ t = 2.0 - l;
293
+
294
+ mm = m * m;
295
+ tt = t * t;
296
+ s = Math.sqrt(tt + mm);
297
+
298
+ if (l == 0.) {
299
+ r = MathUtils.abs(m);
300
+ } else {
301
+ r = Math.sqrt(l * l + mm);
302
+ }
303
+
304
+ a = (s + r) * 0.5;
305
+ ssmin = ha / a;
306
+ ssmax = fa * a;
307
+
308
+ if (mm == 0.0) {
309
+ if (l == 0.0) {
310
+ t = MathUtils.dualSign(c_b3, ft)
311
+ * MathUtils.dualSign(c_b4, gt);
312
+ } else {
313
+ t = gt / MathUtils.dualSign(d, ft) + m / t;
314
+ }
315
+ } else {
316
+ t = (m / (s + t) + m / (r + l)) * (a + 1.0);
317
+ }
318
+
319
+ l = Math.sqrt(t * t + 4.0);
320
+ crt = 2.0 / l;
321
+ srt = t / l;
322
+ clt = (crt + srt * m) / a;
323
+ slt = ht / ft * srt / a;
324
+ }
325
+ }
326
+ if (swap) {
327
+ csl[0] = srt;
328
+ snl[0] = crt;
329
+ csr[0] = slt;
330
+ snr[0] = clt;
331
+ } else {
332
+ csl[0] = clt;
333
+ snl[0] = slt;
334
+ csr[0] = crt;
335
+ snr[0] = srt;
336
+ }
337
+
338
+ if (pmax == 1) {
339
+ tsign = MathUtils.dualSign(c_b4, csr[0])
340
+ * MathUtils.dualSign(c_b4, csl[0])
341
+ * MathUtils.dualSign(c_b4, f);
342
+ }
343
+ if (pmax == 2) {
344
+ tsign = MathUtils.dualSign(c_b4, snr[0])
345
+ * MathUtils.dualSign(c_b4, csl[0])
346
+ * MathUtils.dualSign(c_b4, g);
347
+ }
348
+ if (pmax == 3) {
349
+ tsign = MathUtils.dualSign(c_b4, snr[0])
350
+ * MathUtils.dualSign(c_b4, snl[0])
351
+ * MathUtils.dualSign(c_b4, h);
352
+ }
353
+
354
+ single_values[index] = MathUtils.dualSign(ssmax, tsign);
355
+ d__1 = tsign * MathUtils.dualSign(c_b4, f)
356
+ * MathUtils.dualSign(c_b4, h);
357
+ single_values[index + 1] = MathUtils.dualSign(ssmin, d__1);
358
+ }
359
+
360
+ return 0;
361
+ }
362
+
363
+ private static double compute_rot(double f, double g, double[] sin,
364
+ double[] cos) {
365
+ double cs, sn;
366
+ int i;
367
+ double scale;
368
+ int count;
369
+ double f1, g1;
370
+ double r;
371
+ final double safmn2 = 2.002083095183101E-146;
372
+ final double safmx2 = 4.994797680505588E+145;
373
+
374
+ if (g == 0.0) {
375
+ cs = 1.0;
376
+ sn = 0.0;
377
+ r = f;
378
+ } else if (f == 0.0) {
379
+ cs = 0.0;
380
+ sn = 1.0;
381
+ r = g;
382
+ } else {
383
+ f1 = f;
384
+ g1 = g;
385
+ scale = MathUtils.max(MathUtils.abs(f1), MathUtils.abs(g1));
386
+ if (scale >= safmx2) {
387
+ count = 0;
388
+ while (scale >= safmx2) {
389
+ ++count;
390
+ f1 *= safmn2;
391
+ g1 *= safmn2;
392
+ scale = MathUtils.max(MathUtils.abs(f1), MathUtils.abs(g1));
393
+ }
394
+ r = Math.sqrt(f1 * f1 + g1 * g1);
395
+ cs = f1 / r;
396
+ sn = g1 / r;
397
+ for (i = 1; i <= count; ++i) {
398
+ r *= safmx2;
399
+ }
400
+ } else if (scale <= safmn2) {
401
+ count = 0;
402
+ while (scale <= safmn2) {
403
+ ++count;
404
+ f1 *= safmx2;
405
+ g1 *= safmx2;
406
+ scale = MathUtils.max(MathUtils.abs(f1), MathUtils.abs(g1));
407
+ }
408
+ r = Math.sqrt(f1 * f1 + g1 * g1);
409
+ cs = f1 / r;
410
+ sn = g1 / r;
411
+ for (i = 1; i <= count; ++i) {
412
+ r *= safmn2;
413
+ }
414
+ } else {
415
+ r = Math.sqrt(f1 * f1 + g1 * g1);
416
+ cs = f1 / r;
417
+ sn = g1 / r;
418
+ }
419
+ if (MathUtils.abs(f) > MathUtils.abs(g) && cs < 0.0) {
420
+ cs = -cs;
421
+ sn = -sn;
422
+ r = -r;
423
+ }
424
+ }
425
+ sin[0] = sn;
426
+ cos[0] = cs;
427
+ return r;
428
+ }
429
+
430
+ private static double compute_shift(double f, double g, double h) {
431
+ double d__1, d__2;
432
+ double fhmn, fhmx, c, fa, ga, ha, as, at, au;
433
+ double ssmin;
434
+
435
+ fa = MathUtils.abs(f);
436
+ ga = MathUtils.abs(g);
437
+ ha = MathUtils.abs(h);
438
+ fhmn = MathUtils.min(fa, ha);
439
+ fhmx = MathUtils.max(fa, ha);
440
+
441
+ if (fhmn == 0.0) {
442
+ ssmin = 0.0;
443
+ if (fhmx == 0.0) {
444
+ } else {
445
+ d__1 = MathUtils.min(fhmx, ga) / MathUtils.max(fhmx, ga);
446
+ }
447
+ } else {
448
+ if (ga < fhmx) {
449
+ as = fhmn / fhmx + 1.0;
450
+ at = (fhmx - fhmn) / fhmx;
451
+ d__1 = ga / fhmx;
452
+ au = d__1 * d__1;
453
+ c = 2.0 / (Math.sqrt(as * as + au) + Math.sqrt(at * at + au));
454
+ ssmin = fhmn * c;
455
+ } else {
456
+ au = fhmx / ga;
457
+ if (au == 0.0) {
458
+ ssmin = fhmn * fhmx / ga;
459
+ } else {
460
+ as = fhmn / fhmx + 1.0;
461
+ at = (fhmx - fhmn) / fhmx;
462
+ d__1 = as * au;
463
+ d__2 = at * au;
464
+ c = 1.0 / (Math.sqrt(d__1 * d__1 + 1.0) + Math.sqrt(d__2
465
+ * d__2 + 1.0));
466
+ ssmin = fhmn * c * au;
467
+ ssmin += ssmin;
468
+ }
469
+ }
470
+ }
471
+
472
+ return ssmin;
473
+ }
474
+
475
+ /**
476
+ *
477
+ * @param start
478
+ * @param end
479
+ * @param s
480
+ * @param e
481
+ * @param u
482
+ * @param v
483
+ */
484
+ public static void computeQR(int start, int end, double[] s, double[] e,
485
+ GMatrix u, GMatrix v) {
486
+
487
+ int i, k, n, sl;
488
+ double shift, r, f, g;
489
+ double[] cosl = new double[1];
490
+ double[] cosr = new double[1];
491
+ double[] sinl = new double[1];
492
+ double[] sinr = new double[1];
493
+
494
+ final int MAX_INTERATIONS = 2;
495
+ final double CONVERGE_TOL = 4.89E-15;
496
+
497
+ boolean converged = false;
498
+
499
+ f = 0.0;
500
+ g = 0.0;
501
+
502
+ for (k = 0; k < MAX_INTERATIONS && !converged; k++) {
503
+ for (i = start; i <= end; i++) {
504
+
505
+ // if at start of iterfaction compute shift
506
+ if (i == start) {
507
+ if (e.length == s.length) {
508
+ sl = end;
509
+ } else {
510
+ sl = end + 1;
511
+ }
512
+
513
+ shift = compute_shift(s[sl - 1], e[end], s[sl]);
514
+
515
+ f = (MathUtils.abs(s[i]) - shift)
516
+ * (MathUtils.dualSign(1.0, s[i]) + shift / s[i]);
517
+ g = e[i];
518
+ }
519
+
520
+ r = compute_rot(f, g, sinr, cosr);
521
+ if (i != start) {
522
+ e[i - 1] = r;
523
+ }
524
+
525
+ f = cosr[0] * s[i] + sinr[0] * e[i];
526
+ e[i] = cosr[0] * e[i] - sinr[0] * s[i];
527
+ g = sinr[0] * s[i + 1];
528
+ s[i + 1] = cosr[0] * s[i + 1];
529
+
530
+ update_v(i, v, cosr, sinr);
531
+
532
+ r = compute_rot(f, g, sinl, cosl);
533
+ s[i] = r;
534
+ f = cosl[0] * e[i] + sinl[0] * s[i + 1];
535
+ s[i + 1] = cosl[0] * s[i + 1] - sinl[0] * e[i];
536
+
537
+ if (i < end) {
538
+ // if not last
539
+ g = sinl[0] * e[i + 1];
540
+ e[i + 1] = cosl[0] * e[i + 1];
541
+ }
542
+ update_u(i, u, cosl, sinl);
543
+ }
544
+
545
+ // if extra off diagonal perform one more right side rotation
546
+ if (s.length == e.length) {
547
+ r = compute_rot(f, g, sinr, cosr);
548
+ f = cosr[0] * s[i] + sinr[0] * e[i];
549
+ e[i] = cosr[0] * e[i] - sinr[0] * s[i];
550
+ s[i + 1] = cosr[0] * s[i + 1];
551
+
552
+ update_v(i, v, cosr, sinr);
553
+ }
554
+
555
+ // check for convergence on off diagonals and reduce
556
+ while ((end - start > 1) && (MathUtils.abs(e[end]) < CONVERGE_TOL)) {
557
+ end--;
558
+ }
559
+
560
+ // check if need to split
561
+ for (n = end - 2; n > start; n--) {
562
+ if (MathUtils.abs(e[n]) < CONVERGE_TOL) { // split
563
+ computeQR(n + 1, end, s, e, u, v); // do lower matrix
564
+ end = n - 1; // do upper matrix
565
+
566
+ // check for convergence on off diagonals and reduce
567
+ while ((end - start > 1)
568
+ && (MathUtils.abs(e[end]) < CONVERGE_TOL)) {
569
+ end--;
570
+ }
571
+ }
572
+ }
573
+
574
+ if ((end - start <= 1)
575
+ && (MathUtils.abs(e[start + 1]) < CONVERGE_TOL)) {
576
+ converged = true;
577
+ } else {
578
+ // check if zero on the diagonal
579
+ }
580
+
581
+ }
582
+
583
+ if (MathUtils.abs(e[1]) < CONVERGE_TOL) {
584
+ compute_2X2(s[start], e[start], s[start + 1], s, sinl, cosl, sinr,
585
+ cosr, 0);
586
+ e[start] = 0.0;
587
+ e[start + 1] = 0.0;
588
+ }
589
+
590
+ i = start;
591
+ update_u(i, u, cosl, sinl);
592
+ update_v(i, v, cosr, sinr);
593
+ }
594
+
595
+ /**
596
+ *
597
+ * @param mat
598
+ * @param U
599
+ * @param W
600
+ * @param V
601
+ * @return
602
+ */
603
+ public static int computeSVD(GMatrix mat, GMatrix U, GMatrix W, GMatrix V) {
604
+ int i, j, k;
605
+ int nr, nc, si;
606
+
607
+ int rank;
608
+ double mag, scale, t;
609
+ int eLength, sLength, vecLength;
610
+
611
+ GMatrix tmp = new GMatrix(mat.nRow, mat.nCol);
612
+ GMatrix u = new GMatrix(mat.nRow, mat.nCol);
613
+ GMatrix v = new GMatrix(mat.nRow, mat.nCol);
614
+ GMatrix m = new GMatrix(mat);
615
+
616
+ // compute the number of singular values
617
+ if (m.nRow >= m.nCol) {
618
+ sLength = m.nCol;
619
+ eLength = m.nCol - 1;
620
+ } else {
621
+ sLength = m.nRow;
622
+ eLength = m.nRow;
623
+ }
624
+
625
+ if (m.nRow > m.nCol) {
626
+ vecLength = m.nRow;
627
+ } else {
628
+ vecLength = m.nCol;
629
+ }
630
+
631
+ double[] vec = new double[vecLength];
632
+ double[] single_values = new double[sLength];
633
+ double[] e = new double[eLength];
634
+
635
+ rank = 0;
636
+
637
+ U.identity();
638
+ V.identity();
639
+
640
+ nr = m.nRow;
641
+ nc = m.nCol;
642
+
643
+ // householder reduction
644
+ for (si = 0; si < sLength; si++) {
645
+ // for each singular value
646
+
647
+ if (nr > 1) {
648
+ // compute reflector
649
+ mag = 0.0;
650
+ for (i = 0; i < nr; i++) {
651
+ mag += m.values[i + si][si] * m.values[i + si][si];
652
+ }
653
+
654
+ mag = Math.sqrt(mag);
655
+ if (m.values[si][si] == 0.0) {
656
+ vec[0] = mag;
657
+ } else {
658
+ vec[0] = m.values[si][si]
659
+ + MathUtils.dualSign(mag, m.values[si][si]);
660
+ }
661
+
662
+ for (i = 1; i < nr; i++) {
663
+ vec[i] = m.values[si + i][si];
664
+ }
665
+
666
+ scale = 0.0;
667
+ for (i = 0; i < nr; i++) {
668
+ scale += vec[i] * vec[i];
669
+ }
670
+
671
+ scale = 2.0 / scale;
672
+ for (j = si; j < m.nRow; j++) {
673
+ for (k = si; k < m.nRow; k++) {
674
+ u.values[j][k] = -scale * vec[j - si] * vec[k - si];
675
+ }
676
+ }
677
+
678
+ for (i = si; i < m.nRow; i++) {
679
+ u.values[i][i] += 1.0;
680
+ }
681
+
682
+ // compute s
683
+ t = 0.0;
684
+ for (i = si; i < m.nRow; i++) {
685
+ t += u.values[si][i] * m.values[i][si];
686
+ }
687
+ m.values[si][si] = t;
688
+
689
+ // apply reflector
690
+ for (j = si; j < m.nRow; j++) {
691
+ for (k = si + 1; k < m.nCol; k++) {
692
+ tmp.values[j][k] = 0.0;
693
+ for (i = si; i < m.nCol; i++) {
694
+ tmp.values[j][k] += u.values[j][i] * m.values[i][k];
695
+ }
696
+ }
697
+ }
698
+
699
+ for (j = si; j < m.nRow; j++) {
700
+ for (k = si + 1; k < m.nCol; k++) {
701
+ m.values[j][k] = tmp.values[j][k];
702
+ }
703
+ }
704
+
705
+ // update U matrix
706
+ for (j = si; j < m.nRow; j++) {
707
+ for (k = 0; k < m.nCol; k++) {
708
+ tmp.values[j][k] = 0.0;
709
+ for (i = si; i < m.nCol; i++) {
710
+ tmp.values[j][k] += u.values[j][i] * U.values[i][k];
711
+ }
712
+ }
713
+ }
714
+
715
+ for (j = si; j < m.nRow; j++) {
716
+ for (k = 0; k < m.nCol; k++) {
717
+ U.values[j][k] = tmp.values[j][k];
718
+ }
719
+ }
720
+ nr--;
721
+ }
722
+
723
+ if (nc > 2) {
724
+ mag = 0.0;
725
+ for (i = 1; i < nc; i++) {
726
+ mag += m.values[si][si + i] * m.values[si][si + i];
727
+ }
728
+ // generate the reflection vector, compute the first entry and
729
+ // copy the rest from the row to be zeroed
730
+ mag = Math.sqrt(mag);
731
+ if (m.values[si][si + 1] == 0.0) {
732
+ vec[0] = mag;
733
+ } else {
734
+ vec[0] = m.values[si][si + 1]
735
+ + MathUtils.dualSign(mag, m.values[si][si + 1]);
736
+ }
737
+
738
+ for (i = 1; i < nc - 1; i++) {
739
+ vec[i] = m.values[si][si + i + 1];
740
+ }
741
+
742
+ // use reflection vector to compute v matrix
743
+ scale = 0.0;
744
+ for (i = 0; i < nc - 1; i++) {
745
+ scale += vec[i] * vec[i];
746
+ }
747
+
748
+ scale = 2.0 / scale;
749
+ for (j = si + 1; j < nc; j++) {
750
+ for (k = si + 1; k < m.nCol; k++) {
751
+ v.values[j][k] = -scale * vec[j - si - 1]
752
+ * vec[k - si - 1];
753
+ }
754
+ }
755
+
756
+ for (i = si + 1; i < m.nCol; i++) {
757
+ v.values[i][i] += 1.0;
758
+ }
759
+
760
+ t = 0.0;
761
+ for (i = si; i < m.nCol; i++) {
762
+ t += v.values[i][si + 1] * m.values[si][i];
763
+ }
764
+ m.values[si][si + 1] = t;
765
+
766
+ // apply reflector
767
+ for (j = si + 1; j < m.nRow; j++) {
768
+ for (k = si + 1; k < m.nCol; k++) {
769
+ tmp.values[j][k] = 0.0;
770
+ for (i = si + 1; i < m.nCol; i++) {
771
+ tmp.values[j][k] += v.values[i][k] * m.values[j][i];
772
+ }
773
+ }
774
+ }
775
+
776
+ for (j = si + 1; j < m.nRow; j++) {
777
+ for (k = si + 1; k < m.nCol; k++) {
778
+ m.values[j][k] = tmp.values[j][k];
779
+ }
780
+ }
781
+
782
+ // update V matrix
783
+ for (j = 0; j < m.nRow; j++) {
784
+ for (k = si + 1; k < m.nCol; k++) {
785
+ tmp.values[j][k] = 0.0;
786
+ for (i = si + 1; i < m.nCol; i++) {
787
+ tmp.values[j][k] += v.values[i][k] * V.values[j][i];
788
+ }
789
+ }
790
+ }
791
+
792
+ for (j = 0; j < m.nRow; j++) {
793
+ for (k = si + 1; k < m.nCol; k++) {
794
+ V.values[j][k] = tmp.values[j][k];
795
+ }
796
+ }
797
+ nc--;
798
+ }
799
+ }
800
+
801
+ for (i = 0; i < sLength; i++) {
802
+ single_values[i] = m.values[i][i];
803
+ }
804
+
805
+ for (i = 0; i < eLength; i++) {
806
+ e[i] = m.values[i][i + 1];
807
+ }
808
+
809
+ // Fix ArrayIndexOutOfBounds for 2x2 matrices, which partially
810
+ // addresses bug 4348562 for J3D 1.2.1.
811
+ //
812
+ // Does *not* fix the following problems reported in 4348562,
813
+ // which will wait for J3D 1.3:
814
+ //
815
+ // 1) no output of W
816
+ // 2) wrong transposition of U
817
+ // 3) wrong results for 4x4 matrices
818
+ // 4) slow performance
819
+ if (m.nRow == 2 && m.nCol == 2) {
820
+ double[] cosl = new double[1];
821
+ double[] cosr = new double[1];
822
+ double[] sinl = new double[1];
823
+ double[] sinr = new double[1];
824
+
825
+ compute_2X2(single_values[0], e[0], single_values[1],
826
+ single_values, sinl, cosl, sinr, cosr, 0);
827
+
828
+ update_u(0, U, cosl, sinl);
829
+ update_v(0, V, cosr, sinr);
830
+ return 2;
831
+ }
832
+
833
+ // compute_qr causes ArrayIndexOutOfBounds for 2x2 matrices
834
+ computeQR(0, e.length - 1, single_values, e, U, V);
835
+
836
+ // compute rank = number of non zero singular values
837
+ rank = single_values.length;
838
+
839
+ // sort by order of size of single values
840
+ // and check for zero's
841
+ return rank;
842
+ }
843
+
844
+ /**
845
+ * Given a nxn array "matrix0", this function replaces it with the LU
846
+ * decomposition of a row-wise permutation of itself. The input parameters
847
+ * are "matrix0" and "dim". The array "matrix0" is also an output parameter.
848
+ * The vector "row_perm[]" is an output parameter that contains the row
849
+ * permutations resulting from partial pivoting. The output parameter
850
+ * "even_row_xchg" is 1 when the number of row exchanges is even, or -1
851
+ * otherwise. Assumes data type is always double.
852
+ *
853
+ * @param dim
854
+ * @param matrix0
855
+ * @param row_perm
856
+ * @param even_row_xchg
857
+ * @return true if the matrix is nonsingular, or false otherwise.
858
+ */
859
+ //
860
+ // Reference: Press, Flannery, Teukolsky, Vetterling,
861
+ // _Numerical_Recipes_in_C_, Cambridge University Press,
862
+ // 1988, pp 40-45.
863
+ //
864
+ public static boolean decomposeLU(int dim, double[] matrix0,
865
+ int[] row_perm, int[] even_row_xchg) {
866
+
867
+ double row_scale[] = new double[dim];
868
+
869
+ // Determine implicit scaling information by looping over rows
870
+ int i, j;
871
+ int ptr, rs, mtx;
872
+ double big, temp;
873
+
874
+ ptr = 0;
875
+ rs = 0;
876
+ even_row_xchg[0] = 1;
877
+
878
+ // For each row ...
879
+ i = dim;
880
+ while (i-- != 0) {
881
+ big = 0.0;
882
+
883
+ // For each column, find the largest element in the row
884
+ j = dim;
885
+ while (j-- != 0) {
886
+ temp = matrix0[ptr++];
887
+ temp = MathUtils.abs(temp);
888
+ if (temp > big) {
889
+ big = temp;
890
+ }
891
+ }
892
+
893
+ // Is the matrix singular?
894
+ if (big == 0.0) {
895
+ return false;
896
+ }
897
+ row_scale[rs++] = 1.0 / big;
898
+ }
899
+
900
+ // For all columns, execute Crout's method
901
+ mtx = 0;
902
+ for (j = 0; j < dim; j++) {
903
+ int imax, k;
904
+ int target, p1, p2;
905
+ double sum;
906
+
907
+ // Determine elements of upper diagonal matrix U
908
+ for (i = 0; i < j; i++) {
909
+ target = mtx + (dim * i) + j;
910
+ sum = matrix0[target];
911
+ k = i;
912
+ p1 = mtx + (dim * i);
913
+ p2 = mtx + j;
914
+ while (k-- != 0) {
915
+ sum -= matrix0[p1] * matrix0[p2];
916
+ p1++;
917
+ p2 += dim;
918
+ }
919
+ matrix0[target] = sum;
920
+ }
921
+
922
+ // Search for largest pivot element and calculate
923
+ // intermediate elements of lower diagonal matrix L.
924
+ big = 0.0;
925
+ imax = -1;
926
+ for (i = j; i < dim; i++) {
927
+ target = mtx + (dim * i) + j;
928
+ sum = matrix0[target];
929
+ k = j;
930
+ p1 = mtx + (dim * i);
931
+ p2 = mtx + j;
932
+ while (k-- != 0) {
933
+ sum -= matrix0[p1] * matrix0[p2];
934
+ p1++;
935
+ p2 += dim;
936
+ }
937
+ matrix0[target] = sum;
938
+
939
+ // Is this the best pivot so far?
940
+ if ((temp = row_scale[i] * MathUtils.abs(sum)) >= big) {
941
+ big = temp;
942
+ imax = i;
943
+ }
944
+ }
945
+
946
+ if (imax < 0) {
947
+ throw new RuntimeException();
948
+ }
949
+
950
+ // Is a row exchange necessary?
951
+ if (j != imax) {
952
+ // Yes: exchange rows
953
+ k = dim;
954
+ p1 = mtx + (dim * imax);
955
+ p2 = mtx + (dim * j);
956
+ while (k-- != 0) {
957
+ temp = matrix0[p1];
958
+ matrix0[p1++] = matrix0[p2];
959
+ matrix0[p2++] = temp;
960
+ }
961
+
962
+ // Record change in scale factor
963
+ row_scale[imax] = row_scale[j];
964
+ even_row_xchg[0] = -even_row_xchg[0]; // change exchange parity
965
+ }
966
+
967
+ // Record row permutation
968
+ row_perm[j] = imax;
969
+
970
+ // Is the matrix singular
971
+ if (matrix0[(mtx + (dim * j) + j)] == 0.0) {
972
+ return false;
973
+ }
974
+
975
+ // Divide elements of lower diagonal matrix L by pivot
976
+ if (j != (dim - 1)) {
977
+ temp = 1.0 / (matrix0[(mtx + (dim * j) + j)]);
978
+ target = mtx + (dim * (j + 1)) + j;
979
+ i = (dim - 1) - j;
980
+ while (i-- != 0) {
981
+ matrix0[target] *= temp;
982
+ target += dim;
983
+ }
984
+ }
985
+
986
+ }
987
+
988
+ return true;
989
+ }
990
+
991
+ private static void print_m(GMatrix m, GMatrix u, GMatrix v) {
992
+ GMatrix mtmp = new GMatrix(m.nCol, m.nRow);
993
+
994
+ mtmp.mul(u, mtmp);
995
+ mtmp.mul(mtmp, v);
996
+ System.out.println("\n m = \n" + GMatrix.toString(mtmp));
997
+
998
+ }
999
+
1000
+ private static void print_se(double[] s, double[] e) {
1001
+ System.out.println("\ns =" + s[0] + " " + s[1] + " " + s[2]);
1002
+ System.out.println("e =" + e[0] + " " + e[1]);
1003
+ }
1004
+
1005
+ private static void print_svd(double[] s, double[] e, GMatrix u, GMatrix v) {
1006
+ int i;
1007
+ GMatrix mtmp = new GMatrix(u.nCol, v.nRow);
1008
+
1009
+ System.out.println(" \ns = ");
1010
+ for (i = 0; i < s.length; i++) {
1011
+ System.out.println(" " + s[i]);
1012
+ }
1013
+
1014
+ System.out.println(" \ne = ");
1015
+ for (i = 0; i < e.length; i++) {
1016
+ System.out.println(" " + e[i]);
1017
+ }
1018
+
1019
+ System.out.println(" \nu = \n" + u.toString());
1020
+ System.out.println(" \nv = \n" + v.toString());
1021
+
1022
+ mtmp.identity();
1023
+ for (i = 0; i < s.length; i++) {
1024
+ mtmp.values[i][i] = s[i];
1025
+ }
1026
+ for (i = 0; i < e.length; i++) {
1027
+ mtmp.values[i][i + 1] = e[i];
1028
+ }
1029
+ System.out.println(" \nm = \n" + mtmp.toString());
1030
+
1031
+ mtmp.mulTransposeLeft(u, mtmp);
1032
+ mtmp.mulTransposeRight(mtmp, v);
1033
+
1034
+ System.out.println(" \n u.transpose*m*v.transpose = \n"
1035
+ + mtmp.toString());
1036
+ }
1037
+
1038
+ private static String toString(GMatrix m) {
1039
+ StringBuilder buffer = new StringBuilder(m.nRow * m.nCol * 8);
1040
+ int i, j;
1041
+
1042
+ for (i = 0; i < m.nRow; i++) {
1043
+ for (j = 0; j < m.nCol; j++) {
1044
+ if (MathUtils.abs(m.values[i][j]) < MathUtils.EPS) {
1045
+ buffer.append("0.0000 ");
1046
+ } else {
1047
+ buffer.append(m.values[i][j]).append(" ");
1048
+ }
1049
+ }
1050
+ buffer.append("\n");
1051
+ }
1052
+ return buffer.toString();
1053
+ }
1054
+
1055
+ private static void update_u(int index, GMatrix u, double[] cosl,
1056
+ double[] sinl) {
1057
+ int j;
1058
+ double utemp;
1059
+
1060
+ for (j = 0; j < u.nCol; j++) {
1061
+ utemp = u.values[index][j];
1062
+ u.values[index][j] = cosl[0] * utemp + sinl[0]
1063
+ * u.values[index + 1][j];
1064
+ u.values[index + 1][j] = -sinl[0] * utemp + cosl[0]
1065
+ * u.values[index + 1][j];
1066
+ }
1067
+ }
1068
+
1069
+ private static void update_u_split(int topr, int bottomr, GMatrix u,
1070
+ double[] cosl, double[] sinl, GMatrix t, GMatrix m) {
1071
+ int j;
1072
+ double utemp;
1073
+
1074
+ for (j = 0; j < u.nCol; j++) {
1075
+ utemp = u.values[topr][j];
1076
+ u.values[topr][j] = cosl[0] * utemp - sinl[0]
1077
+ * u.values[bottomr][j];
1078
+ u.values[bottomr][j] = sinl[0] * utemp + cosl[0]
1079
+ * u.values[bottomr][j];
1080
+ }
1081
+
1082
+ checkMatrix(m);
1083
+ checkMatrix(t);
1084
+ m.mul(t, m);
1085
+ checkMatrix(m);
1086
+ }
1087
+
1088
+ private static void update_v(int index, GMatrix v, double[] cosr,
1089
+ double[] sinr) {
1090
+ int j;
1091
+ double vtemp;
1092
+
1093
+ for (j = 0; j < v.nRow; j++) {
1094
+ vtemp = v.values[j][index];
1095
+ v.values[j][index] = cosr[0] * vtemp + sinr[0]
1096
+ * v.values[j][index + 1];
1097
+ v.values[j][index + 1] = -sinr[0] * vtemp + cosr[0]
1098
+ * v.values[j][index + 1];
1099
+ }
1100
+ }
1101
+
1102
+ private static void update_v_split(int topr, int bottomr, GMatrix v,
1103
+ double[] cosr, double[] sinr, GMatrix t, GMatrix m) {
1104
+ int j;
1105
+ double vtemp;
1106
+
1107
+ for (j = 0; j < v.nRow; j++) {
1108
+ vtemp = v.values[j][topr];
1109
+ v.values[j][topr] = cosr[0] * vtemp - sinr[0]
1110
+ * v.values[j][bottomr];
1111
+ v.values[j][bottomr] = sinr[0] * vtemp + cosr[0]
1112
+ * v.values[j][bottomr];
1113
+ }
1114
+
1115
+ checkMatrix(m);
1116
+ checkMatrix(t);
1117
+ m.mul(m, t);
1118
+ checkMatrix(m);
1119
+ }
1120
+
1121
+ int nRow;
1122
+
1123
+ int nCol;
1124
+
1125
+ // double dereference is slow
1126
+ double[][] values;
1127
+
1128
+ private static final double EPS = 1.0E-10;
1129
+
1130
+ /**
1131
+ * Constructs a new GMatrix and copies the initial values from the parameter
1132
+ * matrix.
1133
+ *
1134
+ * @param matrix the source of the initial values of the new GMatrix
1135
+ */
1136
+ public GMatrix(GMatrix matrix) {
1137
+ nRow = matrix.nRow;
1138
+ nCol = matrix.nCol;
1139
+ values = new double[nRow][nCol];
1140
+
1141
+ int i, j;
1142
+ for (i = 0; i < nRow; i++) {
1143
+ for (j = 0; j < nCol; j++) {
1144
+ values[i][j] = matrix.values[i][j];
1145
+ }
1146
+ }
1147
+ }
1148
+
1149
+ /**
1150
+ * Constructs an nRow by NCol identity matrix. Note that because row and
1151
+ * column numbering begins with zero, nRow and nCol will be one larger than
1152
+ * the maximum possible matrix index values.
1153
+ *
1154
+ * @param nRow number of rows in this matrix.
1155
+ * @param nCol number of columns in this matrix.
1156
+ */
1157
+ public GMatrix(int nRow, int nCol) {
1158
+ values = new double[nRow][nCol];
1159
+ this.nRow = nRow;
1160
+ this.nCol = nCol;
1161
+
1162
+ int i, j;
1163
+ for (i = 0; i < nRow; i++) {
1164
+ for (j = 0; j < nCol; j++) {
1165
+ values[i][j] = 0.0;
1166
+ }
1167
+ }
1168
+
1169
+ int l;
1170
+ if (nRow < nCol) {
1171
+ l = nRow;
1172
+ } else {
1173
+ l = nCol;
1174
+ }
1175
+
1176
+ for (i = 0; i < l; i++) {
1177
+ values[i][i] = 1.0;
1178
+ }
1179
+ }
1180
+
1181
+ /**
1182
+ * Constructs an nRow by nCol matrix initialized to the values in the matrix
1183
+ * array. The array values are copied in one row at a time in row major
1184
+ * fashion. The array should be at least nRow*nCol in length. Note that
1185
+ * because row and column numbering begins with zero, nRow and nCol will be
1186
+ * one larger than the maximum possible matrix index values.
1187
+ *
1188
+ * @param nRow number of rows in this matrix.
1189
+ * @param nCol number of columns in this matrix.
1190
+ * @param matrix a 1D array that specifies a matrix in row major fashion
1191
+ */
1192
+ public GMatrix(int nRow, int nCol, double[] matrix) {
1193
+ values = new double[nRow][nCol];
1194
+ this.nRow = nRow;
1195
+ this.nCol = nCol;
1196
+
1197
+ int i, j;
1198
+ for (i = 0; i < nRow; i++) {
1199
+ for (j = 0; j < nCol; j++) {
1200
+ values[i][j] = matrix[i * nCol + j];
1201
+ }
1202
+ }
1203
+ }
1204
+
1205
+ /**
1206
+ * Sets the value of this matrix to sum of itself and matrix m1.
1207
+ *
1208
+ * @param m1 the other matrix
1209
+ */
1210
+ public final void add(GMatrix m1) {
1211
+ int i, j;
1212
+
1213
+ if (nRow != m1.nRow) {
1214
+ throw new MatrixSizeException();
1215
+ }
1216
+
1217
+ if (nCol != m1.nCol) {
1218
+ throw new MatrixSizeException();
1219
+ }
1220
+
1221
+ for (i = 0; i < nRow; i++) {
1222
+ for (j = 0; j < nCol; j++) {
1223
+ values[i][j] = values[i][j] + m1.values[i][j];
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ /**
1229
+ * Sets the value of this matrix to the matrix sum of matrices m1 and m2.
1230
+ *
1231
+ * @param m1 the first matrix
1232
+ * @param m2 the second matrix
1233
+ */
1234
+ public final void add(GMatrix m1, GMatrix m2) {
1235
+ int i, j;
1236
+
1237
+ if (m2.nRow != m1.nRow) {
1238
+ throw new MatrixSizeException();
1239
+ }
1240
+
1241
+ if (m2.nCol != m1.nCol) {
1242
+ throw new MatrixSizeException();
1243
+ }
1244
+
1245
+ if (nCol != m1.nCol || nRow != m1.nRow) {
1246
+ throw new MatrixSizeException();
1247
+ }
1248
+
1249
+ for (i = 0; i < nRow; i++) {
1250
+ for (j = 0; j < nCol; j++) {
1251
+ values[i][j] = m1.values[i][j] + m2.values[i][j];
1252
+ }
1253
+ }
1254
+ }
1255
+
1256
+ /**
1257
+ * Creates a new object of the same class as this object.
1258
+ *
1259
+ * @return a clone of this instance.
1260
+ * @exception OutOfMemoryError if there is not enough memory.
1261
+ * @see java.lang.Cloneable
1262
+ * @since vecmath 1.3
1263
+ */
1264
+ // @Override
1265
+ // public Object clone() throws CloneNotSupportedException {
1266
+ // GMatrix m1 = null;
1267
+ // try {
1268
+ // m1 = (GMatrix) super.clone();
1269
+ // } catch (CloneNotSupportedException e) {
1270
+ // // this shouldn't happen, since we are Cloneable
1271
+ // throw new InternalError();
1272
+ // }
1273
+ //
1274
+ // // Also need to clone array of values
1275
+ // m1.values = new double[nRow][nCol];
1276
+ // for (int i = 0; i < nRow; i++) {
1277
+ // System.arraycopy(values[i], 0, m1.values[i], 0, nCol);
1278
+ // }
1279
+ //
1280
+ // return m1;
1281
+ // }
1282
+
1283
+ /**
1284
+ * LU Decomposition: this matrix must be a square matrix and the LU GMatrix
1285
+ * parameter must be the same size as this matrix. The matrix LU will be
1286
+ * overwritten as the combination of a lower diagonal and upper diagonal
1287
+ * matrix decompostion of this matrix; the diagonal elements of L (unity)
1288
+ * are not stored. The GVector parameter records the row permutation
1289
+ * effected by the partial pivoting, and is used as a parameter to the
1290
+ * GVector method LUDBackSolve to solve sets of linear equations. This
1291
+ * method returns +/- 1 depending on whether the number of row interchanges
1292
+ * was even or odd, respectively.
1293
+ *
1294
+ * @param LU The matrix into which the lower and upper decompositions will
1295
+ * be placed.
1296
+ * @param permutation The row permutation effected by the partial pivoting
1297
+ * @return +-1 depending on whether the number of row interchanges was even
1298
+ * or odd respectively
1299
+ */
1300
+ public final int computeLUD(GMatrix LU, GVector permutation) {
1301
+ int size = LU.nRow * LU.nCol;
1302
+ double[] temp = new double[size];
1303
+ int[] even_row_exchange = new int[1];
1304
+ int[] row_perm = new int[LU.nRow];
1305
+ int i, j;
1306
+
1307
+ if (nRow != nCol) {
1308
+ throw new MatrixSizeException();
1309
+ }
1310
+
1311
+ if (nRow != LU.nRow) {
1312
+ throw new MatrixSizeException();
1313
+ }
1314
+
1315
+ if (nCol != LU.nCol) {
1316
+ throw new MatrixSizeException();
1317
+ }
1318
+
1319
+ if (LU.nRow != permutation.size()) {
1320
+ throw new MatrixSizeException();
1321
+ }
1322
+
1323
+ for (i = 0; i < nRow; i++) {
1324
+ for (j = 0; j < nCol; j++) {
1325
+ temp[i * nCol + j] = values[i][j];
1326
+ }
1327
+ }
1328
+
1329
+ // Calculate LU decomposition: Is the matrix singular?
1330
+ if (!decomposeLU(LU.nRow, temp, row_perm, even_row_exchange)) {
1331
+ // Matrix has no inverse
1332
+ throw new SingularMatrixException();
1333
+ }
1334
+
1335
+ for (i = 0; i < nRow; i++) {
1336
+ for (j = 0; j < nCol; j++) {
1337
+ LU.values[i][j] = temp[i * nCol + j];
1338
+ }
1339
+ }
1340
+
1341
+ for (i = 0; i < LU.nRow; i++) {
1342
+ permutation.values[i] = row_perm[i];
1343
+ }
1344
+
1345
+ return even_row_exchange[0];
1346
+ }
1347
+
1348
+ /**
1349
+ * Finds the singular value decomposition (SVD) of this matrix such that
1350
+ * this = U*W*transpose(V); and returns the rank of this matrix; the values
1351
+ * of U,W,V are all overwritten. Note that the matrix V is output as V, and
1352
+ * not transpose(V). If this matrix is mxn, then U is mxm, W is a diagonal
1353
+ * matrix that is mxn, and V is nxn. Using the notation W = diag(w), then
1354
+ * the inverse of this matrix is: inverse(this) = V*diag(1/w)*tranpose(U),
1355
+ * where diag(1/w) is the same matrix as W except that the reciprocal of
1356
+ * each of the diagonal components is used.
1357
+ *
1358
+ * @param U The computed U matrix in the equation this = U*W*transpose(V)
1359
+ * @param W The computed W matrix in the equation this = U*W*transpose(V)
1360
+ * @param V The computed V matrix in the equation this = U*W*transpose(V)
1361
+ * @return The rank of this matrix.
1362
+ */
1363
+ public final int computeSVD(GMatrix U, GMatrix W, GMatrix V) {
1364
+ // check for consistancy in dimensions
1365
+ if (nCol != V.nCol || nCol != V.nRow) {
1366
+ throw new MatrixSizeException();
1367
+ }
1368
+
1369
+ if (nRow != U.nRow || nRow != U.nCol) {
1370
+ throw new MatrixSizeException();
1371
+ }
1372
+
1373
+ if (nRow != W.nRow || nCol != W.nCol) {
1374
+ throw new MatrixSizeException();
1375
+ }
1376
+
1377
+ // Fix ArrayIndexOutOfBounds for 2x2 matrices, which partially
1378
+ // addresses bug 4348562 for J3D 1.2.1.
1379
+ //
1380
+ // Does *not* fix the following problems reported in 4348562,
1381
+ // which will wait for J3D 1.3:
1382
+ //
1383
+ // 1) no output of W
1384
+ // 2) wrong transposition of U
1385
+ // 3) wrong results for 4x4 matrices
1386
+ // 4) slow performance
1387
+ if (nRow == 2 && nCol == 2) {
1388
+ if (values[1][0] == 0.0) {
1389
+ U.identity();
1390
+ V.identity();
1391
+
1392
+ if (values[0][1] == 0.0) {
1393
+ return 2;
1394
+ }
1395
+
1396
+ double[] sinl = new double[1];
1397
+ double[] sinr = new double[1];
1398
+ double[] cosl = new double[1];
1399
+ double[] cosr = new double[1];
1400
+ double[] single_values = new double[2];
1401
+
1402
+ single_values[0] = values[0][0];
1403
+ single_values[1] = values[1][1];
1404
+
1405
+ compute_2X2(values[0][0], values[0][1], values[1][1],
1406
+ single_values, sinl, cosl, sinr, cosr, 0);
1407
+
1408
+ update_u(0, U, cosl, sinl);
1409
+ update_v(0, V, cosr, sinr);
1410
+
1411
+ return 2;
1412
+ }
1413
+ // else call computeSVD() and check for 2x2 there
1414
+ }
1415
+
1416
+ return computeSVD(this, U, W, V);
1417
+ }
1418
+
1419
+ /**
1420
+ * Copies a sub-matrix derived from this matrix into the target matrix. The
1421
+ * upper left of the sub-matrix is located at (rowSource, colSource); the
1422
+ * lower right of the sub-matrix is located at
1423
+ * (lastRowSource,lastColSource). The sub-matrix is copied into the the
1424
+ * target matrix starting at (rowDest, colDest).
1425
+ *
1426
+ * @param rowSource the top-most row of the sub-matrix
1427
+ * @param colSource the left-most column of the sub-matrix
1428
+ * @param numRow the number of rows in the sub-matrix
1429
+ * @param numCol the number of columns in the sub-matrix
1430
+ * @param rowDest the top-most row of the position of the copied sub-matrix
1431
+ * within the target matrix
1432
+ * @param colDest the left-most column of the position of the copied
1433
+ * sub-matrix within the target matrix
1434
+ * @param target the matrix into which the sub-matrix will be copied
1435
+ */
1436
+ public final void copySubMatrix(int rowSource, int colSource, int numRow,
1437
+ int numCol, int rowDest, int colDest, GMatrix target) {
1438
+ int i, j;
1439
+
1440
+ if (this != target) {
1441
+ for (i = 0; i < numRow; i++) {
1442
+ for (j = 0; j < numCol; j++) {
1443
+ target.values[rowDest + i][colDest + j] = values[rowSource
1444
+ + i][colSource + j];
1445
+ }
1446
+ }
1447
+ } else {
1448
+ double[][] tmp = new double[numRow][numCol];
1449
+ for (i = 0; i < numRow; i++) {
1450
+ for (j = 0; j < numCol; j++) {
1451
+ tmp[i][j] = values[rowSource + i][colSource + j];
1452
+ }
1453
+ }
1454
+ for (i = 0; i < numRow; i++) {
1455
+ for (j = 0; j < numCol; j++) {
1456
+ target.values[rowDest + i][colDest + j] = tmp[i][j];
1457
+ }
1458
+ }
1459
+ }
1460
+ }
1461
+
1462
+ /**
1463
+ * Returns true if the L-infinite distance between this matrix and matrix m1
1464
+ * is less than or equal to the epsilon parameter, otherwise returns false.
1465
+ * The L-infinite distance is equal to MAX[i=0,1,2, . . .n ; j=0,1,2, . . .n
1466
+ * ; abs(this.m(i,j) - m1.m(i,j)]
1467
+ *
1468
+ * @param m1 The matrix to be compared to this matrix
1469
+ * @param epsilon the threshold value
1470
+ * @return
1471
+ */
1472
+ public boolean epsilonEquals(GMatrix m1, double epsilon) {
1473
+ int i, j;
1474
+ double diff;
1475
+ if (nRow != m1.nRow || nCol != m1.nCol) {
1476
+ return false;
1477
+ }
1478
+
1479
+ for (i = 0; i < nRow; i++) {
1480
+ for (j = 0; j < nCol; j++) {
1481
+ diff = values[i][j] - m1.values[i][j];
1482
+ if ((diff < 0 ? -diff : diff) > epsilon) {
1483
+ return false;
1484
+ }
1485
+ }
1486
+ }
1487
+ return true;
1488
+ }
1489
+
1490
+ /**
1491
+ * @param m1
1492
+ * @param epsilon
1493
+ * @return
1494
+ * @deprecated Use epsilonEquals(GMatrix, double) instead
1495
+ */
1496
+ @Deprecated
1497
+ public boolean epsilonEquals(GMatrix m1, float epsilon) {
1498
+ return epsilonEquals(m1, (double) epsilon);
1499
+ }
1500
+
1501
+ /**
1502
+ * Returns true if all of the data members of GMatrix m1 are equal to the
1503
+ * corresponding data members in this GMatrix.
1504
+ *
1505
+ * @param m1 The matrix with which the comparison is made.
1506
+ * @return true or false
1507
+ */
1508
+ public boolean equals(GMatrix m1) {
1509
+ try {
1510
+ int i, j;
1511
+
1512
+ if (nRow != m1.nRow || nCol != m1.nCol) {
1513
+ return false;
1514
+ }
1515
+
1516
+ for (i = 0; i < nRow; i++) {
1517
+ for (j = 0; j < nCol; j++) {
1518
+ if (values[i][j] != m1.values[i][j]) {
1519
+ return false;
1520
+ }
1521
+ }
1522
+ }
1523
+ return true;
1524
+ } catch (NullPointerException e2) {
1525
+ return false;
1526
+ }
1527
+ }
1528
+
1529
+ /**
1530
+ * Returns true if the Object o1 is of type GMatrix and all of the data
1531
+ * members of o1 are equal to the corresponding data members in this
1532
+ * GMatrix.
1533
+ *
1534
+ * @param o1 The object with which the comparison is made.
1535
+ * @return true or false
1536
+ */
1537
+ @Override
1538
+ public boolean equals(Object o1) {
1539
+ if (o1 instanceof GMatrix) {
1540
+ GMatrix m2 = (GMatrix) o1;
1541
+ int i, j;
1542
+ if (nRow != m2.nRow || nCol != m2.nCol) {
1543
+ return false;
1544
+ }
1545
+
1546
+ for (i = 0; i < nRow; i++) {
1547
+ for (j = 0; j < nCol; j++) {
1548
+ if (values[i][j] != m2.values[i][j]) {
1549
+ return false;
1550
+ }
1551
+ }
1552
+
1553
+ }
1554
+ return true;
1555
+ }
1556
+ return false;
1557
+ }
1558
+
1559
+ /**
1560
+ *
1561
+ * @return
1562
+ */
1563
+ @Override
1564
+ public int hashCode() {
1565
+ int hash = 7;
1566
+ hash = 67 * hash + this.nRow;
1567
+ hash = 67 * hash + this.nCol;
1568
+ hash = 67 * hash + Arrays.deepHashCode(this.values);
1569
+ return hash;
1570
+ }
1571
+ /**
1572
+ * Places the values in the this GMatrix into the matrix m1; m1 should
1573
+ * be at least as large as this GMatrix.
1574
+ *
1575
+ * @param m1 The matrix that will hold the new values
1576
+ */
1577
+ public final void get(GMatrix m1) {
1578
+ int i, j, nc, nr;
1579
+
1580
+ if (nCol < m1.nCol) {
1581
+ nc = nCol;
1582
+ } else {
1583
+ nc = m1.nCol;
1584
+ }
1585
+
1586
+ if (nRow < m1.nRow) {
1587
+ nr = nRow;
1588
+ } else {
1589
+ nr = m1.nRow;
1590
+ }
1591
+
1592
+ for (i = 0; i < nr; i++) {
1593
+ for (j = 0; j < nc; j++) {
1594
+ m1.values[i][j] = values[i][j];
1595
+ }
1596
+ }
1597
+ for (i = nr; i < m1.nRow; i++) {
1598
+ for (j = 0; j < m1.nCol; j++) {
1599
+ m1.values[i][j] = 0.0;
1600
+ }
1601
+ }
1602
+ for (j = nc; j < m1.nCol; j++) {
1603
+ for (i = 0; i < nr; i++) {
1604
+ m1.values[i][j] = 0.0;
1605
+ }
1606
+ }
1607
+ }
1608
+
1609
+ /**
1610
+ * Places the values in the upper 3x3 of this GMatrix into the matrix m1.
1611
+ *
1612
+ * @param m1 The matrix that will hold the new values
1613
+ */
1614
+ public final void get(Matrix3d m1) {
1615
+ if (nRow < 3 || nCol < 3) {
1616
+ m1.setZero();
1617
+ if (nCol > 0) {
1618
+ if (nRow > 0) {
1619
+ m1.m00 = values[0][0];
1620
+ if (nRow > 1) {
1621
+ m1.m10 = values[1][0];
1622
+ if (nRow > 2) {
1623
+ m1.m20 = values[2][0];
1624
+ }
1625
+ }
1626
+ }
1627
+ if (nCol > 1) {
1628
+ if (nRow > 0) {
1629
+ m1.m01 = values[0][1];
1630
+ if (nRow > 1) {
1631
+ m1.m11 = values[1][1];
1632
+ if (nRow > 2) {
1633
+ m1.m21 = values[2][1];
1634
+ }
1635
+ }
1636
+ }
1637
+ if (nCol > 2) {
1638
+ if (nRow > 0) {
1639
+ m1.m02 = values[0][2];
1640
+ if (nRow > 1) {
1641
+ m1.m12 = values[1][2];
1642
+ if (nRow > 2) {
1643
+ m1.m22 = values[2][2];
1644
+ }
1645
+ }
1646
+ }
1647
+ }
1648
+ }
1649
+ }
1650
+ } else {
1651
+ m1.m00 = values[0][0];
1652
+ m1.m01 = values[0][1];
1653
+ m1.m02 = values[0][2];
1654
+
1655
+ m1.m10 = values[1][0];
1656
+ m1.m11 = values[1][1];
1657
+ m1.m12 = values[1][2];
1658
+
1659
+ m1.m20 = values[2][0];
1660
+ m1.m21 = values[2][1];
1661
+ m1.m22 = values[2][2];
1662
+ }
1663
+ }
1664
+
1665
+ /**
1666
+ * Places the values in the upper 4x4 of this GMatrix into the matrix m1.
1667
+ *
1668
+ * @param m1 The matrix that will hold the new values
1669
+ */
1670
+ public final void get(Matrix4f m1) {
1671
+
1672
+ if (nRow < 4 || nCol < 4) {
1673
+ m1.setZero();
1674
+ if (nCol > 0) {
1675
+ if (nRow > 0) {
1676
+ m1.m00 = (float) values[0][0];
1677
+ if (nRow > 1) {
1678
+ m1.m10 = (float) values[1][0];
1679
+ if (nRow > 2) {
1680
+ m1.m20 = (float) values[2][0];
1681
+ if (nRow > 3) {
1682
+ m1.m30 = (float) values[3][0];
1683
+ }
1684
+ }
1685
+ }
1686
+ }
1687
+ if (nCol > 1) {
1688
+ if (nRow > 0) {
1689
+ m1.m01 = (float) values[0][1];
1690
+ if (nRow > 1) {
1691
+ m1.m11 = (float) values[1][1];
1692
+ if (nRow > 2) {
1693
+ m1.m21 = (float) values[2][1];
1694
+ if (nRow > 3) {
1695
+ m1.m31 = (float) values[3][1];
1696
+ }
1697
+ }
1698
+ }
1699
+ }
1700
+ if (nCol > 2) {
1701
+ if (nRow > 0) {
1702
+ m1.m02 = (float) values[0][2];
1703
+ if (nRow > 1) {
1704
+ m1.m12 = (float) values[1][2];
1705
+ if (nRow > 2) {
1706
+ m1.m22 = (float) values[2][2];
1707
+ if (nRow > 3) {
1708
+ m1.m32 = (float) values[3][2];
1709
+ }
1710
+ }
1711
+ }
1712
+ }
1713
+ if (nCol > 3) {
1714
+ if (nRow > 0) {
1715
+ m1.m03 = (float) values[0][3];
1716
+ if (nRow > 1) {
1717
+ m1.m13 = (float) values[1][3];
1718
+ if (nRow > 2) {
1719
+ m1.m23 = (float) values[2][3];
1720
+ if (nRow > 3) {
1721
+ m1.m33 = (float) values[3][3];
1722
+ }
1723
+ }
1724
+ }
1725
+ }
1726
+ }
1727
+ }
1728
+ }
1729
+ }
1730
+ } else {
1731
+ m1.m00 = (float) values[0][0];
1732
+ m1.m01 = (float) values[0][1];
1733
+ m1.m02 = (float) values[0][2];
1734
+ m1.m03 = (float) values[0][3];
1735
+
1736
+ m1.m10 = (float) values[1][0];
1737
+ m1.m11 = (float) values[1][1];
1738
+ m1.m12 = (float) values[1][2];
1739
+ m1.m13 = (float) values[1][3];
1740
+
1741
+ m1.m20 = (float) values[2][0];
1742
+ m1.m21 = (float) values[2][1];
1743
+ m1.m22 = (float) values[2][2];
1744
+ m1.m23 = (float) values[2][3];
1745
+
1746
+ m1.m30 = (float) values[3][0];
1747
+ m1.m31 = (float) values[3][1];
1748
+ m1.m32 = (float) values[3][2];
1749
+ m1.m33 = (float) values[3][3];
1750
+ }
1751
+ }
1752
+
1753
+ /**
1754
+ * Places the values of the specified column into the array parameter.
1755
+ *
1756
+ * @param col the target column number
1757
+ * @param array the array into which the column values will be placed
1758
+ */
1759
+ public final void getColumn(int col, double[] array) {
1760
+ for (int i = 0; i < nRow; i++) {
1761
+ array[i] = values[i][col];
1762
+ }
1763
+
1764
+ }
1765
+
1766
+ /**
1767
+ * Places the values of the specified column into the vector parameter.
1768
+ *
1769
+ * @param col the target column number
1770
+ * @param vector the vector into which the column values will be placed
1771
+ */
1772
+ public final void getColumn(int col, GVector vector) {
1773
+ if (vector.size() < nRow) {
1774
+ vector.setSize(nRow);
1775
+ }
1776
+
1777
+ for (int i = 0; i < nRow; i++) {
1778
+ vector.values[i] = values[i][col];
1779
+ }
1780
+ }
1781
+
1782
+ /**
1783
+ * Retrieves the value at the specified row and column of this matrix.
1784
+ *
1785
+ * @param row the row number to be retrieved (zero indexed)
1786
+ * @param column the column number to be retrieved (zero indexed)
1787
+ * @return the value at the indexed element
1788
+ */
1789
+ public final double getElement(int row, int column) {
1790
+ return (values[row][column]);
1791
+ }
1792
+
1793
+ /**
1794
+ * Returns the number of colmuns in this matrix.
1795
+ *
1796
+ * @return number of columns in this matrix
1797
+ */
1798
+ public final int getNumCol() {
1799
+ return (nCol);
1800
+ }
1801
+
1802
+ /**
1803
+ * Returns the number of rows in this matrix.
1804
+ *
1805
+ * @return number of rows in this matrix
1806
+ */
1807
+ public final int getNumRow() {
1808
+ return (nRow);
1809
+ }
1810
+
1811
+ /**
1812
+ * Places the values of the specified row into the array parameter.
1813
+ *
1814
+ * @param row the target row number
1815
+ * @param array the array into which the row values will be placed
1816
+ */
1817
+ public final void getRow(int row, double[] array) {
1818
+ System.arraycopy(values[row], 0, array, 0, nCol);
1819
+ }
1820
+
1821
+ /**
1822
+ * Places the values of the specified row into the vector parameter.
1823
+ *
1824
+ * @param row the target row number
1825
+ * @param vector the vector into which the row values will be placed
1826
+ */
1827
+ public final void getRow(int row, GVector vector) {
1828
+ if (vector.size() < nCol) {
1829
+ vector.setSize(nCol);
1830
+ }
1831
+ System.arraycopy(values[row], 0, vector.values, 0, nCol);
1832
+ }
1833
+
1834
+ /**
1835
+ * Returns a hash code value based on the data values in this object. Two
1836
+ * different GMatrix objects with identical data values (i.e.,
1837
+ * GMatrix.equals returns true) will return the same hash number. Two
1838
+ * GMatrix objects with different data members may return the same hash
1839
+ * value, although this is not likely.
1840
+ *
1841
+ * @return the integer hash code value
1842
+ */
1843
+ // @Override
1844
+ // public int hashCode() {
1845
+ // long bits = 1L;
1846
+ //
1847
+ // bits = 31L * bits + nRow;
1848
+ // bits = 31L * bits + nCol;
1849
+ //
1850
+ // for (int i = 0; i < nRow; i++) {
1851
+ // for (int j = 0; j < nCol; j++) {
1852
+ // bits = 31L * bits + VecMathUtil.doubleToLongBits(values[i][j]);
1853
+ // }
1854
+ // }
1855
+ //
1856
+ // return (int) (bits ^ (bits >> 32));
1857
+ // }
1858
+
1859
+ /**
1860
+ * Sets this GMatrix to the identity matrix.
1861
+ */
1862
+ public final void identity() {
1863
+ int i, j;
1864
+ for (i = 0; i < nRow; i++) {
1865
+ for (j = 0; j < nCol; j++) {
1866
+ values[i][j] = 0.0;
1867
+ }
1868
+ }
1869
+
1870
+ int l;
1871
+ if (nRow < nCol) {
1872
+ l = nRow;
1873
+ } else {
1874
+ l = nCol;
1875
+ }
1876
+
1877
+ for (i = 0; i < l; i++) {
1878
+ values[i][i] = 1.0;
1879
+ }
1880
+ }
1881
+
1882
+ /**
1883
+ * Subtracts this matrix from the identity matrix and puts the values back
1884
+ * into this (this = I - this).
1885
+ */
1886
+ public final void identityMinus() {
1887
+ int i, j;
1888
+
1889
+ for (i = 0; i < nRow; i++) {
1890
+ for (j = 0; j < nCol; j++) {
1891
+ values[i][j] = -values[i][j];
1892
+ }
1893
+ }
1894
+
1895
+ int l;
1896
+ if (nRow < nCol) {
1897
+ l = nRow;
1898
+ } else {
1899
+ l = nCol;
1900
+ }
1901
+
1902
+ for (i = 0; i < l; i++) {
1903
+ values[i][i] += 1.0;
1904
+ }
1905
+ }
1906
+
1907
+ /**
1908
+ * Inverts this matrix in place.
1909
+ */
1910
+ public final void invert() {
1911
+ invertGeneral(this);
1912
+ }
1913
+
1914
+ /**
1915
+ * Inverts matrix m1 and places the new values into this matrix. Matrix m1
1916
+ * is not modified.
1917
+ *
1918
+ * @param m1 the matrix to be inverted
1919
+ */
1920
+ public final void invert(GMatrix m1) {
1921
+ invertGeneral(m1);
1922
+ }
1923
+
1924
+ /**
1925
+ * General invert routine. Inverts m1 and places the result in "this". Note
1926
+ * that this routine handles both the "this" version and the non-"this"
1927
+ * version.
1928
+ *
1929
+ * Also note that since this routine is slow anyway, we won't worry about
1930
+ * allocating a little bit of garbage.
1931
+ */
1932
+ final void invertGeneral(GMatrix m1) {
1933
+ int size = m1.nRow * m1.nCol;
1934
+ double temp[] = new double[size];
1935
+ double result[] = new double[size];
1936
+ int row_perm[] = new int[m1.nRow];
1937
+ int[] even_row_exchange = new int[1];
1938
+ int i, j;
1939
+
1940
+ // Use LU decomposition and backsubstitution code specifically
1941
+ // for floating-point nxn matrices.
1942
+ if (m1.nRow != m1.nCol) {
1943
+ // Matrix is either under or over determined
1944
+ throw new MatrixSizeException();
1945
+ }
1946
+
1947
+ // Copy source matrix to temp
1948
+ for (i = 0; i < nRow; i++) {
1949
+ for (j = 0; j < nCol; j++) {
1950
+ temp[i * nCol + j] = m1.values[i][j];
1951
+ }
1952
+ }
1953
+
1954
+ // Calculate LU decomposition: Is the matrix singular?
1955
+ if (!decomposeLU(m1.nRow, temp, row_perm, even_row_exchange)) {
1956
+ // Matrix has no inverse
1957
+ throw new SingularMatrixException();
1958
+ }
1959
+
1960
+ // Perform back substitution on the identity matrix
1961
+ for (i = 0; i < size; i++) {
1962
+ result[i] = 0.0;
1963
+ }
1964
+
1965
+ for (i = 0; i < nCol; i++) {
1966
+ result[i + i * nCol] = 1.0;
1967
+ }
1968
+
1969
+ backSubstituteLU(m1.nRow, temp, row_perm, result);
1970
+
1971
+ for (i = 0; i < nRow; i++) {
1972
+ for (j = 0; j < nCol; j++) {
1973
+ values[i][j] = result[i * nCol + j];
1974
+ }
1975
+ }
1976
+ }
1977
+
1978
+ /**
1979
+ * Sets the value of this matrix to the result of multiplying itself with
1980
+ * matrix m1 (this = this * m1).
1981
+ *
1982
+ * @param m1 the other matrix
1983
+ */
1984
+ public final void mul(GMatrix m1) {
1985
+ int i, j, k;
1986
+
1987
+ if (nCol != m1.nRow || nCol != m1.nCol) {
1988
+ throw new MatrixSizeException();
1989
+ }
1990
+
1991
+ double[][] tmp = new double[nRow][nCol];
1992
+
1993
+ for (i = 0; i < nRow; i++) {
1994
+ for (j = 0; j < nCol; j++) {
1995
+ tmp[i][j] = 0.0;
1996
+ for (k = 0; k < nCol; k++) {
1997
+ tmp[i][j] += values[i][k] * m1.values[k][j];
1998
+ }
1999
+ }
2000
+ }
2001
+
2002
+ values = tmp;
2003
+ }
2004
+
2005
+ /**
2006
+ * Sets the value of this matrix to the result of multiplying the two
2007
+ * argument matrices together (this = m1 * m2).
2008
+ *
2009
+ * @param m1 the first matrix
2010
+ * @param m2 the second matrix
2011
+ */
2012
+ public final void mul(GMatrix m1, GMatrix m2) {
2013
+ int i, j, k;
2014
+
2015
+ if (m1.nCol != m2.nRow || nRow != m1.nRow || nCol != m2.nCol) {
2016
+ throw new MatrixSizeException();
2017
+ }
2018
+
2019
+ double[][] tmp = new double[nRow][nCol];
2020
+
2021
+ for (i = 0; i < m1.nRow; i++) {
2022
+ for (j = 0; j < m2.nCol; j++) {
2023
+ tmp[i][j] = 0.0;
2024
+ for (k = 0; k < m1.nCol; k++) {
2025
+ tmp[i][j] += m1.values[i][k] * m2.values[k][j];
2026
+ }
2027
+ }
2028
+ }
2029
+
2030
+ values = tmp;
2031
+ }
2032
+
2033
+ /**
2034
+ * Computes the outer product of the two vectors; multiplies the the first
2035
+ * vector by the transpose of the second vector and places the matrix result
2036
+ * into this matrix. This matrix must be be as big or bigger than
2037
+ * getSize(v1)xgetSize(v2).
2038
+ *
2039
+ * @param v1 the first vector, treated as a row vector
2040
+ * @param v2 the second vector, treated as a column vector
2041
+ */
2042
+ public final void mul(GVector v1, GVector v2) {
2043
+ int i, j;
2044
+
2045
+ if (nRow < v1.size()) {
2046
+ throw new MatrixSizeException();
2047
+ }
2048
+
2049
+ if (nCol < v2.size()) {
2050
+ throw new MatrixSizeException();
2051
+ }
2052
+
2053
+ for (i = 0; i < v1.size(); i++) {
2054
+ for (j = 0; j < v2.size(); j++) {
2055
+ values[i][j] = v1.values[i] * v2.values[j];
2056
+ }
2057
+ }
2058
+ }
2059
+
2060
+ /**
2061
+ * Multiplies the transpose of matrix m1 times the transpose of matrix m2,
2062
+ * and places the result into this.
2063
+ *
2064
+ * @param m1 The matrix on the left hand side of the multiplication
2065
+ * @param m2 The matrix on the right hand side of the multiplication
2066
+ */
2067
+ public final void mulTransposeBoth(GMatrix m1, GMatrix m2) {
2068
+ int i, j, k;
2069
+
2070
+ if (m1.nRow != m2.nCol || nRow != m1.nCol || nCol != m2.nRow) {
2071
+ throw new MatrixSizeException();
2072
+ }
2073
+
2074
+ if (m1 == this || m2 == this) {
2075
+ double[][] tmp = new double[nRow][nCol];
2076
+ for (i = 0; i < nRow; i++) {
2077
+ for (j = 0; j < nCol; j++) {
2078
+ tmp[i][j] = 0.0;
2079
+ for (k = 0; k < m1.nRow; k++) {
2080
+ tmp[i][j] += m1.values[k][i] * m2.values[j][k];
2081
+ }
2082
+ }
2083
+ }
2084
+ values = tmp;
2085
+ } else {
2086
+ for (i = 0; i < nRow; i++) {
2087
+ for (j = 0; j < nCol; j++) {
2088
+ values[i][j] = 0.0;
2089
+ for (k = 0; k < m1.nRow; k++) {
2090
+ values[i][j] += m1.values[k][i] * m2.values[j][k];
2091
+ }
2092
+ }
2093
+ }
2094
+ }
2095
+ }
2096
+
2097
+ /**
2098
+ * Multiplies the transpose of matrix m1 times matrix m2, and places the
2099
+ * result into this.
2100
+ *
2101
+ * @param m1 The matrix on the left hand side of the multiplication
2102
+ * @param m2 The matrix on the right hand side of the multiplication
2103
+ */
2104
+ public final void mulTransposeLeft(GMatrix m1, GMatrix m2) {
2105
+ int i, j, k;
2106
+
2107
+ if (m1.nRow != m2.nRow || nCol != m2.nCol || nRow != m1.nCol) {
2108
+ throw new MatrixSizeException();
2109
+ }
2110
+
2111
+ if (m1 == this || m2 == this) {
2112
+ double[][] tmp = new double[nRow][nCol];
2113
+ for (i = 0; i < nRow; i++) {
2114
+ for (j = 0; j < nCol; j++) {
2115
+ tmp[i][j] = 0.0;
2116
+ for (k = 0; k < m1.nRow; k++) {
2117
+ tmp[i][j] += m1.values[k][i] * m2.values[k][j];
2118
+ }
2119
+ }
2120
+ }
2121
+ values = tmp;
2122
+ } else {
2123
+ for (i = 0; i < nRow; i++) {
2124
+ for (j = 0; j < nCol; j++) {
2125
+ values[i][j] = 0.0;
2126
+ for (k = 0; k < m1.nRow; k++) {
2127
+ values[i][j] += m1.values[k][i] * m2.values[k][j];
2128
+ }
2129
+ }
2130
+ }
2131
+ }
2132
+ }
2133
+
2134
+ /**
2135
+ * Multiplies matrix m1 times the transpose of matrix m2, and places the
2136
+ * result into this.
2137
+ *
2138
+ * @param m1 The matrix on the left hand side of the multiplication
2139
+ * @param m2 The matrix on the right hand side of the multiplication
2140
+ */
2141
+ public final void mulTransposeRight(GMatrix m1, GMatrix m2) {
2142
+ int i, j, k;
2143
+
2144
+ if (m1.nCol != m2.nCol || nCol != m2.nRow || nRow != m1.nRow) {
2145
+ throw new MatrixSizeException();
2146
+ }
2147
+
2148
+ if (m1 == this || m2 == this) {
2149
+ double[][] tmp = new double[nRow][nCol];
2150
+ for (i = 0; i < nRow; i++) {
2151
+ for (j = 0; j < nCol; j++) {
2152
+ tmp[i][j] = 0.0;
2153
+ for (k = 0; k < m1.nCol; k++) {
2154
+ tmp[i][j] += m1.values[i][k] * m2.values[j][k];
2155
+ }
2156
+ }
2157
+ }
2158
+ values = tmp;
2159
+ } else {
2160
+ for (i = 0; i < nRow; i++) {
2161
+ for (j = 0; j < nCol; j++) {
2162
+ values[i][j] = 0.0;
2163
+ for (k = 0; k < m1.nCol; k++) {
2164
+ values[i][j] += m1.values[i][k] * m2.values[j][k];
2165
+ }
2166
+ }
2167
+ }
2168
+ }
2169
+
2170
+ }
2171
+
2172
+ /**
2173
+ * Negates the value of this matrix: this = -this.
2174
+ */
2175
+ public final void negate() {
2176
+ int i, j;
2177
+ for (i = 0; i < nRow; i++) {
2178
+ for (j = 0; j < nCol; j++) {
2179
+ values[i][j] = -values[i][j];
2180
+ }
2181
+ }
2182
+ }
2183
+
2184
+ /**
2185
+ * Sets the value of this matrix equal to the negation of of the GMatrix
2186
+ * parameter.
2187
+ *
2188
+ * @param m1 The source matrix
2189
+ */
2190
+ public final void negate(GMatrix m1) {
2191
+ int i, j;
2192
+ if (nRow != m1.nRow || nCol != m1.nCol) {
2193
+ throw new MatrixSizeException();
2194
+ }
2195
+
2196
+ for (i = 0; i < nRow; i++) {
2197
+ for (j = 0; j < nCol; j++) {
2198
+ values[i][j] = -m1.values[i][j];
2199
+ }
2200
+ }
2201
+ }
2202
+
2203
+ /**
2204
+ * Sets the value of this matrix to the values found in the array parameter.
2205
+ * The values are copied in one row at a time, in row major fashion. The
2206
+ * array should be at least equal in length to the number of matrix rows
2207
+ * times the number of matrix columns in this matrix.
2208
+ *
2209
+ * @param matrix the row major source array
2210
+ */
2211
+ public final void set(double[] matrix) {
2212
+ int i, j;
2213
+
2214
+ for (i = 0; i < nRow; i++) {
2215
+ for (j = 0; j < nCol; j++) {
2216
+ values[i][j] = matrix[nCol * i + j];
2217
+ }
2218
+ }
2219
+ }
2220
+
2221
+ /**
2222
+ * Sets the value of this matrix to the values found in matrix m1.
2223
+ *
2224
+ * @param m1 the source matrix
2225
+ */
2226
+ public final void set(GMatrix m1) {
2227
+ int i, j;
2228
+
2229
+ if (nRow < m1.nRow || nCol < m1.nCol) {
2230
+ nRow = m1.nRow;
2231
+ nCol = m1.nCol;
2232
+ values = new double[nRow][nCol];
2233
+ }
2234
+
2235
+ for (i = 0; i < Math.min(nRow, m1.nRow); i++) {
2236
+ for (j = 0; j < Math.min(nCol, m1.nCol); j++) {
2237
+ values[i][j] = m1.values[i][j];
2238
+ }
2239
+ }
2240
+
2241
+ for (i = m1.nRow; i < nRow; i++) { // pad rest or matrix with zeros
2242
+ for (j = m1.nCol; j < nCol; j++) {
2243
+ values[i][j] = 0.0;
2244
+ }
2245
+ }
2246
+ }
2247
+
2248
+ /**
2249
+ * Sets the value of this matrix to that of the Matrix3d provided.
2250
+ *
2251
+ * @param m1 the matrix
2252
+ */
2253
+ public final void set(Matrix3d m1) {
2254
+ if (nRow < 3 || nCol < 3) {
2255
+ values = new double[3][3];
2256
+ nRow = 3;
2257
+ nCol = 3;
2258
+ }
2259
+
2260
+ values[0][0] = m1.m00;
2261
+ values[0][1] = m1.m01;
2262
+ values[0][2] = m1.m02;
2263
+
2264
+ values[1][0] = m1.m10;
2265
+ values[1][1] = m1.m11;
2266
+ values[1][2] = m1.m12;
2267
+
2268
+ values[2][0] = m1.m20;
2269
+ values[2][1] = m1.m21;
2270
+ values[2][2] = m1.m22;
2271
+
2272
+ for (int i = 3; i < nRow; i++) { // pad rest or matrix with zeros
2273
+ for (int j = 3; j < nCol; j++) {
2274
+ values[i][j] = 0.0;
2275
+ }
2276
+ }
2277
+
2278
+ }
2279
+
2280
+ /**
2281
+ * Sets the value of this matrix to that of the Matrix4f provided.
2282
+ *
2283
+ * @param m1 the matrix
2284
+ */
2285
+ public final void set(Matrix4f m1) {
2286
+ if (nRow < 4 || nCol < 4) {
2287
+ values = new double[4][4];
2288
+ nRow = 4;
2289
+ nCol = 4;
2290
+ }
2291
+
2292
+ values[0][0] = m1.m00;
2293
+ values[0][1] = m1.m01;
2294
+ values[0][2] = m1.m02;
2295
+ values[0][3] = m1.m03;
2296
+
2297
+ values[1][0] = m1.m10;
2298
+ values[1][1] = m1.m11;
2299
+ values[1][2] = m1.m12;
2300
+ values[1][3] = m1.m13;
2301
+
2302
+ values[2][0] = m1.m20;
2303
+ values[2][1] = m1.m21;
2304
+ values[2][2] = m1.m22;
2305
+ values[2][3] = m1.m23;
2306
+
2307
+ values[3][0] = m1.m30;
2308
+ values[3][1] = m1.m31;
2309
+ values[3][2] = m1.m32;
2310
+ values[3][3] = m1.m33;
2311
+
2312
+ for (int i = 4; i < nRow; i++) { // pad rest or matrix with zeros
2313
+ for (int j = 4; j < nCol; j++) {
2314
+ values[i][j] = 0.0;
2315
+ }
2316
+ }
2317
+ }
2318
+
2319
+ /**
2320
+ * Copy the values from the array into the specified column of this matrix.
2321
+ *
2322
+ * @param col the column of this matrix into which the array values will be
2323
+ * copied
2324
+ * @param array the source array
2325
+ */
2326
+ public final void setColumn(int col, double[] array) {
2327
+ for (int i = 0; i < nRow; i++) {
2328
+ values[i][col] = array[i];
2329
+ }
2330
+ }
2331
+
2332
+ /**
2333
+ * Copy the values from the vector into the specified column of this matrix.
2334
+ *
2335
+ * @param col the column of this matrix into which the array values will be
2336
+ * copied
2337
+ * @param vector the source vector
2338
+ */
2339
+ public final void setColumn(int col, GVector vector) {
2340
+ for (int i = 0; i < nRow; i++) {
2341
+ values[i][col] = vector.values[i];
2342
+ }
2343
+
2344
+ }
2345
+
2346
+ /**
2347
+ * Modifies the value at the specified row and column of this matrix.
2348
+ *
2349
+ * @param row the row number to be modified (zero indexed)
2350
+ * @param column the column number to be modified (zero indexed)
2351
+ * @param value the new matrix element value
2352
+ */
2353
+ public final void setElement(int row, int column, double value) {
2354
+ values[row][column] = value;
2355
+ }
2356
+
2357
+ /**
2358
+ * Copy the values from the array into the specified row of this matrix.
2359
+ *
2360
+ * @param row the row of this matrix into which the array values will be
2361
+ * copied.
2362
+ * @param array the source array
2363
+ */
2364
+ public final void setRow(int row, double[] array) {
2365
+ System.arraycopy(array, 0, values[row], 0, nCol);
2366
+ }
2367
+
2368
+ /**
2369
+ * Copy the values from the vector into the specified row of this matrix.
2370
+ *
2371
+ * @param row the row of this matrix into which the array values will be
2372
+ * copied
2373
+ * @param vector the source vector
2374
+ */
2375
+ public final void setRow(int row, GVector vector) {
2376
+ System.arraycopy(vector.values, 0, values[row], 0, nCol);
2377
+ }
2378
+
2379
+ /**
2380
+ * Sets this matrix to a uniform scale matrix; all of the values are reset.
2381
+ *
2382
+ * @param scale The new scale value
2383
+ */
2384
+ public final void setScale(double scale) {
2385
+ int i, j, l;
2386
+
2387
+ if (nRow < nCol) {
2388
+ l = nRow;
2389
+ } else {
2390
+ l = nCol;
2391
+ }
2392
+
2393
+ for (i = 0; i < nRow; i++) {
2394
+ for (j = 0; j < nCol; j++) {
2395
+ values[i][j] = 0.0;
2396
+ }
2397
+ }
2398
+
2399
+ for (i = 0; i < l; i++) {
2400
+ values[i][i] = scale;
2401
+ }
2402
+ }
2403
+
2404
+ /**
2405
+ * Changes the size of this matrix dynamically. If the size is increased no
2406
+ * data values will be lost. If the size is decreased, only those data
2407
+ * values whose matrix positions were eliminated will be lost.
2408
+ *
2409
+ * @param nRow number of desired rows in this matrix
2410
+ * @param nCol number of desired columns in this matrix
2411
+ */
2412
+ public final void setSize(int nRow, int nCol) {
2413
+ double[][] tmp = new double[nRow][nCol];
2414
+ int i, j, maxRow, maxCol;
2415
+
2416
+ if (this.nRow < nRow) {
2417
+ maxRow = this.nRow;
2418
+ } else {
2419
+ maxRow = nRow;
2420
+ }
2421
+
2422
+ if (this.nCol < nCol) {
2423
+ maxCol = this.nCol;
2424
+ } else {
2425
+ maxCol = nCol;
2426
+ }
2427
+
2428
+ for (i = 0; i < maxRow; i++) {
2429
+ for (j = 0; j < maxCol; j++) {
2430
+ tmp[i][j] = values[i][j];
2431
+ }
2432
+ }
2433
+
2434
+ this.nRow = nRow;
2435
+ this.nCol = nCol;
2436
+
2437
+ values = tmp;
2438
+ }
2439
+
2440
+ /**
2441
+ * Sets all the values in this matrix to zero.
2442
+ */
2443
+ public final void setZero() {
2444
+ int i, j;
2445
+ for (i = 0; i < nRow; i++) {
2446
+ for (j = 0; j < nCol; j++) {
2447
+ values[i][j] = 0.0;
2448
+ }
2449
+ }
2450
+ }
2451
+
2452
+ /**
2453
+ * Sets the value of this matrix to the matrix difference of itself and
2454
+ * matrix m1 (this = this - m1).
2455
+ *
2456
+ * @param m1 the other matrix
2457
+ */
2458
+ public final void sub(GMatrix m1) {
2459
+ int i, j;
2460
+ if (nRow != m1.nRow) {
2461
+ throw new MatrixSizeException();
2462
+ }
2463
+
2464
+ if (nCol != m1.nCol) {
2465
+ throw new MatrixSizeException();
2466
+ }
2467
+
2468
+ for (i = 0; i < nRow; i++) {
2469
+ for (j = 0; j < nCol; j++) {
2470
+ values[i][j] = values[i][j] - m1.values[i][j];
2471
+ }
2472
+ }
2473
+ }
2474
+
2475
+ /**
2476
+ * Sets the value of this matrix to the matrix difference of matrices m1 and
2477
+ * m2 (this = m1 - m2).
2478
+ *
2479
+ * @param m1 the first matrix
2480
+ * @param m2 the second matrix
2481
+ */
2482
+ public final void sub(GMatrix m1, GMatrix m2) {
2483
+ int i, j;
2484
+ if (m2.nRow != m1.nRow) {
2485
+ throw new MatrixSizeException();
2486
+ }
2487
+
2488
+ if (m2.nCol != m1.nCol) {
2489
+ throw new MatrixSizeException();
2490
+ }
2491
+
2492
+ if (nRow != m1.nRow || nCol != m1.nCol) {
2493
+ throw new MatrixSizeException();
2494
+ }
2495
+
2496
+ for (i = 0; i < nRow; i++) {
2497
+ for (j = 0; j < nCol; j++) {
2498
+ values[i][j] = m1.values[i][j] - m2.values[i][j];
2499
+ }
2500
+ }
2501
+ }
2502
+
2503
+ /**
2504
+ * Returns a string that contains the values of this GMatrix.
2505
+ *
2506
+ * @return the String representation
2507
+ */
2508
+ @Override
2509
+ public String toString() {
2510
+ StringBuilder buffer = new StringBuilder(nRow * nCol * 8);
2511
+
2512
+ int i, j;
2513
+
2514
+ for (i = 0; i < nRow; i++) {
2515
+ for (j = 0; j < nCol; j++) {
2516
+ buffer.append(values[i][j]).append(" ");
2517
+ }
2518
+ buffer.append("\n");
2519
+ }
2520
+
2521
+ return buffer.toString();
2522
+ }
2523
+
2524
+ /**
2525
+ * Returns the trace of this matrix.
2526
+ *
2527
+ * @return the trace of this matrix
2528
+ */
2529
+ public final double trace() {
2530
+ int i, l;
2531
+ double t;
2532
+
2533
+ if (nRow < nCol) {
2534
+ l = nRow;
2535
+ } else {
2536
+ l = nCol;
2537
+ }
2538
+
2539
+ t = 0.0;
2540
+ for (i = 0; i < l; i++) {
2541
+ t += values[i][i];
2542
+ }
2543
+ return t;
2544
+ }
2545
+
2546
+ /**
2547
+ * Transposes this matrix in place.
2548
+ */
2549
+ public final void transpose() {
2550
+ int i, j;
2551
+
2552
+ if (nRow != nCol) {
2553
+ double[][] tmp;
2554
+ i = nRow;
2555
+ nRow = nCol;
2556
+ nCol = i;
2557
+ tmp = new double[nRow][nCol];
2558
+ for (i = 0; i < nRow; i++) {
2559
+ for (j = 0; j < nCol; j++) {
2560
+ tmp[i][j] = values[j][i];
2561
+ }
2562
+ }
2563
+ values = tmp;
2564
+ } else {
2565
+ double swap;
2566
+ for (i = 0; i < nRow; i++) {
2567
+ for (j = 0; j < i; j++) {
2568
+ swap = values[i][j];
2569
+ values[i][j] = values[j][i];
2570
+ values[j][i] = swap;
2571
+ }
2572
+ }
2573
+ }
2574
+ }
2575
+
2576
+ /**
2577
+ * Places the matrix values of the transpose of matrix m1 into this matrix.
2578
+ *
2579
+ * @param m1 the matrix to be transposed (but not modified)
2580
+ */
2581
+ public final void transpose(GMatrix m1) {
2582
+ int i, j;
2583
+
2584
+ if (nRow != m1.nCol || nCol != m1.nRow) {
2585
+ throw new MatrixSizeException();
2586
+ }
2587
+
2588
+ if (m1 != this) {
2589
+ for (i = 0; i < nRow; i++) {
2590
+ for (j = 0; j < nCol; j++) {
2591
+ values[i][j] = m1.values[j][i];
2592
+ }
2593
+ }
2594
+ } else {
2595
+ transpose();
2596
+ }
2597
+ }
2598
+
2599
+ }