Extruder.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  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
  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
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using OpenSim.Region.Physics.Manager;
  28. namespace OpenSim.Region.Physics.Meshing
  29. {
  30. internal class Extruder
  31. {
  32. public float startParameter;
  33. public float stopParameter;
  34. public PhysicsVector size;
  35. public float taperTopFactorX = 1f;
  36. public float taperTopFactorY = 1f;
  37. public float taperBotFactorX = 1f;
  38. public float taperBotFactorY = 1f;
  39. public float pushX = 0f;
  40. public float pushY = 0f;
  41. // twist amount in radians. NOT DEGREES.
  42. public float twistTop = 0;
  43. public float twistBot = 0;
  44. public float twistMid = 0;
  45. public float pathScaleX = 1.0f;
  46. public float pathScaleY = 0.5f;
  47. public float skew = 0.0f;
  48. public float radius = 0.0f;
  49. public float revolutions = 1.0f;
  50. public float pathCutBegin = 0.0f;
  51. public float pathCutEnd = 1.0f;
  52. public ushort pathBegin = 0;
  53. public ushort pathEnd = 0;
  54. public float pathTaperX = 0.0f;
  55. public float pathTaperY = 0.0f;
  56. public Mesh Extrude(Mesh m)
  57. {
  58. startParameter = float.MinValue;
  59. stopParameter = float.MaxValue;
  60. // Currently only works for iSteps=1;
  61. Mesh result = new Mesh();
  62. Mesh workingPlus = m.Clone();
  63. Mesh workingMiddle = m.Clone();
  64. Mesh workingMinus = m.Clone();
  65. Quaternion tt = new Quaternion();
  66. Vertex v2 = new Vertex(0, 0, 0);
  67. foreach (Vertex v in workingPlus.vertices)
  68. {
  69. if (v == null)
  70. continue;
  71. // This is the top
  72. // Set the Z + .5 to match the rest of the scale of the mesh
  73. // Scale it by Size, and Taper the scaling
  74. v.Z = +.5f;
  75. v.X *= (size.X * taperTopFactorX);
  76. v.Y *= (size.Y * taperTopFactorY);
  77. v.Z *= size.Z;
  78. //Push the top of the object over by the Top Shear amount
  79. v.X += pushX * size.X;
  80. v.Y += pushY * size.Y;
  81. if (twistTop != 0)
  82. {
  83. // twist and shout
  84. tt = new Quaternion(new Vertex(0, 0, 1), twistTop);
  85. v2 = v * tt;
  86. v.X = v2.X;
  87. v.Y = v2.Y;
  88. v.Z = v2.Z;
  89. }
  90. }
  91. foreach (Vertex v in workingMiddle.vertices)
  92. {
  93. if (v == null)
  94. continue;
  95. // This is the top
  96. // Set the Z + .5 to match the rest of the scale of the mesh
  97. // Scale it by Size, and Taper the scaling
  98. v.Z *= size.Z;
  99. v.X *= (size.X * ((taperTopFactorX + taperBotFactorX) /2));
  100. v.Y *= (size.Y * ((taperTopFactorY + taperBotFactorY) / 2));
  101. v.X += (pushX / 2) * size.X;
  102. v.Y += (pushY / 2) * size.Y;
  103. //Push the top of the object over by the Top Shear amount
  104. if (twistMid != 0)
  105. {
  106. // twist and shout
  107. tt = new Quaternion(new Vertex(0, 0, 1), twistMid);
  108. v2 = v * tt;
  109. v.X = v2.X;
  110. v.Y = v2.Y;
  111. v.Z = v2.Z;
  112. }
  113. }
  114. foreach (Vertex v in workingMinus.vertices)
  115. {
  116. if (v == null)
  117. continue;
  118. // This is the bottom
  119. v.Z = -.5f;
  120. v.X *= (size.X * taperBotFactorX);
  121. v.Y *= (size.Y * taperBotFactorY);
  122. v.Z *= size.Z;
  123. if (twistBot != 0)
  124. {
  125. // twist and shout
  126. tt = new Quaternion(new Vertex(0, 0, 1), twistBot);
  127. v2 = v * tt;
  128. v.X = v2.X;
  129. v.Y = v2.Y;
  130. v.Z = v2.Z;
  131. }
  132. }
  133. foreach (Triangle t in workingMinus.triangles)
  134. {
  135. t.invertNormal();
  136. }
  137. result.Append(workingMinus);
  138. result.Append(workingMiddle);
  139. int iLastNull = 0;
  140. for (int i = 0; i < workingMiddle.vertices.Count; i++)
  141. {
  142. int iNext = (i + 1);
  143. if (workingMiddle.vertices[i] == null) // Can't make a simplex here
  144. {
  145. iLastNull = i + 1;
  146. continue;
  147. }
  148. if (i == workingMiddle.vertices.Count - 1) // End of list
  149. {
  150. iNext = iLastNull;
  151. }
  152. if (workingMiddle.vertices[iNext] == null) // Null means wrap to begin of last segment
  153. {
  154. iNext = iLastNull;
  155. }
  156. Triangle tSide;
  157. tSide = new Triangle(workingMiddle.vertices[i], workingMinus.vertices[i], workingMiddle.vertices[iNext]);
  158. result.Add(tSide);
  159. tSide =
  160. new Triangle(workingMiddle.vertices[iNext], workingMinus.vertices[i], workingMinus.vertices[iNext]);
  161. result.Add(tSide);
  162. }
  163. //foreach (Triangle t in workingPlus.triangles)
  164. //{
  165. //t.invertNormal();
  166. // }
  167. result.Append(workingPlus);
  168. iLastNull = 0;
  169. for (int i = 0; i < workingPlus.vertices.Count; i++)
  170. {
  171. int iNext = (i + 1);
  172. if (workingPlus.vertices[i] == null) // Can't make a simplex here
  173. {
  174. iLastNull = i + 1;
  175. continue;
  176. }
  177. if (i == workingPlus.vertices.Count - 1) // End of list
  178. {
  179. iNext = iLastNull;
  180. }
  181. if (workingPlus.vertices[iNext] == null) // Null means wrap to begin of last segment
  182. {
  183. iNext = iLastNull;
  184. }
  185. Triangle tSide;
  186. tSide = new Triangle(workingPlus.vertices[i], workingMiddle.vertices[i], workingPlus.vertices[iNext]);
  187. result.Add(tSide);
  188. tSide =
  189. new Triangle(workingPlus.vertices[iNext], workingMiddle.vertices[i], workingMiddle.vertices[iNext]);
  190. result.Add(tSide);
  191. }
  192. if (twistMid != 0)
  193. {
  194. foreach (Vertex v in result.vertices)
  195. {
  196. // twist and shout
  197. if (v != null)
  198. {
  199. tt = new Quaternion(new Vertex(0, 0, -1), twistMid*2);
  200. v2 = v * tt;
  201. v.X = v2.X;
  202. v.Y = v2.Y;
  203. v.Z = v2.Z;
  204. }
  205. }
  206. }
  207. return result;
  208. }
  209. public Mesh ExtrudeCircularPath(Mesh m)
  210. {
  211. //startParameter = float.MinValue;
  212. //stopParameter = float.MaxValue;
  213. // Currently only works for iSteps=1;
  214. Mesh result = new Mesh();
  215. Quaternion tt = new Quaternion();
  216. Vertex v2 = new Vertex(0, 0, 0);
  217. Mesh newLayer;
  218. Mesh lastLayer = null;
  219. int start = 0;
  220. int step;
  221. int steps = 24;
  222. float twistTotal = twistTop - twistBot;
  223. if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 1.5) steps *= 2;
  224. if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 3.0) steps *= 2;
  225. double percentOfPathMultiplier = 1.0 / steps;
  226. double angleStepMultiplier = System.Math.PI * 2.0 / steps;
  227. //System.Console.WriteLine("twistTop: " + twistTop.ToString() + " twistbot: " + twistBot.ToString() + " twisttotal: " + twistTotal.ToString());
  228. float yPathScale = pathScaleY * 0.5f;
  229. float skewStart = -skew;
  230. float skewOffset = 0.0f;
  231. float totalSkew = skew * 2.0f;
  232. float startAngle = (float)(System.Math.PI * 2.0 * pathCutBegin * revolutions);
  233. float endAngle = (float)(System.Math.PI * 2.0 * pathCutEnd * revolutions);
  234. float stepSize = (float)0.2617993878; // 2*PI / 24 segments
  235. step = (int)(startAngle / stepSize);
  236. float angle = startAngle;
  237. float xProfileScale = 1.0f;
  238. float yProfileScale = 1.0f;
  239. //System.Console.WriteLine("startAngle: " + startAngle.ToString() + " endAngle: " + endAngle.ToString() + " step: " + step.ToString());
  240. bool done = false;
  241. //System.Console.WriteLine(" PathScaleX: " + pathScaleX.ToString() + " pathScaleY: " + pathScaleY.ToString());
  242. //System.Console.WriteLine("taperBotFactorX: " + taperBotFactorX.ToString() + " taperBotFactorY: " + taperBotFactorY.ToString()
  243. // + " taperTopFactorX: " + taperTopFactorX.ToString() + " taperTopFactorY: " + taperTopFactorY.ToString());
  244. do
  245. {
  246. float percentOfPath = 1.0f;
  247. percentOfPath = (angle - startAngle) / (endAngle - startAngle); // endAngle should always be larger than startAngle
  248. // System.Console.WriteLine("angle: " + angle.ToString() + " percentOfPath: " + percentOfPath.ToString());
  249. if (pathTaperX > 0.001f) // can't really compare to 0.0f as the value passed is never exactly zero
  250. xProfileScale = 1.0f - percentOfPath * pathTaperX;
  251. else if (pathTaperX < -0.001f)
  252. xProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperX;
  253. else xProfileScale = 1.0f;
  254. if (pathTaperY > 0.001f)
  255. yProfileScale = 1.0f - percentOfPath * pathTaperY;
  256. else if (pathTaperY < -0.001f)
  257. yProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperY;
  258. else yProfileScale = 1.0f;
  259. float radiusScale;
  260. if (radius > 0.001f)
  261. radiusScale = 1.0f - radius * percentOfPath;
  262. else if (radius < 0.001f)
  263. radiusScale = 1.0f + radius * (1.0f - percentOfPath);
  264. else radiusScale = 1.0f;
  265. //radiusScale = 1.0f;
  266. //System.Console.WriteLine("Extruder: radius: " + radius.ToString() + " radiusScale: " + radiusScale.ToString());
  267. float twist = twistBot + (twistTotal * (float)percentOfPath);
  268. float zOffset = (float)(System.Math.Sin(angle) * (0.5f - yPathScale)) * radiusScale;
  269. float yOffset = (float)(System.Math.Cos(angle) * (0.5f - yPathScale)) * radiusScale;
  270. float xOffset = 0.5f * (skewStart + totalSkew * (float)percentOfPath);
  271. newLayer = m.Clone();
  272. Vertex vTemp = new Vertex(0.0f, 0.0f, 0.0f);
  273. if (twistTotal != 0.0f || twistBot != 0.0f)
  274. {
  275. Quaternion profileRot = new Quaternion(new Vertex(0.0f, 0.0f, -1.0f), twist);
  276. foreach (Vertex v in newLayer.vertices)
  277. {
  278. if (v != null)
  279. {
  280. vTemp = v * profileRot;
  281. v.X = vTemp.X;
  282. v.Y = vTemp.Y;
  283. v.Z = vTemp.Z;
  284. }
  285. }
  286. }
  287. Quaternion layerRot = new Quaternion(new Vertex(-1.0f, 0.0f, 0.0f), (float)angle);
  288. foreach (Vertex v in newLayer.vertices)
  289. {
  290. if (v != null)
  291. {
  292. vTemp = v * layerRot;
  293. v.X = xProfileScale * vTemp.X + xOffset;
  294. v.Y = yProfileScale * vTemp.Y + yOffset;
  295. v.Z = vTemp.Z + zOffset;
  296. }
  297. }
  298. if (angle == startAngle) // last layer, invert normals
  299. foreach (Triangle t in newLayer.triangles)
  300. {
  301. t.invertNormal();
  302. }
  303. result.Append(newLayer);
  304. int iLastNull = 0;
  305. if (lastLayer != null)
  306. {
  307. int i, count = newLayer.vertices.Count;
  308. for (i = 0; i < count; i++)
  309. {
  310. int iNext = (i + 1);
  311. if (lastLayer.vertices[i] == null) // cant make a simplex here
  312. iLastNull = i + 1;
  313. else
  314. {
  315. if (i == count - 1) // End of list
  316. iNext = iLastNull;
  317. if (lastLayer.vertices[iNext] == null) // Null means wrap to begin of last segment
  318. iNext = iLastNull;
  319. result.Add(new Triangle(newLayer.vertices[i], lastLayer.vertices[i], newLayer.vertices[iNext]));
  320. result.Add(new Triangle(newLayer.vertices[iNext], lastLayer.vertices[i], lastLayer.vertices[iNext]));
  321. }
  322. }
  323. }
  324. lastLayer = newLayer;
  325. // calc next angle
  326. if (angle >= endAngle)
  327. done = true;
  328. else
  329. {
  330. angle = stepSize * ++step;
  331. if (angle > endAngle)
  332. angle = endAngle;
  333. }
  334. } while (!done);
  335. // scale the mesh to the desired size
  336. float xScale = size.X;
  337. float yScale = size.Y;
  338. float zScale = size.Z;
  339. foreach (Vertex v in result.vertices)
  340. {
  341. if (v != null)
  342. {
  343. v.X *= xScale;
  344. v.Y *= yScale;
  345. v.Z *= zScale;
  346. }
  347. }
  348. return result;
  349. }
  350. }
  351. }