MegaShapeSVG.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. using UnityEngine;
  2. using System;
  3. using System.Collections.Generic;
  4. #if !UNITY_FLASH && !UNITY_METRO && !UNITY_WP8
  5. using System.Text.RegularExpressions;
  6. #endif
  7. // Part of MegaShape?
  8. public class MegaShapeSVG
  9. {
  10. public void LoadXML(string svgdata, MegaShape shape, bool clear, int start)
  11. {
  12. MegaXMLReader xml = new MegaXMLReader();
  13. MegaXMLNode node = xml.read(svgdata);
  14. if ( !clear )
  15. shape.splines.Clear();
  16. shape.selcurve = start;
  17. splineindex = start;
  18. ParseXML(node, shape);
  19. }
  20. int splineindex = 0;
  21. public void ParseXML(MegaXMLNode node, MegaShape shape)
  22. {
  23. foreach ( MegaXMLNode n in node.children )
  24. {
  25. switch ( n.tagName )
  26. {
  27. case "circle": ParseCircle(n, shape); break;
  28. case "path": ParsePath(n, shape); break;
  29. case "ellipse": ParseEllipse(n, shape); break;
  30. case "rect": ParseRect(n, shape); break;
  31. case "polygon": ParsePolygon(n, shape); break;
  32. default: break;
  33. }
  34. ParseXML(n, shape);
  35. }
  36. }
  37. MegaSpline GetSpline(MegaShape shape)
  38. {
  39. MegaSpline spline;
  40. if ( splineindex < shape.splines.Count )
  41. spline = shape.splines[splineindex];
  42. else
  43. {
  44. spline = new MegaSpline();
  45. shape.splines.Add(spline);
  46. }
  47. splineindex++;
  48. return spline;
  49. }
  50. Vector3 SwapAxis(Vector3 val, MegaAxis axis)
  51. {
  52. float v = 0.0f;
  53. switch ( axis )
  54. {
  55. case MegaAxis.X:
  56. v = val.x;
  57. val.x = val.y;
  58. val.y = v;
  59. break;
  60. case MegaAxis.Y:
  61. break;
  62. case MegaAxis.Z:
  63. v = val.y;
  64. val.y = val.z;
  65. val.z = v;
  66. break;
  67. }
  68. return val;
  69. }
  70. void AddKnot(MegaSpline spline, Vector3 p, Vector3 invec, Vector3 outvec, MegaAxis axis)
  71. {
  72. spline.AddKnot(SwapAxis(p, axis), SwapAxis(invec, axis), SwapAxis(outvec, axis));
  73. }
  74. void ParseCircle(MegaXMLNode node, MegaShape shape)
  75. {
  76. MegaSpline spline = GetSpline(shape);
  77. float cx = 0.0f;
  78. float cy = 0.0f;
  79. float r = 0.0f;
  80. for ( int i = 0; i < node.values.Count; i++ )
  81. {
  82. MegaXMLValue val = node.values[i];
  83. switch ( val.name )
  84. {
  85. case "cx": cx = float.Parse(val.value); break;
  86. case "cy": cy = float.Parse(val.value); break;
  87. case "r": r = float.Parse(val.value); break;
  88. }
  89. }
  90. float vector = CIRCLE_VECTOR_LENGTH * r;
  91. spline.knots.Clear();
  92. for ( int ix = 0; ix < 4; ++ix )
  93. {
  94. float angle = (Mathf.PI * 2.0f) * (float)ix / (float)4;
  95. float sinfac = Mathf.Sin(angle);
  96. float cosfac = Mathf.Cos(angle);
  97. Vector3 p = new Vector3((cosfac * r) + cx, 0.0f, (sinfac * r) + cy);
  98. Vector3 rotvec = new Vector3(sinfac * vector, 0.0f, -cosfac * vector);
  99. //spline.AddKnot(p, p + rotvec, p - rotvec);
  100. AddKnot(spline, p, p + rotvec, p - rotvec, shape.axis);
  101. }
  102. spline.closed = true;
  103. }
  104. void ParseEllipse(MegaXMLNode node, MegaShape shape)
  105. {
  106. MegaSpline spline = GetSpline(shape);
  107. float cx = 0.0f;
  108. float cy = 0.0f;
  109. float rx = 0.0f;
  110. float ry = 0.0f;
  111. for ( int i = 0; i < node.values.Count; i++ )
  112. {
  113. MegaXMLValue val = node.values[i];
  114. switch ( val.name )
  115. {
  116. case "cx": cx = float.Parse(val.value); break;
  117. case "cy": cy = float.Parse(val.value); break;
  118. case "rx": rx = float.Parse(val.value); break;
  119. case "ry": ry = float.Parse(val.value); break;
  120. }
  121. }
  122. ry = Mathf.Clamp(ry, 0.0f, float.MaxValue);
  123. rx = Mathf.Clamp(rx, 0.0f, float.MaxValue);
  124. float radius, xmult, ymult;
  125. if ( ry < rx )
  126. {
  127. radius = rx;
  128. xmult = 1.0f;
  129. ymult = ry / rx;
  130. }
  131. else
  132. {
  133. if ( rx < ry )
  134. {
  135. radius = ry;
  136. xmult = rx / ry;
  137. ymult = 1.0f;
  138. }
  139. else
  140. {
  141. radius = ry;
  142. xmult = ymult = 1.0f;
  143. }
  144. }
  145. float vector = CIRCLE_VECTOR_LENGTH * radius;
  146. Vector3 mult = new Vector3(xmult, ymult, 1.0f);
  147. for ( int ix = 0; ix < 4; ++ix )
  148. {
  149. float angle = 6.2831853f * (float)ix / 4.0f;
  150. float sinfac = Mathf.Sin(angle);
  151. float cosfac = Mathf.Cos(angle);
  152. Vector3 p = new Vector3(cosfac * radius + cx, 0.0f, sinfac * radius + cy);
  153. Vector3 rotvec = new Vector3(sinfac * vector, 0.0f, -cosfac * vector);
  154. //spline.AddKnot(Vector3.Scale(p, mult), Vector3.Scale((p + rotvec), mult), Vector3.Scale((p - rotvec), mult)); //, tm);
  155. AddKnot(spline, Vector3.Scale(p, mult), Vector3.Scale((p + rotvec), mult), Vector3.Scale((p - rotvec), mult), shape.axis); //, tm);
  156. }
  157. spline.closed = true;
  158. }
  159. void ParseRect(MegaXMLNode node, MegaShape shape)
  160. {
  161. MegaSpline spline = GetSpline(shape);
  162. Vector3[] ppoints = new Vector3[4];
  163. float w = 0.0f;
  164. float h = 0.0f;
  165. float x = 0.0f;
  166. float y = 0.0f;
  167. for ( int i = 0; i < node.values.Count; i++ )
  168. {
  169. MegaXMLValue val = node.values[i];
  170. switch ( val.name )
  171. {
  172. case "x": x = float.Parse(val.value); break;
  173. case "y": y = float.Parse(val.value); break;
  174. case "width": w = float.Parse(val.value); break;
  175. case "height": h = float.Parse(val.value); break;
  176. case "transform": Debug.Log("SVG Transform not implemented yet");
  177. break;
  178. }
  179. }
  180. ppoints[0] = new Vector3(x, 0.0f, y);
  181. ppoints[1] = new Vector3(x, 0.0f, y + h);
  182. ppoints[2] = new Vector3(x + w, 0.0f, y + h);
  183. ppoints[3] = new Vector3(x + w, 0.0f, y);
  184. spline.closed = true;
  185. spline.knots.Clear();
  186. //spline.AddKnot(ppoints[0], ppoints[0], ppoints[0]);
  187. //spline.AddKnot(ppoints[1], ppoints[1], ppoints[1]);
  188. //spline.AddKnot(ppoints[2], ppoints[2], ppoints[2]);
  189. //spline.AddKnot(ppoints[3], ppoints[3], ppoints[3]);
  190. AddKnot(spline, ppoints[0], ppoints[0], ppoints[0], shape.axis);
  191. AddKnot(spline, ppoints[1], ppoints[1], ppoints[1], shape.axis);
  192. AddKnot(spline, ppoints[2], ppoints[2], ppoints[2], shape.axis);
  193. AddKnot(spline, ppoints[3], ppoints[3], ppoints[3], shape.axis);
  194. }
  195. void ParsePolygon(MegaXMLNode node, MegaShape shape)
  196. {
  197. MegaSpline spline = GetSpline(shape);
  198. spline.knots.Clear();
  199. spline.closed = true;
  200. char[] charSeparators = new char[] { ' ' };
  201. for ( int i = 0; i < node.values.Count; i++ )
  202. {
  203. MegaXMLValue val = node.values[i];
  204. switch ( val.name )
  205. {
  206. case "points":
  207. string[] coordinates = val.value.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
  208. for ( int j = 0; j < coordinates.Length; j++ )
  209. {
  210. Vector3 p = ParseV2Split(coordinates[j], 0);
  211. MegaKnot k = new MegaKnot();
  212. k.p = SwapAxis(new Vector3(p.x, 0.0f, p.y), shape.axis);
  213. k.invec = k.p;
  214. k.outvec = k.p;
  215. spline.knots.Add(k);
  216. }
  217. break;
  218. }
  219. }
  220. if ( spline.closed )
  221. {
  222. Vector3 delta1 = spline.knots[0].outvec - spline.knots[0].p;
  223. spline.knots[0].invec = spline.knots[0].p - delta1;
  224. }
  225. }
  226. char[] commaspace = new char[] { ',', ' ' };
  227. void ParsePath(MegaXMLNode node, MegaShape shape)
  228. {
  229. Vector3 cp = Vector3.zero;
  230. Vector2 cP1;
  231. Vector2 cP2;
  232. char[] charSeparators = new char[] { ',', ' ' };
  233. MegaSpline spline = null;
  234. MegaKnot k;
  235. string[] coord;
  236. for ( int i = 0; i < node.values.Count; i++ )
  237. {
  238. MegaXMLValue val = node.values[i];
  239. //Debug.Log("val name " + val.name);
  240. switch ( val.name )
  241. {
  242. case "d":
  243. #if UNITY_FLASH || UNITY_WP8 || UNITY_METRO
  244. string[] coordinates = null; //string.Split(val.value, @"(?=[MmLlCcSsZzHhVv])");
  245. #else
  246. string[] coordinates = Regex.Split(val.value, @"(?=[MmLlCcSsZzHhVv])");
  247. #endif
  248. for ( int j = 0; j < coordinates.Length; j++ )
  249. {
  250. if ( coordinates[j].Length > 0 )
  251. {
  252. string v = coordinates[j].Substring(1);
  253. if ( v != null && v.Length > 0 )
  254. {
  255. //v = v.Replace("-", ",-");
  256. while ( v.Length > 0 && (v[0] == ',' || v[0] == ' ') )
  257. v = v.Substring(1);
  258. }
  259. switch ( coordinates[j][0] )
  260. {
  261. case 'Z':
  262. case 'z':
  263. if ( spline != null )
  264. {
  265. spline.closed = true;
  266. #if false
  267. Vector3 delta1 = spline.knots[0].outvec - spline.knots[0].p;
  268. spline.knots[0].invec = spline.knots[0].p - delta1;
  269. if ( spline.knots[0].p == spline.knots[spline.knots.Count - 1].p )
  270. spline.knots.Remove(spline.knots[spline.knots.Count - 1]);
  271. #else
  272. int kc = spline.knots.Count - 1;
  273. spline.knots[0].invec = spline.knots[kc].invec;
  274. spline.knots.Remove(spline.knots[kc]);
  275. #endif
  276. }
  277. break;
  278. case 'M':
  279. spline = GetSpline(shape);
  280. spline.knots.Clear();
  281. cp = ParseV2Split(v, 0);
  282. k = new MegaKnot();
  283. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  284. k.invec = k.p;
  285. k.outvec = k.p;
  286. spline.knots.Add(k);
  287. break;
  288. case 'm':
  289. spline = GetSpline(shape);
  290. spline.knots.Clear();
  291. //Debug.Log("v: " + v);
  292. coord = v.Split(" "[0]);
  293. //Debug.Log("m coords " + coord.Length);
  294. //Debug.Log("v2 " + coord[0]);
  295. for ( int k0 = 0; k0 < coord.Length - 1; k0 = k0 + 1 )
  296. {
  297. //Debug.Log("v2 " + coord[k0]);
  298. Vector3 cp1 = ParseV2Split(coord[k0], 0);
  299. //Debug.Log("cp1 " + cp1);
  300. cp.x += cp1.x; //ParseV2Split(coord[k0], 0); // ParseV2(coord, k0);
  301. cp.y += cp1.y;
  302. k = new MegaKnot();
  303. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  304. k.invec = k.p;
  305. k.outvec = k.p;
  306. spline.knots.Add(k);
  307. }
  308. #if false
  309. Vector3 cp1 = ParseV2Split(v, 0);
  310. cp.x += cp1.x;
  311. cp.y += cp1.y;
  312. k = new MegaKnot();
  313. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  314. k.invec = k.p;
  315. k.outvec = k.p;
  316. spline.knots.Add(k);
  317. #endif
  318. break;
  319. case 'l':
  320. //coord = v.Split(","[0]);
  321. coord = v.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
  322. for ( int k0 = 0; k0 < coord.Length; k0 = k0 + 2 )
  323. cp += ParseV2(coord, k0);
  324. spline.knots[spline.knots.Count - 1].outvec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  325. k = new MegaKnot();
  326. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  327. k.invec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  328. k.outvec = k.p - (k.invec - k.p);
  329. spline.knots.Add(k);
  330. break;
  331. case 'c':
  332. coord = v.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
  333. for ( int k2 = 0; k2 < coord.Length; k2 += 6 )
  334. {
  335. cP1 = cp + ParseV2(coord, k2);
  336. cP2 = cp + ParseV2(coord, k2 + 2);
  337. cp += ParseV2(coord, k2 + 4);
  338. spline.knots[spline.knots.Count - 1].outvec = SwapAxis(new Vector3(cP1.x, 0.0f, cP1.y), shape.axis);
  339. k = new MegaKnot();
  340. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  341. k.invec = SwapAxis(new Vector3(cP2.x, 0.0f, cP2.y), shape.axis);
  342. k.outvec = k.p - (k.invec - k.p);
  343. spline.knots.Add(k);
  344. }
  345. break;
  346. case 'L':
  347. //coord = v.Split(","[0]);
  348. coord = v.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
  349. //Debug.Log("v " + v);
  350. //Debug.Log("coords " + coord.Length);
  351. for ( int k3 = 0; k3 < coord.Length; k3 = k3 + 2 )
  352. cp = ParseV2(coord, k3);
  353. spline.knots[spline.knots.Count - 1].outvec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  354. k = new MegaKnot();
  355. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  356. k.invec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  357. k.outvec = k.p - (k.invec - k.p);
  358. spline.knots.Add(k);
  359. break;
  360. case 'v':
  361. //Debug.Log("v: " + v);
  362. coord = v.Split(","[0]);
  363. for ( int k4 = 0; k4 < coord.Length; k4++ )
  364. cp.y += float.Parse(coord[k4]);
  365. spline.knots[spline.knots.Count - 1].outvec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  366. k = new MegaKnot();
  367. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  368. k.invec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  369. k.outvec = k.p - (k.invec - k.p);
  370. spline.knots.Add(k);
  371. break;
  372. case 'V':
  373. //coord = v.Split(","[0]);
  374. coord = v.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
  375. for ( int k9 = 0; k9 < coord.Length; k9++ )
  376. cp.y = float.Parse(coord[k9]);
  377. spline.knots[spline.knots.Count - 1].outvec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  378. k = new MegaKnot();
  379. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  380. k.invec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  381. k.outvec = k.p - (k.invec - k.p);
  382. spline.knots.Add(k);
  383. break;
  384. case 'h':
  385. //coord = v.Split(","[0]);
  386. coord = v.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
  387. for ( int k5 = 0; k5 < coord.Length; k5++ )
  388. cp.x += float.Parse(coord[k5]);
  389. spline.knots[spline.knots.Count - 1].outvec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  390. k = new MegaKnot();
  391. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  392. k.invec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  393. k.outvec = k.p - (k.invec - k.p);
  394. spline.knots.Add(k);
  395. break;
  396. case 'H':
  397. coord = v.Split(","[0]);
  398. for ( int k6 = 0; k6 < coord.Length; k6++ )
  399. cp.x = float.Parse(coord[k6]);
  400. spline.knots[spline.knots.Count - 1].outvec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  401. k = new MegaKnot();
  402. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  403. k.invec = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  404. k.outvec = k.p - (k.invec - k.p);
  405. spline.knots.Add(k);
  406. break;
  407. case 'S':
  408. //coord = v.Split(","[0]);
  409. coord = v.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
  410. for ( int k7 = 0; k7 < coord.Length; k7 = k7 + 4 )
  411. {
  412. cp = ParseV2(coord, k7 + 2);
  413. cP1 = ParseV2(coord, k7);
  414. k = new MegaKnot();
  415. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  416. k.invec = SwapAxis(new Vector3(cP1.x, 0.0f, cP1.y), shape.axis);
  417. k.outvec = k.p - (k.invec - k.p);
  418. spline.knots.Add(k);
  419. }
  420. break;
  421. case 's':
  422. coord = v.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
  423. for ( int k7 = 0; k7 < coord.Length; k7 = k7 + 4 )
  424. {
  425. cP1 = cp + ParseV2(coord, k7);
  426. cp += ParseV2(coord, k7 + 2);
  427. k = new MegaKnot();
  428. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  429. k.invec = SwapAxis(new Vector3(cP1.x, 0.0f, cP1.y), shape.axis);
  430. k.outvec = k.p - (k.invec - k.p);
  431. spline.knots.Add(k);
  432. }
  433. break;
  434. case 'C':
  435. //Debug.Log("v " + v);
  436. coord = v.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
  437. //Debug.Log("crds " + coord.Length);
  438. for ( int k2 = 0; k2 < coord.Length; k2 += 6 )
  439. {
  440. cP1 = ParseV2(coord, k2);
  441. cP2 = ParseV2(coord, k2 + 2);
  442. cp = ParseV2(coord, k2 + 4);
  443. spline.knots[spline.knots.Count - 1].outvec = SwapAxis(new Vector3(cP1.x, 0.0f, cP1.y), shape.axis);
  444. k = new MegaKnot();
  445. k.p = SwapAxis(new Vector3(cp.x, 0.0f, cp.y), shape.axis);
  446. k.invec = SwapAxis(new Vector3(cP2.x, 0.0f, cP2.y), shape.axis);
  447. k.outvec = k.p - (k.invec - k.p);
  448. spline.knots.Add(k);
  449. }
  450. break;
  451. default:
  452. break;
  453. }
  454. }
  455. }
  456. break;
  457. }
  458. }
  459. }
  460. public void importData(string svgdata, MegaShape shape, float scale, bool clear, int start)
  461. {
  462. LoadXML(svgdata, shape, clear, start);
  463. for ( int i = start; i < splineindex; i++ )
  464. {
  465. float area = shape.splines[i].Area();
  466. if ( area < 0.0f )
  467. shape.splines[i].reverse = false;
  468. else
  469. shape.splines[i].reverse = true;
  470. }
  471. //shape.Centre(0.01f, new Vector3(-1.0f, 1.0f, 1.0f));
  472. //shape.Centre(scale, new Vector3(-1.0f, 1.0f, 1.0f), start);
  473. shape.CoordAdjust(scale, new Vector3(-1.0f, 1.0f, 1.0f), start);
  474. shape.CalcLength(); //10);
  475. }
  476. const float CIRCLE_VECTOR_LENGTH = 0.5517861843f;
  477. Vector2 ParseV2Split(string str, int i)
  478. {
  479. return ParseV2(str.Split(commaspace, StringSplitOptions.RemoveEmptyEntries), i);
  480. }
  481. Vector3 ParseV2(string[] str, int i)
  482. {
  483. //Debug.Log("pv2 " + str[i] + " " + str[i + 1]);
  484. Vector3 p = Vector2.zero;
  485. p.x = float.Parse(str[i]);
  486. p.y = float.Parse(str[i + 1]);
  487. return p;
  488. }
  489. static public string Export(MegaShape shape, int x, int y, float strokewidth, Color col)
  490. {
  491. string file = "";
  492. Color32 c = col;
  493. file += "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
  494. file += "<!-- MegaShapes SVG Exporter v1.0 -->\n";
  495. file += "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
  496. file += "<svg version=\"1.1\" id=\"" + shape.name + "\" x=\"0px\" y=\"0px\" width=\"640.0px\" height=\"480.0px\">\n";
  497. for ( int i = 0; i < shape.splines.Count; i++ )
  498. {
  499. MegaSpline spline = shape.splines[i];
  500. file += "<path d=\"";
  501. MegaKnot k1;
  502. MegaKnot k = spline.knots[0];
  503. k1 = k;
  504. file += "M" + k.p[x] + "," + -k.p[y];
  505. //Vector3 cp = k.p;
  506. for ( int j = 1; j < spline.knots.Count; j++ )
  507. {
  508. k = spline.knots[j];
  509. Vector3 po = k1.outvec; // - cp; // - k1.p;
  510. Vector3 pi = k.invec; // - cp; // - k.p;
  511. Vector3 kp = k.p; // - cp;
  512. kp[y] = -kp[y];
  513. po[y] = -po[y];
  514. pi[y] = -pi[y];
  515. file += "C" + po[x] + "," + po[y];
  516. file += " " + pi[x] + "," + pi[y];
  517. file += " " + kp[x] + "," + kp[y];
  518. k1 = k;
  519. }
  520. if ( spline.closed )
  521. {
  522. file += "z\"";
  523. }
  524. file += " fill=\"none\"";
  525. file += " stroke=\"#" + c.r.ToString("x") + c.g.ToString("x") + c.b.ToString("x") + "\"";
  526. file += " stroke-width=\"" + strokewidth + "\"";
  527. file += "/>\n";
  528. }
  529. file += "</svg>\n";
  530. return file;
  531. }
  532. }