diff options
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Extruder.cs | 211 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/HelperTypes.cs | 36 | ||||
-rw-r--r-- | OpenSim/Region/Physics/Meshing/Meshmerizer.cs | 450 | ||||
-rw-r--r-- | OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 19 |
4 files changed, 669 insertions, 47 deletions
diff --git a/OpenSim/Region/Physics/Meshing/Extruder.cs b/OpenSim/Region/Physics/Meshing/Extruder.cs index c7dcf33..480ffda 100644 --- a/OpenSim/Region/Physics/Meshing/Extruder.cs +++ b/OpenSim/Region/Physics/Meshing/Extruder.cs | |||
@@ -47,6 +47,21 @@ namespace OpenSim.Region.Physics.Meshing | |||
47 | public float twistTop = 0; | 47 | public float twistTop = 0; |
48 | public float twistBot = 0; | 48 | public float twistBot = 0; |
49 | public float twistMid = 0; | 49 | public float twistMid = 0; |
50 | public float pathScaleX = 1.0f; | ||
51 | public float pathScaleY = 0.5f; | ||
52 | public float skew = 0.0f; | ||
53 | public float radius = 0.0f; | ||
54 | public float revolutions = 1.0f; | ||
55 | |||
56 | public float pathCutBegin = 0.0f; | ||
57 | public float pathCutEnd = 1.0f; | ||
58 | |||
59 | public ushort pathBegin = 0; | ||
60 | public ushort pathEnd = 0; | ||
61 | |||
62 | public float pathTaperX = 0.0f; | ||
63 | public float pathTaperY = 0.0f; | ||
64 | |||
50 | 65 | ||
51 | public Mesh Extrude(Mesh m) | 66 | public Mesh Extrude(Mesh m) |
52 | { | 67 | { |
@@ -230,5 +245,201 @@ namespace OpenSim.Region.Physics.Meshing | |||
230 | } | 245 | } |
231 | return result; | 246 | return result; |
232 | } | 247 | } |
248 | public Mesh ExtrudeCircularPath(Mesh m) | ||
249 | { | ||
250 | //startParameter = float.MinValue; | ||
251 | //stopParameter = float.MaxValue; | ||
252 | // Currently only works for iSteps=1; | ||
253 | Mesh result = new Mesh(); | ||
254 | |||
255 | Quaternion tt = new Quaternion(); | ||
256 | Vertex v2 = new Vertex(0, 0, 0); | ||
257 | |||
258 | Mesh newLayer; | ||
259 | Mesh lastLayer = null; | ||
260 | |||
261 | int start = 0; | ||
262 | int step; | ||
263 | int steps = 24; | ||
264 | |||
265 | float twistTotal = twistTop - twistBot; | ||
266 | if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 1.5) steps *= 2; | ||
267 | if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 3.0) steps *= 2; | ||
268 | |||
269 | double percentOfPathMultiplier = 1.0 / steps; | ||
270 | double angleStepMultiplier = System.Math.PI * 2.0 / steps; | ||
271 | |||
272 | //System.Console.WriteLine("twistTop: " + twistTop.ToString() + " twistbot: " + twistBot.ToString() + " twisttotal: " + twistTotal.ToString()); | ||
273 | |||
274 | float yPathScale = pathScaleY * 0.5f; | ||
275 | float skewStart = -skew; | ||
276 | float skewOffset = 0.0f; | ||
277 | float totalSkew = skew * 2.0f; | ||
278 | |||
279 | |||
280 | float startAngle = (float)(System.Math.PI * 2.0 * pathCutBegin * revolutions); | ||
281 | float endAngle = (float)(System.Math.PI * 2.0 * pathCutEnd * revolutions); | ||
282 | float stepSize = (float)0.2617993878; // 2*PI / 24 segments | ||
283 | step = (int)(startAngle / stepSize); | ||
284 | float angle = startAngle; | ||
285 | |||
286 | float xProfileScale = 1.0f; | ||
287 | float yProfileScale = 1.0f; | ||
288 | |||
289 | //System.Console.WriteLine("startAngle: " + startAngle.ToString() + " endAngle: " + endAngle.ToString() + " step: " + step.ToString()); | ||
290 | bool done = false; | ||
291 | |||
292 | //System.Console.WriteLine(" PathScaleX: " + pathScaleX.ToString() + " pathScaleY: " + pathScaleY.ToString()); | ||
293 | |||
294 | //System.Console.WriteLine("taperBotFactorX: " + taperBotFactorX.ToString() + " taperBotFactorY: " + taperBotFactorY.ToString() | ||
295 | // + " taperTopFactorX: " + taperTopFactorX.ToString() + " taperTopFactorY: " + taperTopFactorY.ToString()); | ||
296 | |||
297 | |||
298 | |||
299 | do | ||
300 | { | ||
301 | float percentOfPath = 1.0f; | ||
302 | |||
303 | percentOfPath = (angle - startAngle) / (endAngle - startAngle); // endAngle should always be larger than startAngle | ||
304 | |||
305 | // System.Console.WriteLine("angle: " + angle.ToString() + " percentOfPath: " + percentOfPath.ToString()); | ||
306 | |||
307 | if (pathTaperX > 0.001f) // can't really compare to 0.0f as the value passed is never exactly zero | ||
308 | xProfileScale = 1.0f - percentOfPath * pathTaperX; | ||
309 | else if (pathTaperX < -0.001f) | ||
310 | xProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperX; | ||
311 | else xProfileScale = 1.0f; | ||
312 | |||
313 | if (pathTaperY > 0.001f) | ||
314 | yProfileScale = 1.0f - percentOfPath * pathTaperY; | ||
315 | else if (pathTaperY < -0.001f) | ||
316 | yProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperY; | ||
317 | else yProfileScale = 1.0f; | ||
318 | |||
319 | float radiusScale; | ||
320 | |||
321 | if (radius > 0.001f) | ||
322 | radiusScale = 1.0f - radius * percentOfPath; | ||
323 | else if (radius < 0.001f) | ||
324 | radiusScale = 1.0f + radius * (1.0f - percentOfPath); | ||
325 | else radiusScale = 1.0f; | ||
326 | |||
327 | //radiusScale = 1.0f; | ||
328 | |||
329 | //System.Console.WriteLine("Extruder: radius: " + radius.ToString() + " radiusScale: " + radiusScale.ToString()); | ||
330 | |||
331 | |||
332 | |||
333 | |||
334 | |||
335 | float twist = twistBot + (twistTotal * (float)percentOfPath); | ||
336 | |||
337 | float zOffset = (float)(System.Math.Sin(angle) * (0.5f - yPathScale)) * radiusScale; | ||
338 | float yOffset = (float)(System.Math.Cos(angle) * (0.5f - yPathScale)) * radiusScale; | ||
339 | float xOffset = 0.5f * (skewStart + totalSkew * (float)percentOfPath); | ||
340 | |||
341 | newLayer = m.Clone(); | ||
342 | |||
343 | Vertex vTemp = new Vertex(0.0f, 0.0f, 0.0f); | ||
344 | |||
345 | if (twistTotal != 0.0f || twistBot != 0.0f) | ||
346 | { | ||
347 | Quaternion profileRot = new Quaternion(new Vertex(0.0f, 0.0f, -1.0f), twist); | ||
348 | foreach (Vertex v in newLayer.vertices) | ||
349 | { | ||
350 | if (v != null) | ||
351 | { | ||
352 | vTemp = v * profileRot; | ||
353 | v.X = vTemp.X; | ||
354 | v.Y = vTemp.Y; | ||
355 | v.Z = vTemp.Z; | ||
356 | } | ||
357 | } | ||
358 | } | ||
359 | |||
360 | Quaternion layerRot = new Quaternion(new Vertex(-1.0f, 0.0f, 0.0f), (float)angle); | ||
361 | foreach (Vertex v in newLayer.vertices) | ||
362 | { | ||
363 | if (v != null) | ||
364 | { | ||
365 | vTemp = v * layerRot; | ||
366 | v.X = xProfileScale * vTemp.X + xOffset; | ||
367 | v.Y = yProfileScale * vTemp.Y + yOffset; | ||
368 | v.Z = vTemp.Z + zOffset; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | if (angle == startAngle) // last layer, invert normals | ||
373 | foreach (Triangle t in newLayer.triangles) | ||
374 | { | ||
375 | t.invertNormal(); | ||
376 | } | ||
377 | |||
378 | result.Append(newLayer); | ||
379 | |||
380 | int iLastNull = 0; | ||
381 | |||
382 | if (lastLayer != null) | ||
383 | { | ||
384 | int i, count = newLayer.vertices.Count; | ||
385 | |||
386 | for (i = 0; i < count; i++) | ||
387 | { | ||
388 | int iNext = (i + 1); | ||
389 | |||
390 | if (lastLayer.vertices[i] == null) // cant make a simplex here | ||
391 | iLastNull = i + 1; | ||
392 | else | ||
393 | { | ||
394 | if (i == count - 1) // End of list | ||
395 | iNext = iLastNull; | ||
396 | |||
397 | if (lastLayer.vertices[iNext] == null) // Null means wrap to begin of last segment | ||
398 | iNext = iLastNull; | ||
399 | |||
400 | result.Add(new Triangle(newLayer.vertices[i], lastLayer.vertices[i], newLayer.vertices[iNext])); | ||
401 | result.Add(new Triangle(newLayer.vertices[iNext], lastLayer.vertices[i], lastLayer.vertices[iNext])); | ||
402 | } | ||
403 | } | ||
404 | } | ||
405 | lastLayer = newLayer; | ||
406 | |||
407 | |||
408 | |||
409 | |||
410 | |||
411 | |||
412 | |||
413 | |||
414 | // calc next angle | ||
415 | |||
416 | if (angle >= endAngle) | ||
417 | done = true; | ||
418 | else | ||
419 | { | ||
420 | angle = stepSize * ++step; | ||
421 | if (angle > endAngle) | ||
422 | angle = endAngle; | ||
423 | } | ||
424 | } | ||
425 | while (!done); | ||
426 | |||
427 | |||
428 | |||
429 | // scale the mesh to the desired size | ||
430 | float xScale = size.X; | ||
431 | float yScale = size.Y; | ||
432 | float zScale = size.Z; | ||
433 | |||
434 | foreach (Vertex v in result.vertices) | ||
435 | if (v != null) | ||
436 | { | ||
437 | v.X *= xScale; | ||
438 | v.Y *= yScale; | ||
439 | v.Z *= zScale; | ||
440 | } | ||
441 | |||
442 | return result; | ||
443 | } | ||
233 | } | 444 | } |
234 | } | 445 | } |
diff --git a/OpenSim/Region/Physics/Meshing/HelperTypes.cs b/OpenSim/Region/Physics/Meshing/HelperTypes.cs index 584133c..f031fb6 100644 --- a/OpenSim/Region/Physics/Meshing/HelperTypes.cs +++ b/OpenSim/Region/Physics/Meshing/HelperTypes.cs | |||
@@ -51,9 +51,13 @@ public class Quaternion | |||
51 | { | 51 | { |
52 | // using (* 0.5) instead of (/2) | 52 | // using (* 0.5) instead of (/2) |
53 | w = (float)Math.Cos(angle * 0.5f); | 53 | w = (float)Math.Cos(angle * 0.5f); |
54 | x = axis.X * (float)Math.Sin(angle * 0.5f); | 54 | float sin = (float)Math.Sin(angle * 0.5f); |
55 | y = axis.Y * (float)Math.Sin(angle * 0.5f); | 55 | //x = axis.X * (float)Math.Sin(angle * 0.5f); |
56 | z = axis.Z * (float)Math.Sin(angle * 0.5f); | 56 | //y = axis.Y * (float)Math.Sin(angle * 0.5f); |
57 | //z = axis.Z * (float)Math.Sin(angle * 0.5f); | ||
58 | x = axis.X * sin; | ||
59 | y = axis.Y * sin; | ||
60 | z = axis.Z * sin; | ||
57 | normalize(); | 61 | normalize(); |
58 | } | 62 | } |
59 | public static Quaternion operator *(Quaternion a, Quaternion b) | 63 | public static Quaternion operator *(Quaternion a, Quaternion b) |
@@ -73,12 +77,18 @@ public class Quaternion | |||
73 | } | 77 | } |
74 | public void normalize() | 78 | public void normalize() |
75 | { | 79 | { |
76 | float mag = length(); | 80 | //float mag = length(); |
77 | 81 | ||
78 | w /= mag; | 82 | //w /= mag; |
79 | x /= mag; | 83 | //x /= mag; |
80 | y /= mag; | 84 | //y /= mag; |
81 | z /= mag; | 85 | //z /= mag; |
86 | float iMag = 1.0f / length(); | ||
87 | |||
88 | w *= iMag; | ||
89 | x *= iMag; | ||
90 | y *= iMag; | ||
91 | z *= iMag; | ||
82 | } | 92 | } |
83 | public float length() | 93 | public float length() |
84 | { | 94 | { |
@@ -169,7 +179,8 @@ public class Vertex : PhysicsVector, IComparable<Vertex> | |||
169 | float tlength = length(); | 179 | float tlength = length(); |
170 | if (tlength != 0) | 180 | if (tlength != 0) |
171 | { | 181 | { |
172 | return new Vertex(X / tlength, Y / tlength, Z / tlength); | 182 | float mul = 1.0f / tlength; |
183 | return new Vertex(X * mul, Y * mul, Z * mul); | ||
173 | } | 184 | } |
174 | else | 185 | else |
175 | { | 186 | { |
@@ -230,9 +241,10 @@ public class Vertex : PhysicsVector, IComparable<Vertex> | |||
230 | { | 241 | { |
231 | return new Vertex(0f,0f,0f); | 242 | return new Vertex(0f,0f,0f); |
232 | } | 243 | } |
233 | v1.X /= am; | 244 | float mul = 1.0f / am; |
234 | v1.Y /= am; | 245 | v1.X *= mul; |
235 | v1.Z /= am; | 246 | v1.Y *= mul; |
247 | v1.Z *= mul; | ||
236 | return v1; | 248 | return v1; |
237 | } | 249 | } |
238 | 250 | ||
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index ba4f941..5ef392c 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -29,6 +29,7 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using OpenSim.Framework; | 30 | using OpenSim.Framework; |
31 | using OpenSim.Region.Physics.Manager; | 31 | using OpenSim.Region.Physics.Manager; |
32 | using libsecondlife; | ||
32 | 33 | ||
33 | namespace OpenSim.Region.Physics.Meshing | 34 | namespace OpenSim.Region.Physics.Meshing |
34 | { | 35 | { |
@@ -253,7 +254,8 @@ namespace OpenSim.Region.Physics.Meshing | |||
253 | holeHull.AddVertex(IPP); | 254 | holeHull.AddVertex(IPP); |
254 | holeHull.AddVertex(IPM); | 255 | holeHull.AddVertex(IPM); |
255 | } | 256 | } |
256 | if (hshape == HollowShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) | 257 | //if (hshape == HollowShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) |
258 | if ( hshape == HollowShape.Circle ) | ||
257 | { | 259 | { |
258 | float hollowFactorF = (float)fhollowFactor / (float)50000; | 260 | float hollowFactorF = (float)fhollowFactor / (float)50000; |
259 | 261 | ||
@@ -576,7 +578,6 @@ namespace OpenSim.Region.Physics.Meshing | |||
576 | } | 578 | } |
577 | } | 579 | } |
578 | 580 | ||
579 | |||
580 | if (pathShearX != 0) | 581 | if (pathShearX != 0) |
581 | { | 582 | { |
582 | if (pathShearX > 50) | 583 | if (pathShearX > 50) |
@@ -647,7 +648,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
647 | return result; | 648 | return result; |
648 | } | 649 | } |
649 | 650 | ||
650 | private static Mesh CreateCyllinderMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size) | 651 | private static Mesh CreateCylinderMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size) |
651 | // Builds the z (+ and -) surfaces of a box shaped prim | 652 | // Builds the z (+ and -) surfaces of a box shaped prim |
652 | { | 653 | { |
653 | 654 | ||
@@ -1318,6 +1319,317 @@ namespace OpenSim.Region.Physics.Meshing | |||
1318 | return sm; | 1319 | return sm; |
1319 | 1320 | ||
1320 | } | 1321 | } |
1322 | |||
1323 | private static Mesh CreateCircularProfileMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size) | ||
1324 | { | ||
1325 | |||
1326 | UInt16 hollowFactor = primShape.ProfileHollow; | ||
1327 | UInt16 profileBegin = primShape.ProfileBegin; | ||
1328 | UInt16 profileEnd = primShape.ProfileEnd; | ||
1329 | UInt16 taperX = primShape.PathScaleX; | ||
1330 | UInt16 taperY = primShape.PathScaleY; | ||
1331 | UInt16 pathShearX = primShape.PathShearX; | ||
1332 | UInt16 pathShearY = primShape.PathShearY; | ||
1333 | Int16 twistBot = primShape.PathTwist; | ||
1334 | Int16 twistTop = primShape.PathTwistBegin; | ||
1335 | HollowShape hollowShape = primShape.HollowShape; | ||
1336 | |||
1337 | //Console.WriteLine("pathTwist: " + primShape.PathTwist.ToString() + " pathTwistBegin: " + primShape.PathTwistBegin.ToString()); | ||
1338 | |||
1339 | SimpleHull outerHull = new SimpleHull(); | ||
1340 | |||
1341 | //Console.WriteLine("primShape.ProfileCurve & 0x07: " + Convert.ToString(primShape.ProfileCurve & 0x07)); | ||
1342 | |||
1343 | if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
1344 | |||
1345 | //if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle | ||
1346 | // || (primShape.ProfileCurve & 0x07) == (byte) ProfileShape.Square) | ||
1347 | { | ||
1348 | //Console.WriteLine("Meshmerizer thinks " + primName + " is a TORUS"); | ||
1349 | if ( hollowShape == HollowShape.Same ) | ||
1350 | hollowShape = HollowShape.Circle; | ||
1351 | |||
1352 | // build the profile shape | ||
1353 | // counter-clockwise around the quadrants, start at 45 degrees | ||
1354 | |||
1355 | outerHull.AddVertex(new Vertex(0.353553f, 0.353553f, 0.0f)); // 45 degrees | ||
1356 | outerHull.AddVertex(new Vertex(0.250000f, 0.433013f, 0.0f)); // 60 degrees | ||
1357 | outerHull.AddVertex(new Vertex(0.129410f, 0.482963f, 0.0f)); // 75 degrees | ||
1358 | outerHull.AddVertex(new Vertex(0.000000f, 0.500000f, 0.0f)); // 90 degrees | ||
1359 | outerHull.AddVertex(new Vertex(-0.129410f, 0.482963f, 0.0f)); // 105 degrees | ||
1360 | outerHull.AddVertex(new Vertex(-0.250000f, 0.433013f, 0.0f)); // 120 degrees | ||
1361 | outerHull.AddVertex(new Vertex(-0.353553f, 0.353553f, 0.0f)); // 135 degrees | ||
1362 | outerHull.AddVertex(new Vertex(-0.433013f, 0.250000f, 0.0f)); // 150 degrees | ||
1363 | outerHull.AddVertex(new Vertex(-0.482963f, 0.129410f, 0.0f)); // 165 degrees | ||
1364 | outerHull.AddVertex(new Vertex(-0.500000f, 0.000000f, 0.0f)); // 180 degrees | ||
1365 | outerHull.AddVertex(new Vertex(-0.482963f, -0.129410f, 0.0f)); // 195 degrees | ||
1366 | outerHull.AddVertex(new Vertex(-0.433013f, -0.250000f, 0.0f)); // 210 degrees | ||
1367 | outerHull.AddVertex(new Vertex(-0.353553f, -0.353553f, 0.0f)); // 225 degrees | ||
1368 | outerHull.AddVertex(new Vertex(-0.250000f, -0.433013f, 0.0f)); // 240 degrees | ||
1369 | outerHull.AddVertex(new Vertex(-0.129410f, -0.482963f, 0.0f)); // 255 degrees | ||
1370 | outerHull.AddVertex(new Vertex(0.000000f, -0.500000f, 0.0f)); // 270 degrees | ||
1371 | outerHull.AddVertex(new Vertex(0.129410f, -0.482963f, 0.0f)); // 285 degrees | ||
1372 | outerHull.AddVertex(new Vertex(0.250000f, -0.433013f, 0.0f)); // 300 degrees | ||
1373 | outerHull.AddVertex(new Vertex(0.353553f, -0.353553f, 0.0f)); // 315 degrees | ||
1374 | outerHull.AddVertex(new Vertex(0.433013f, -0.250000f, 0.0f)); // 330 degrees | ||
1375 | outerHull.AddVertex(new Vertex(0.482963f, -0.129410f, 0.0f)); // 345 degrees | ||
1376 | outerHull.AddVertex(new Vertex(0.500000f, 0.000000f, 0.0f)); // 0 degrees | ||
1377 | outerHull.AddVertex(new Vertex(0.482963f, 0.129410f, 0.0f)); // 15 degrees | ||
1378 | outerHull.AddVertex(new Vertex(0.433013f, 0.250000f, 0.0f)); // 30 degrees | ||
1379 | } | ||
1380 | |||
1381 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Square) // a ring | ||
1382 | { | ||
1383 | //Console.WriteLine("Meshmerizer thinks " + primName + " is a TUBE"); | ||
1384 | if ( hollowShape == HollowShape.Same ) | ||
1385 | hollowShape = HollowShape.Square; | ||
1386 | |||
1387 | outerHull.AddVertex(new Vertex(+0.5f, +0.5f, 0.0f)); | ||
1388 | outerHull.AddVertex(new Vertex(-0.5f, +0.5f, 0.0f)); | ||
1389 | outerHull.AddVertex(new Vertex(-0.5f, -0.5f, 0.0f)); | ||
1390 | outerHull.AddVertex(new Vertex(+0.5f, -0.5f, 0.0f)); | ||
1391 | } | ||
1392 | |||
1393 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
1394 | { | ||
1395 | //Console.WriteLine("Meshmerizer thinks " + primName + " is a RING"); | ||
1396 | if ( hollowShape == HollowShape.Same ) | ||
1397 | hollowShape = HollowShape.Triangle; | ||
1398 | |||
1399 | outerHull.AddVertex(new Vertex(+0.255f, -0.375f, 0.0f)); | ||
1400 | outerHull.AddVertex(new Vertex(+0.25f, +0.375f, 0.0f)); | ||
1401 | outerHull.AddVertex(new Vertex(-0.5f, +0.0f, 0.0f)); | ||
1402 | |||
1403 | } | ||
1404 | |||
1405 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) | ||
1406 | { | ||
1407 | //Console.WriteLine("Meshmerizer thinks " + primName + " is a SPHERE"); | ||
1408 | if (hollowShape == HollowShape.Same) | ||
1409 | hollowShape = HollowShape.Circle; | ||
1410 | |||
1411 | // not implemented here, use old routine | ||
1412 | return CreateSphereMesh(primName, primShape, size); | ||
1413 | } | ||
1414 | |||
1415 | // Deal with cuts now | ||
1416 | if ((profileBegin != 0) || (profileEnd != 0)) | ||
1417 | { | ||
1418 | double fProfileBeginAngle = profileBegin / 50000.0 * 360.0; | ||
1419 | // In degree, for easier debugging and understanding | ||
1420 | //fProfileBeginAngle -= (90.0 + 45.0); // for some reasons, the SL client counts from the corner -X/-Y | ||
1421 | double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0 | ||
1422 | //fProfileEndAngle -= (90.0 + 45.0); | ||
1423 | if (fProfileBeginAngle < fProfileEndAngle) | ||
1424 | fProfileEndAngle -= 360.0; | ||
1425 | |||
1426 | // Note, that we don't want to cut out a triangle, even if this is a | ||
1427 | // good approximation for small cuts. Indeed we want to cut out an arc | ||
1428 | // and we approximate this arc by a polygon chain | ||
1429 | // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space | ||
1430 | // So it can easily be subtracted from the outer hull | ||
1431 | int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5); | ||
1432 | // how many steps do we need with approximately 45 degree | ||
1433 | double dStepWidth = (fProfileBeginAngle - fProfileEndAngle) / iSteps; | ||
1434 | |||
1435 | Vertex origin = new Vertex(0.0f, 0.0f, 0.0f); | ||
1436 | |||
1437 | // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull | ||
1438 | SimpleHull cutHull = new SimpleHull(); | ||
1439 | cutHull.AddVertex(origin); | ||
1440 | for (int i = 0; i < iSteps; i++) | ||
1441 | { | ||
1442 | double angle = fProfileBeginAngle - i * dStepWidth; // we count against the angle orientation!!!! | ||
1443 | Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0); | ||
1444 | cutHull.AddVertex(v); | ||
1445 | } | ||
1446 | Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0); | ||
1447 | // Calculated separately to avoid errors | ||
1448 | cutHull.AddVertex(legEnd); | ||
1449 | |||
1450 | // m_log.DebugFormat("Starting cutting of the hollow shape from the prim {1}", 0, primName); | ||
1451 | SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull); | ||
1452 | |||
1453 | if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
1454 | { | ||
1455 | Quaternion zFlip = new Quaternion(new Vertex(0.0f, 0.0f, 1.0f), (float)Math.PI); | ||
1456 | Vertex vTmp = new Vertex(0.0f, 0.0f, 0.0f); | ||
1457 | foreach (Vertex v in cuttedHull.getVertices()) | ||
1458 | if (v != null) | ||
1459 | { | ||
1460 | vTmp = v * zFlip; | ||
1461 | v.X = vTmp.X; | ||
1462 | v.Y = vTmp.Y; | ||
1463 | v.Z = vTmp.Z; | ||
1464 | } | ||
1465 | } | ||
1466 | |||
1467 | outerHull = cuttedHull; | ||
1468 | } | ||
1469 | |||
1470 | // Deal with the hole here | ||
1471 | if (hollowFactor > 0) | ||
1472 | { | ||
1473 | SimpleHull holeHull; | ||
1474 | |||
1475 | if (hollowShape == HollowShape.Triangle) | ||
1476 | { | ||
1477 | holeHull = new SimpleHull(); | ||
1478 | |||
1479 | float hollowFactorF = (float) hollowFactor / 50000.0f; | ||
1480 | |||
1481 | if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
1482 | { | ||
1483 | holeHull.AddVertex(new Vertex(+0.125f * hollowFactorF, -0.1875f * hollowFactorF, 0.0f)); | ||
1484 | holeHull.AddVertex(new Vertex(-0.25f * hollowFactorF, -0f * hollowFactorF, 0.0f)); | ||
1485 | holeHull.AddVertex(new Vertex(+0.125f * hollowFactorF, +0.1875f * hollowFactorF, 0.0f)); | ||
1486 | } | ||
1487 | else | ||
1488 | { | ||
1489 | holeHull.AddVertex(new Vertex(+0.25f * hollowFactorF, -0.45f * hollowFactorF, 0.0f)); | ||
1490 | holeHull.AddVertex(new Vertex(-0.5f * hollowFactorF, -0f * hollowFactorF, 0.0f)); | ||
1491 | holeHull.AddVertex(new Vertex(+0.25f * hollowFactorF, +0.45f * hollowFactorF, 0.0f)); | ||
1492 | |||
1493 | ////holeHull.AddVertex(new Vertex(-0.5f * hollowFactorF, -0f * hollowFactorF, 0.0f)); | ||
1494 | |||
1495 | ////holeHull.AddVertex(new Vertex(+0.25f * hollowFactorF, +0.45f * hollowFactorF, 0.0f)); | ||
1496 | |||
1497 | ////holeHull.AddVertex(new Vertex(+0.25f * hollowFactorF, -0.45f * hollowFactorF, 0.0f)); | ||
1498 | |||
1499 | //holeHull.AddVertex(new Vertex(-0.5f * hollowFactorF, +0f * hollowFactorF, 0.0f)); | ||
1500 | //holeHull.AddVertex(new Vertex(+0.25f * hollowFactorF, -0.45f * hollowFactorF, 0.0f)); | ||
1501 | //holeHull.AddVertex(new Vertex(+0.25f * hollowFactorF, +0.45f * hollowFactorF, 0.0f)); | ||
1502 | ////holeHull.AddVertex(new Vertex(-0.5f * hollowFactorF, +0f * hollowFactorF, 0.0f)); | ||
1503 | } | ||
1504 | } | ||
1505 | else | ||
1506 | { | ||
1507 | holeHull = BuildHoleHull(primShape, primShape.ProfileShape, primShape.HollowShape, hollowFactor); | ||
1508 | } | ||
1509 | |||
1510 | if (holeHull != null) | ||
1511 | { | ||
1512 | SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull); | ||
1513 | |||
1514 | outerHull = hollowedHull; | ||
1515 | } | ||
1516 | } | ||
1517 | |||
1518 | Mesh m = new Mesh(); | ||
1519 | |||
1520 | Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f); | ||
1521 | Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f); | ||
1522 | Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f); | ||
1523 | |||
1524 | m.Add(Seed1); | ||
1525 | m.Add(Seed2); | ||
1526 | m.Add(Seed3); | ||
1527 | |||
1528 | m.Add(new Triangle(Seed1, Seed2, Seed3)); | ||
1529 | m.Add(outerHull.getVertices()); | ||
1530 | |||
1531 | InsertVertices(m.vertices, 3, m.triangles); | ||
1532 | m.DumpRaw(baseDir, primName, "Proto first Mesh"); | ||
1533 | |||
1534 | m.Remove(Seed1); | ||
1535 | m.Remove(Seed2); | ||
1536 | m.Remove(Seed3); | ||
1537 | m.DumpRaw(baseDir, primName, "Proto seeds removed"); | ||
1538 | |||
1539 | m.RemoveTrianglesOutside(outerHull); | ||
1540 | m.DumpRaw(baseDir, primName, "Proto outsides removed"); | ||
1541 | |||
1542 | foreach (Triangle t in m.triangles) | ||
1543 | t.invertNormal(); | ||
1544 | |||
1545 | Vertex vTemp = new Vertex(0.0f, 0.0f, 0.0f); | ||
1546 | |||
1547 | //Console.WriteLine("primShape.PathScaleX: " + primShape.PathScaleX.ToString() + " primShape.PathScaleY: " + primShape.PathScaleY.ToString()); | ||
1548 | //Console.WriteLine("primShape.PathSkew: " + primShape.PathSkew.ToString() + " primShape.PathRadiusOffset: " + primShape.PathRadiusOffset.ToString() + " primShape.pathRevolutions: " + primShape.PathRevolutions.ToString()); | ||
1549 | |||
1550 | float skew = primShape.PathSkew * 0.01f; | ||
1551 | float pathScaleX = (float)(200 - primShape.PathScaleX) * 0.01f; | ||
1552 | float pathScaleY = (float)(200 - primShape.PathScaleY) * 0.01f; | ||
1553 | //Console.WriteLine("PathScaleX: " + pathScaleX.ToString() + " pathScaleY: " + pathScaleY.ToString()); | ||
1554 | |||
1555 | float profileXComp = pathScaleX * (1.0f - Math.Abs(skew)); | ||
1556 | foreach (Vertex v in m.vertices) | ||
1557 | if (v != null) | ||
1558 | { | ||
1559 | v.X *= profileXComp; | ||
1560 | v.Y *= pathScaleY; | ||
1561 | //v.Y *= 0.5f; // torus profile is scaled in y axis | ||
1562 | } | ||
1563 | |||
1564 | Extruder extr = new Extruder(); | ||
1565 | |||
1566 | extr.size = size; | ||
1567 | extr.pathScaleX = pathScaleX; | ||
1568 | extr.pathScaleY = pathScaleY; | ||
1569 | extr.pathCutBegin = 0.00002f * primShape.PathBegin; | ||
1570 | extr.pathCutEnd = 0.00002f * (50000 - primShape.PathEnd); | ||
1571 | extr.pathBegin = primShape.PathBegin; | ||
1572 | extr.pathEnd = primShape.PathEnd; | ||
1573 | extr.skew = skew; | ||
1574 | extr.revolutions = 1.0f + (float)primShape.PathRevolutions * 3.0f / 200.0f; | ||
1575 | |||
1576 | //System.Console.WriteLine("primShape.PathBegin: " + primShape.PathBegin.ToString() + " primShape.PathEnd: " + primShape.PathEnd.ToString()); | ||
1577 | //System.Console.WriteLine("extr.pathCutBegin: " + extr.pathCutBegin.ToString() + " extr.pathCutEnd: " + extr.pathCutEnd.ToString()); | ||
1578 | //System.Console.WriteLine("extr.revolutions: " + extr.revolutions.ToString()); | ||
1579 | |||
1580 | //System.Console.WriteLine("primShape.PathTaperX: " + primShape.PathTaperX.ToString()); | ||
1581 | //System.Console.WriteLine("primShape.PathTaperY: " + primShape.PathTaperY.ToString()); | ||
1582 | |||
1583 | extr.pathTaperX = 0.01f * (float)primShape.PathTaperX; | ||
1584 | extr.pathTaperY = 0.01f * (float)primShape.PathTaperY; | ||
1585 | |||
1586 | extr.radius = 0.01f * (float)primShape.PathRadiusOffset; | ||
1587 | //System.Console.WriteLine("primShape.PathRadiusOffset: " + primShape.PathRadiusOffset.ToString()); | ||
1588 | |||
1589 | |||
1590 | |||
1591 | |||
1592 | |||
1593 | if (pathShearX != 0) | ||
1594 | { | ||
1595 | if (pathShearX > 50) | ||
1596 | { | ||
1597 | // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 | ||
1598 | extr.pushX = (((float)(256 - pathShearX) / 100) * -1f); | ||
1599 | //m_log.Warn("pushX: " + extr.pushX); | ||
1600 | } | ||
1601 | else | ||
1602 | { | ||
1603 | extr.pushX = (float)pathShearX / 100; | ||
1604 | //m_log.Warn("pushX: " + extr.pushX); | ||
1605 | } | ||
1606 | } | ||
1607 | |||
1608 | if (pathShearY != 0) | ||
1609 | { | ||
1610 | if (pathShearY > 50) | ||
1611 | { | ||
1612 | // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 | ||
1613 | extr.pushY = (((float)(256 - pathShearY) / 100) * -1f); | ||
1614 | //m_log.Warn("pushY: " + extr.pushY); | ||
1615 | } | ||
1616 | else | ||
1617 | { | ||
1618 | extr.pushY = (float)pathShearY / 100; | ||
1619 | //m_log.Warn("pushY: " + extr.pushY); | ||
1620 | } | ||
1621 | |||
1622 | } | ||
1623 | |||
1624 | extr.twistTop = (float)primShape.PathTwist * (float)Math.PI * 0.02f; | ||
1625 | extr.twistBot = (float)primShape.PathTwistBegin * (float)Math.PI * 0.02f; | ||
1626 | |||
1627 | //System.Console.WriteLine("[MESH]: twistTop = " + twistTop.ToString() + "|" + extr.twistTop.ToString() + ", twistMid = " + twistMid.ToString() + "|" + extr.twistMid.ToString() + ", twistbot = " + twistBot.ToString() + "|" + extr.twistBot.ToString()); | ||
1628 | Mesh result = extr.ExtrudeCircularPath(m); | ||
1629 | result.DumpRaw(baseDir, primName, "Z extruded"); | ||
1630 | return result; | ||
1631 | } | ||
1632 | |||
1321 | public static void CalcNormals(Mesh mesh) | 1633 | public static void CalcNormals(Mesh mesh) |
1322 | { | 1634 | { |
1323 | int iTriangles = mesh.triangles.Count; | 1635 | int iTriangles = mesh.triangles.Count; |
@@ -1432,43 +1744,111 @@ namespace OpenSim.Region.Physics.Meshing | |||
1432 | mesh = (Mesh)smesh; | 1744 | mesh = (Mesh)smesh; |
1433 | CalcNormals(mesh); | 1745 | CalcNormals(mesh); |
1434 | } | 1746 | } |
1435 | else | 1747 | else if ((primShape.ProfileCurve & (byte)ProfileShape.Square) == (byte)ProfileShape.Square) |
1748 | { | ||
1749 | if (primShape.PathCurve == (byte)LLObject.PathCurve.Line) | ||
1750 | { // its a box | ||
1751 | mesh = CreateBoxMesh(primName, primShape, size); | ||
1752 | CalcNormals(mesh); | ||
1753 | } | ||
1754 | else if (primShape.PathCurve == (byte)LLObject.PathCurve.Circle) | ||
1755 | { // tube | ||
1756 | // do a cylinder for now | ||
1757 | //mesh = CreateCylinderMesh(primName, primShape, size); | ||
1758 | mesh = CreateCircularProfileMesh(primName, primShape, size); | ||
1759 | CalcNormals(mesh); | ||
1760 | } | ||
1761 | } | ||
1762 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) | ||
1436 | { | 1763 | { |
1437 | switch (primShape.ProfileShape) | 1764 | if (primShape.PathCurve == (byte)Extrusion.Straight) |
1438 | { | 1765 | { |
1439 | case ProfileShape.Square: | 1766 | mesh = CreateCylinderMesh(primName, primShape, size); |
1440 | mesh = CreateBoxMesh(primName, primShape, size); | 1767 | CalcNormals(mesh); |
1441 | CalcNormals(mesh); | 1768 | } |
1442 | break; | ||
1443 | case ProfileShape.Circle: | ||
1444 | if (primShape.PathCurve == (byte)Extrusion.Straight) | ||
1445 | { | ||
1446 | mesh = CreateCyllinderMesh(primName, primShape, size); | ||
1447 | CalcNormals(mesh); | ||
1448 | } | ||
1449 | break; | ||
1450 | case ProfileShape.HalfCircle: | ||
1451 | if (primShape.PathCurve == (byte)Extrusion.Curve1) | ||
1452 | { | ||
1453 | mesh = CreateSphereMesh(primName, primShape, size); | ||
1454 | CalcNormals(mesh); | ||
1455 | } | ||
1456 | break; | ||
1457 | |||
1458 | case ProfileShape.EquilateralTriangle: | ||
1459 | mesh = CreatePrismMesh(primName, primShape, size); | ||
1460 | CalcNormals(mesh); | ||
1461 | break; | ||
1462 | 1769 | ||
1463 | default: | 1770 | // look at LLObject.cs in libsecondlife for how to know the prim type |
1464 | mesh = CreateBoxMesh(primName, primShape, size); | 1771 | // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits |
1465 | CalcNormals(mesh); | 1772 | else if (primShape.PathCurve == (byte) Extrusion.Curve1 && LLObject.UnpackPathScale(primShape.PathScaleY) <= 0.75f) |
1466 | //Set default mesh to cube otherwise it'll return | 1773 | { // dahlia's favorite, a torus :) |
1467 | // null and crash on the 'setMesh' method in the physics plugins. | 1774 | mesh = CreateCircularProfileMesh(primName, primShape, size); |
1468 | //mesh = null; | 1775 | CalcNormals(mesh); |
1469 | break; | ||
1470 | } | 1776 | } |
1471 | } | 1777 | } |
1778 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) | ||
1779 | { | ||
1780 | if (primShape.PathCurve == (byte)Extrusion.Curve1 || primShape.PathCurve == (byte) Extrusion.Curve2) | ||
1781 | { | ||
1782 | mesh = CreateSphereMesh(primName, primShape, size); | ||
1783 | CalcNormals(mesh); | ||
1784 | } | ||
1785 | } | ||
1786 | else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) | ||
1787 | { | ||
1788 | if (primShape.PathCurve == (byte)Extrusion.Straight) | ||
1789 | { | ||
1790 | mesh = CreatePrismMesh(primName, primShape, size); | ||
1791 | CalcNormals(mesh); | ||
1792 | } | ||
1793 | else if (primShape.PathCurve == (byte) Extrusion.Curve1) | ||
1794 | { // a ring - do a cylinder for now | ||
1795 | //mesh = CreateCylinderMesh(primName, primShape, size); | ||
1796 | mesh = CreateCircularProfileMesh(primName, primShape, size); | ||
1797 | CalcNormals(mesh); | ||
1798 | } | ||
1799 | } | ||
1800 | else // just do a box | ||
1801 | { | ||
1802 | mesh = CreateBoxMesh(primName, primShape, size); | ||
1803 | CalcNormals(mesh); | ||
1804 | } | ||
1805 | |||
1806 | //else | ||
1807 | //{ | ||
1808 | // switch (primShape.ProfileShape) | ||
1809 | // { | ||
1810 | // case ProfileShape.Square: | ||
1811 | // mesh = CreateBoxMesh(primName, primShape, size); | ||
1812 | // CalcNormals(mesh); | ||
1813 | // break; | ||
1814 | // case ProfileShape.Circle: | ||
1815 | // if (primShape.PathCurve == (byte)Extrusion.Straight) | ||
1816 | // { | ||
1817 | // mesh = CreateCylinderMesh(primName, primShape, size); | ||
1818 | // CalcNormals(mesh); | ||
1819 | // } | ||
1820 | |||
1821 | // // look at LLObject.cs in libsecondlife for how to know the prim type | ||
1822 | // // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits | ||
1823 | // else if ((primShape.ProfileCurve & 0x07) == (byte)LLObject.ProfileCurve.Circle && LLObject.UnpackPathScale(primShape.PathScaleY) <= 0.75f) | ||
1824 | // { // dahlia's favorite, a torus :) | ||
1825 | // mesh = CreateCylinderMesh(primName, primShape, size); | ||
1826 | // CalcNormals(mesh); | ||
1827 | // } | ||
1828 | |||
1829 | // break; | ||
1830 | // case ProfileShape.HalfCircle: | ||
1831 | // if (primShape.PathCurve == (byte)Extrusion.Curve1) | ||
1832 | // { | ||
1833 | // mesh = CreateSphereMesh(primName, primShape, size); | ||
1834 | // CalcNormals(mesh); | ||
1835 | // } | ||
1836 | // break; | ||
1837 | |||
1838 | // case ProfileShape.EquilateralTriangle: | ||
1839 | // mesh = CreatePrismMesh(primName, primShape, size); | ||
1840 | // CalcNormals(mesh); | ||
1841 | // break; | ||
1842 | |||
1843 | // default: | ||
1844 | // mesh = CreateBoxMesh(primName, primShape, size); | ||
1845 | // CalcNormals(mesh); | ||
1846 | // //Set default mesh to cube otherwise it'll return | ||
1847 | // // null and crash on the 'setMesh' method in the physics plugins. | ||
1848 | // //mesh = null; | ||
1849 | // break; | ||
1850 | // } | ||
1851 | //} | ||
1472 | 1852 | ||
1473 | return mesh; | 1853 | return mesh; |
1474 | } | 1854 | } |
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index e43a1ac..5078f03 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | |||
@@ -36,6 +36,7 @@ using Nini.Config; | |||
36 | using Ode.NET; | 36 | using Ode.NET; |
37 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
38 | using OpenSim.Region.Physics.Manager; | 38 | using OpenSim.Region.Physics.Manager; |
39 | using libsecondlife; | ||
39 | 40 | ||
40 | //using OpenSim.Region.Physics.OdePlugin.Meshing; | 41 | //using OpenSim.Region.Physics.OdePlugin.Meshing; |
41 | 42 | ||
@@ -1512,6 +1513,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1512 | /// <returns></returns> | 1513 | /// <returns></returns> |
1513 | public bool needsMeshing(PrimitiveBaseShape pbs) | 1514 | public bool needsMeshing(PrimitiveBaseShape pbs) |
1514 | { | 1515 | { |
1516 | //if (pbs.PathCurve == (byte)LLObject.PathCurve.Circle && pbs.ProfileCurve == (byte)LLObject.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f) | ||
1517 | //Console.WriteLine("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + LLObject.UnpackPathScale(pbs.PathScaleY).ToString()); | ||
1515 | if (pbs.SculptEntry && !meshSculptedPrim) | 1518 | if (pbs.SculptEntry && !meshSculptedPrim) |
1516 | { | 1519 | { |
1517 | return false; | 1520 | return false; |
@@ -1537,6 +1540,22 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1537 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) | 1540 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) |
1538 | return true; | 1541 | return true; |
1539 | 1542 | ||
1543 | // test for torus | ||
1544 | if (pbs.PathCurve == (byte)LLObject.PathCurve.Circle | ||
1545 | && (pbs.ProfileCurve & 0x07) == (byte)LLObject.ProfileCurve.Circle | ||
1546 | && LLObject.UnpackPathScale(pbs.PathScaleY) <= 0.75f) | ||
1547 | return true; | ||
1548 | |||
1549 | // test for tube | ||
1550 | if (pbs.PathCurve == (byte)LLObject.PathCurve.Circle | ||
1551 | && (pbs.ProfileCurve & 0x07) == (byte)LLObject.ProfileCurve.EqualTriangle) | ||
1552 | return true; | ||
1553 | |||
1554 | // test for ring | ||
1555 | if (pbs.PathCurve == (byte)LLObject.PathCurve.Circle | ||
1556 | && (pbs.ProfileCurve & 0x07) == (byte)LLObject.ProfileCurve.EqualTriangle) | ||
1557 | return true; | ||
1558 | |||
1540 | if (pbs.ProfileShape == ProfileShape.EquilateralTriangle) | 1559 | if (pbs.ProfileShape == ProfileShape.EquilateralTriangle) |
1541 | return true; | 1560 | return true; |
1542 | 1561 | ||