diff options
author | Jeff Ames | 2007-11-11 09:19:21 +0000 |
---|---|---|
committer | Jeff Ames | 2007-11-11 09:19:21 +0000 |
commit | db174dfa2061ce35b657cd8f119f1176b53c6207 (patch) | |
tree | 7ff889f817ab0ebac5a90c6adbecf4a263239a73 /OpenSim/Region/Physics/Meshing/HelperTypes.cs | |
parent | fixed chatting while sitting (diff) | |
download | opensim-SC_OLD-db174dfa2061ce35b657cd8f119f1176b53c6207.zip opensim-SC_OLD-db174dfa2061ce35b657cd8f119f1176b53c6207.tar.gz opensim-SC_OLD-db174dfa2061ce35b657cd8f119f1176b53c6207.tar.bz2 opensim-SC_OLD-db174dfa2061ce35b657cd8f119f1176b53c6207.tar.xz |
set svn:eol-style
Diffstat (limited to 'OpenSim/Region/Physics/Meshing/HelperTypes.cs')
-rw-r--r-- | OpenSim/Region/Physics/Meshing/HelperTypes.cs | 610 |
1 files changed, 305 insertions, 305 deletions
diff --git a/OpenSim/Region/Physics/Meshing/HelperTypes.cs b/OpenSim/Region/Physics/Meshing/HelperTypes.cs index 9e75826..be82c32 100644 --- a/OpenSim/Region/Physics/Meshing/HelperTypes.cs +++ b/OpenSim/Region/Physics/Meshing/HelperTypes.cs | |||
@@ -1,306 +1,306 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSim Project nor the | 12 | * * Neither the name of the OpenSim Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | using System; | 29 | using System; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Diagnostics; | 31 | using System.Diagnostics; |
32 | using System.Globalization; | 32 | using System.Globalization; |
33 | using OpenSim.Framework.Console; | 33 | using OpenSim.Framework.Console; |
34 | using OpenSim.Region.Physics.Manager; | 34 | using OpenSim.Region.Physics.Manager; |
35 | 35 | ||
36 | using OpenSim.Region.Physics.Meshing; | 36 | using OpenSim.Region.Physics.Meshing; |
37 | 37 | ||
38 | public class Vertex : PhysicsVector, IComparable<Vertex> | 38 | public class Vertex : PhysicsVector, IComparable<Vertex> |
39 | { | 39 | { |
40 | public Vertex(float x, float y, float z) | 40 | public Vertex(float x, float y, float z) |
41 | : base(x, y, z) | 41 | : base(x, y, z) |
42 | { | 42 | { |
43 | } | 43 | } |
44 | 44 | ||
45 | public Vertex(PhysicsVector v) | 45 | public Vertex(PhysicsVector v) |
46 | : base(v.X, v.Y, v.Z) | 46 | : base(v.X, v.Y, v.Z) |
47 | { | 47 | { |
48 | } | 48 | } |
49 | 49 | ||
50 | public Vertex Clone() | 50 | public Vertex Clone() |
51 | { | 51 | { |
52 | return new Vertex(X, Y, Z); | 52 | return new Vertex(X, Y, Z); |
53 | } | 53 | } |
54 | 54 | ||
55 | public static Vertex FromAngle(double angle) | 55 | public static Vertex FromAngle(double angle) |
56 | { | 56 | { |
57 | return new Vertex((float)Math.Cos(angle), (float)Math.Sin(angle), 0.0f); | 57 | return new Vertex((float)Math.Cos(angle), (float)Math.Sin(angle), 0.0f); |
58 | } | 58 | } |
59 | 59 | ||
60 | 60 | ||
61 | public virtual bool Equals(Vertex v, float tolerance) | 61 | public virtual bool Equals(Vertex v, float tolerance) |
62 | { | 62 | { |
63 | PhysicsVector diff = this - v; | 63 | PhysicsVector diff = this - v; |
64 | float d = diff.length(); | 64 | float d = diff.length(); |
65 | if (d < tolerance) | 65 | if (d < tolerance) |
66 | return true; | 66 | return true; |
67 | 67 | ||
68 | return false; | 68 | return false; |
69 | } | 69 | } |
70 | 70 | ||
71 | 71 | ||
72 | public int CompareTo(Vertex other) | 72 | public int CompareTo(Vertex other) |
73 | { | 73 | { |
74 | if (X < other.X) | 74 | if (X < other.X) |
75 | return -1; | 75 | return -1; |
76 | 76 | ||
77 | if (X > other.X) | 77 | if (X > other.X) |
78 | return 1; | 78 | return 1; |
79 | 79 | ||
80 | if (Y < other.Y) | 80 | if (Y < other.Y) |
81 | return -1; | 81 | return -1; |
82 | 82 | ||
83 | if (Y > other.Y) | 83 | if (Y > other.Y) |
84 | return 1; | 84 | return 1; |
85 | 85 | ||
86 | if (Z < other.Z) | 86 | if (Z < other.Z) |
87 | return -1; | 87 | return -1; |
88 | 88 | ||
89 | if (Z > other.Z) | 89 | if (Z > other.Z) |
90 | return 1; | 90 | return 1; |
91 | 91 | ||
92 | return 0; | 92 | return 0; |
93 | } | 93 | } |
94 | 94 | ||
95 | public static bool operator >(Vertex me, Vertex other) | 95 | public static bool operator >(Vertex me, Vertex other) |
96 | { | 96 | { |
97 | return me.CompareTo(other) > 0; | 97 | return me.CompareTo(other) > 0; |
98 | } | 98 | } |
99 | 99 | ||
100 | public static bool operator <(Vertex me, Vertex other) | 100 | public static bool operator <(Vertex me, Vertex other) |
101 | { | 101 | { |
102 | return me.CompareTo(other) < 0; | 102 | return me.CompareTo(other) < 0; |
103 | } | 103 | } |
104 | public String ToRaw() | 104 | public String ToRaw() |
105 | { | 105 | { |
106 | // Why this stuff with the number formatter? | 106 | // Why this stuff with the number formatter? |
107 | // Well, the raw format uses the english/US notation of numbers | 107 | // Well, the raw format uses the english/US notation of numbers |
108 | // where the "," separates groups of 1000 while the "." marks the border between 1 and 10E-1. | 108 | // where the "," separates groups of 1000 while the "." marks the border between 1 and 10E-1. |
109 | // The german notation uses these characters exactly vice versa! | 109 | // The german notation uses these characters exactly vice versa! |
110 | // The Float.ToString() routine is a localized one, giving different results depending on the country | 110 | // The Float.ToString() routine is a localized one, giving different results depending on the country |
111 | // settings your machine works with. Unusable for a machine readable file format :-( | 111 | // settings your machine works with. Unusable for a machine readable file format :-( |
112 | NumberFormatInfo nfi = new NumberFormatInfo(); | 112 | NumberFormatInfo nfi = new NumberFormatInfo(); |
113 | nfi.NumberDecimalSeparator = "."; | 113 | nfi.NumberDecimalSeparator = "."; |
114 | nfi.NumberDecimalDigits = 3; | 114 | nfi.NumberDecimalDigits = 3; |
115 | 115 | ||
116 | String s1 = X.ToString("N2", nfi) + " " + Y.ToString("N2", nfi) + " " + Z.ToString("N2", nfi); | 116 | String s1 = X.ToString("N2", nfi) + " " + Y.ToString("N2", nfi) + " " + Z.ToString("N2", nfi); |
117 | 117 | ||
118 | return s1; | 118 | return s1; |
119 | } | 119 | } |
120 | 120 | ||
121 | } | 121 | } |
122 | 122 | ||
123 | public class Triangle | 123 | public class Triangle |
124 | { | 124 | { |
125 | public Vertex v1; | 125 | public Vertex v1; |
126 | public Vertex v2; | 126 | public Vertex v2; |
127 | public Vertex v3; | 127 | public Vertex v3; |
128 | 128 | ||
129 | private float radius_square; | 129 | private float radius_square; |
130 | private float cx; | 130 | private float cx; |
131 | private float cy; | 131 | private float cy; |
132 | 132 | ||
133 | public Triangle(Vertex _v1, Vertex _v2, Vertex _v3) | 133 | public Triangle(Vertex _v1, Vertex _v2, Vertex _v3) |
134 | { | 134 | { |
135 | v1 = _v1; | 135 | v1 = _v1; |
136 | v2 = _v2; | 136 | v2 = _v2; |
137 | v3 = _v3; | 137 | v3 = _v3; |
138 | 138 | ||
139 | CalcCircle(); | 139 | CalcCircle(); |
140 | } | 140 | } |
141 | 141 | ||
142 | public bool isInCircle(float x, float y) | 142 | public bool isInCircle(float x, float y) |
143 | { | 143 | { |
144 | float dx, dy; | 144 | float dx, dy; |
145 | float dd; | 145 | float dd; |
146 | 146 | ||
147 | dx = x - cx; | 147 | dx = x - cx; |
148 | dy = y - cy; | 148 | dy = y - cy; |
149 | 149 | ||
150 | dd = dx*dx + dy*dy; | 150 | dd = dx*dx + dy*dy; |
151 | if (dd < radius_square) | 151 | if (dd < radius_square) |
152 | return true; | 152 | return true; |
153 | else | 153 | else |
154 | return false; | 154 | return false; |
155 | } | 155 | } |
156 | 156 | ||
157 | public bool isDegraded() | 157 | public bool isDegraded() |
158 | { | 158 | { |
159 | // This means, the vertices of this triangle are somewhat strange. | 159 | // This means, the vertices of this triangle are somewhat strange. |
160 | // They either line up or at least two of them are identical | 160 | // They either line up or at least two of them are identical |
161 | return (radius_square == 0.0); | 161 | return (radius_square == 0.0); |
162 | } | 162 | } |
163 | 163 | ||
164 | private void CalcCircle() | 164 | private void CalcCircle() |
165 | { | 165 | { |
166 | // Calculate the center and the radius of a circle given by three points p1, p2, p3 | 166 | // Calculate the center and the radius of a circle given by three points p1, p2, p3 |
167 | // It is assumed, that the triangles vertices are already set correctly | 167 | // It is assumed, that the triangles vertices are already set correctly |
168 | double p1x, p2x, p1y, p2y, p3x, p3y; | 168 | double p1x, p2x, p1y, p2y, p3x, p3y; |
169 | 169 | ||
170 | // Deviation of this routine: | 170 | // Deviation of this routine: |
171 | // A circle has the general equation (M-p)^2=r^2, where M and p are vectors | 171 | // A circle has the general equation (M-p)^2=r^2, where M and p are vectors |
172 | // this gives us three equations f(p)=r^2, each for one point p1, p2, p3 | 172 | // this gives us three equations f(p)=r^2, each for one point p1, p2, p3 |
173 | // putting respectively two equations together gives two equations | 173 | // putting respectively two equations together gives two equations |
174 | // f(p1)=f(p2) and f(p1)=f(p3) | 174 | // f(p1)=f(p2) and f(p1)=f(p3) |
175 | // bringing all constant terms to one side brings them to the form | 175 | // bringing all constant terms to one side brings them to the form |
176 | // M*v1=c1 resp.M*v2=c2 where v1=(p1-p2) and v2=(p1-p3) (still vectors) | 176 | // M*v1=c1 resp.M*v2=c2 where v1=(p1-p2) and v2=(p1-p3) (still vectors) |
177 | // and c1, c2 are scalars (Naming conventions like the variables below) | 177 | // and c1, c2 are scalars (Naming conventions like the variables below) |
178 | // Now using the equations that are formed by the components of the vectors | 178 | // Now using the equations that are formed by the components of the vectors |
179 | // and isolate Mx lets you make one equation that only holds My | 179 | // and isolate Mx lets you make one equation that only holds My |
180 | // The rest is straight forward and eaasy :-) | 180 | // The rest is straight forward and eaasy :-) |
181 | // | 181 | // |
182 | 182 | ||
183 | /* helping variables for temporary results */ | 183 | /* helping variables for temporary results */ |
184 | double c1, c2; | 184 | double c1, c2; |
185 | double v1x, v1y, v2x, v2y; | 185 | double v1x, v1y, v2x, v2y; |
186 | 186 | ||
187 | double z, n; | 187 | double z, n; |
188 | 188 | ||
189 | double rx, ry; | 189 | double rx, ry; |
190 | 190 | ||
191 | // Readout the three points, the triangle consists of | 191 | // Readout the three points, the triangle consists of |
192 | p1x = v1.X; | 192 | p1x = v1.X; |
193 | p1y = v1.Y; | 193 | p1y = v1.Y; |
194 | 194 | ||
195 | p2x = v2.X; | 195 | p2x = v2.X; |
196 | p2y = v2.Y; | 196 | p2y = v2.Y; |
197 | 197 | ||
198 | p3x = v3.X; | 198 | p3x = v3.X; |
199 | p3y = v3.Y; | 199 | p3y = v3.Y; |
200 | 200 | ||
201 | /* calc helping values first */ | 201 | /* calc helping values first */ |
202 | c1 = (p1x*p1x + p1y*p1y - p2x*p2x - p2y*p2y)/2; | 202 | c1 = (p1x*p1x + p1y*p1y - p2x*p2x - p2y*p2y)/2; |
203 | c2 = (p1x*p1x + p1y*p1y - p3x*p3x - p3y*p3y)/2; | 203 | c2 = (p1x*p1x + p1y*p1y - p3x*p3x - p3y*p3y)/2; |
204 | 204 | ||
205 | v1x = p1x - p2x; | 205 | v1x = p1x - p2x; |
206 | v1y = p1y - p2y; | 206 | v1y = p1y - p2y; |
207 | 207 | ||
208 | v2x = p1x - p3x; | 208 | v2x = p1x - p3x; |
209 | v2y = p1y - p3y; | 209 | v2y = p1y - p3y; |
210 | 210 | ||
211 | z = (c1*v2x - c2*v1x); | 211 | z = (c1*v2x - c2*v1x); |
212 | n = (v1y*v2x - v2y*v1x); | 212 | n = (v1y*v2x - v2y*v1x); |
213 | 213 | ||
214 | if (n == 0.0) // This is no triangle, i.e there are (at least) two points at the same location | 214 | if (n == 0.0) // This is no triangle, i.e there are (at least) two points at the same location |
215 | { | 215 | { |
216 | radius_square = 0.0f; | 216 | radius_square = 0.0f; |
217 | return; | 217 | return; |
218 | } | 218 | } |
219 | 219 | ||
220 | cy = (float) (z/n); | 220 | cy = (float) (z/n); |
221 | 221 | ||
222 | if (v2x != 0.0) | 222 | if (v2x != 0.0) |
223 | { | 223 | { |
224 | cx = (float) ((c2 - v2y*cy)/v2x); | 224 | cx = (float) ((c2 - v2y*cy)/v2x); |
225 | } | 225 | } |
226 | else if (v1x != 0.0) | 226 | else if (v1x != 0.0) |
227 | { | 227 | { |
228 | cx = (float) ((c1 - v1y*cy)/v1x); | 228 | cx = (float) ((c1 - v1y*cy)/v1x); |
229 | } | 229 | } |
230 | else | 230 | else |
231 | { | 231 | { |
232 | Debug.Assert(false, "Malformed triangle"); /* Both terms zero means nothing good */ | 232 | Debug.Assert(false, "Malformed triangle"); /* Both terms zero means nothing good */ |
233 | } | 233 | } |
234 | 234 | ||
235 | rx = (p1x - cx); | 235 | rx = (p1x - cx); |
236 | ry = (p1y - cy); | 236 | ry = (p1y - cy); |
237 | 237 | ||
238 | radius_square = (float) (rx*rx + ry*ry); | 238 | radius_square = (float) (rx*rx + ry*ry); |
239 | } | 239 | } |
240 | 240 | ||
241 | public List<Simplex> GetSimplices() | 241 | public List<Simplex> GetSimplices() |
242 | { | 242 | { |
243 | List<Simplex> result = new List<Simplex>(); | 243 | List<Simplex> result = new List<Simplex>(); |
244 | Simplex s1 = new Simplex(v1, v2); | 244 | Simplex s1 = new Simplex(v1, v2); |
245 | Simplex s2 = new Simplex(v2, v3); | 245 | Simplex s2 = new Simplex(v2, v3); |
246 | Simplex s3 = new Simplex(v3, v1); | 246 | Simplex s3 = new Simplex(v3, v1); |
247 | 247 | ||
248 | result.Add(s1); | 248 | result.Add(s1); |
249 | result.Add(s2); | 249 | result.Add(s2); |
250 | result.Add(s3); | 250 | result.Add(s3); |
251 | 251 | ||
252 | return result; | 252 | return result; |
253 | } | 253 | } |
254 | 254 | ||
255 | public override String ToString() | 255 | public override String ToString() |
256 | { | 256 | { |
257 | NumberFormatInfo nfi = new NumberFormatInfo(); | 257 | NumberFormatInfo nfi = new NumberFormatInfo(); |
258 | nfi.CurrencyDecimalDigits = 2; | 258 | nfi.CurrencyDecimalDigits = 2; |
259 | nfi.CurrencyDecimalSeparator = "."; | 259 | nfi.CurrencyDecimalSeparator = "."; |
260 | 260 | ||
261 | String s1 = "<" + v1.X.ToString(nfi) + "," + v1.Y.ToString(nfi) + "," + v1.Z.ToString(nfi) + ">"; | 261 | String s1 = "<" + v1.X.ToString(nfi) + "," + v1.Y.ToString(nfi) + "," + v1.Z.ToString(nfi) + ">"; |
262 | String s2 = "<" + v2.X.ToString(nfi) + "," + v2.Y.ToString(nfi) + "," + v2.Z.ToString(nfi) + ">"; | 262 | String s2 = "<" + v2.X.ToString(nfi) + "," + v2.Y.ToString(nfi) + "," + v2.Z.ToString(nfi) + ">"; |
263 | String s3 = "<" + v3.X.ToString(nfi) + "," + v3.Y.ToString(nfi) + "," + v3.Z.ToString(nfi) + ">"; | 263 | String s3 = "<" + v3.X.ToString(nfi) + "," + v3.Y.ToString(nfi) + "," + v3.Z.ToString(nfi) + ">"; |
264 | 264 | ||
265 | return s1 + ";" + s2 + ";" + s3; | 265 | return s1 + ";" + s2 + ";" + s3; |
266 | } | 266 | } |
267 | 267 | ||
268 | public PhysicsVector getNormal() | 268 | public PhysicsVector getNormal() |
269 | { | 269 | { |
270 | // Vertices | 270 | // Vertices |
271 | 271 | ||
272 | // Vectors for edges | 272 | // Vectors for edges |
273 | PhysicsVector e1; | 273 | PhysicsVector e1; |
274 | PhysicsVector e2; | 274 | PhysicsVector e2; |
275 | 275 | ||
276 | e1 = new PhysicsVector(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); | 276 | e1 = new PhysicsVector(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z); |
277 | e2 = new PhysicsVector(v1.X - v3.X, v1.Y - v3.Y, v1.Z - v3.Z); | 277 | e2 = new PhysicsVector(v1.X - v3.X, v1.Y - v3.Y, v1.Z - v3.Z); |
278 | 278 | ||
279 | // Cross product for normal | 279 | // Cross product for normal |
280 | PhysicsVector n = PhysicsVector.cross(e1, e2); | 280 | PhysicsVector n = PhysicsVector.cross(e1, e2); |
281 | 281 | ||
282 | // Length | 282 | // Length |
283 | float l = n.length(); | 283 | float l = n.length(); |
284 | 284 | ||
285 | // Normalized "normal" | 285 | // Normalized "normal" |
286 | n = n / l; | 286 | n = n / l; |
287 | 287 | ||
288 | return n; | 288 | return n; |
289 | } | 289 | } |
290 | 290 | ||
291 | public void invertNormal() | 291 | public void invertNormal() |
292 | { | 292 | { |
293 | Vertex vt; | 293 | Vertex vt; |
294 | vt = v1; | 294 | vt = v1; |
295 | v1 = v2; | 295 | v1 = v2; |
296 | v2 = vt; | 296 | v2 = vt; |
297 | } | 297 | } |
298 | 298 | ||
299 | // Dumps a triangle in the "raw faces" format, blender can import. This is for visualisation and | 299 | // Dumps a triangle in the "raw faces" format, blender can import. This is for visualisation and |
300 | // debugging purposes | 300 | // debugging purposes |
301 | public String ToStringRaw() | 301 | public String ToStringRaw() |
302 | { | 302 | { |
303 | String output = v1.ToRaw() + " " + v2.ToRaw() + " " +v3.ToRaw(); | 303 | String output = v1.ToRaw() + " " + v2.ToRaw() + " " +v3.ToRaw(); |
304 | return output; | 304 | return output; |
305 | } | 305 | } |
306 | } \ No newline at end of file | 306 | } \ No newline at end of file |