not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

727 lines
24 KiB

  1. // Generated by CoffeeScript 1.6.3
  2. (function() {
  3. "use strict";
  4. var ArcSegment, LineSegment, Point, Util,
  5. __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
  6. __hasProp = {}.hasOwnProperty,
  7. __slice = [].slice;
  8. window.gearsketch = {};
  9. Point = (function() {
  10. function Point(x, y) {
  11. this.x = x;
  12. this.y = y;
  13. }
  14. Point.prototype.plus = function(p) {
  15. return new Point(this.x + p.x, this.y + p.y);
  16. };
  17. Point.prototype.minus = function(p) {
  18. return new Point(this.x - p.x, this.y - p.y);
  19. };
  20. Point.prototype.times = function(n) {
  21. return new Point(n * this.x, n * this.y);
  22. };
  23. Point.prototype.distance = function(p) {
  24. return Math.sqrt(Math.pow(this.x - p.x, 2) + Math.pow(this.y - p.y, 2));
  25. };
  26. Point.prototype.cross = function(p) {
  27. return this.x * p.y - this.y * p.x;
  28. };
  29. Point.prototype.clone = function() {
  30. return new Point(this.x, this.y);
  31. };
  32. Point.polar = function(theta, r) {
  33. return new Point(r * Math.cos(theta), r * Math.sin(theta));
  34. };
  35. Point.fromObject = function(obj) {
  36. return new Point(obj.x, obj.y);
  37. };
  38. return Point;
  39. })();
  40. window.gearsketch.Point = Point;
  41. ArcSegment = (function() {
  42. function ArcSegment(center, radius, startAngle, endAngle, direction) {
  43. this.center = center;
  44. this.radius = radius;
  45. this.startAngle = startAngle;
  46. this.endAngle = endAngle;
  47. this.direction = direction;
  48. this.start = this.pointOnCircle(startAngle);
  49. this.end = this.pointOnCircle(endAngle);
  50. }
  51. ArcSegment.prototype.getLength = function() {
  52. var angle;
  53. angle = this.direction === Util.Direction.CLOCKWISE ? Util.mod(this.endAngle - this.startAngle, 2 * Math.PI) : Util.mod(this.startAngle - this.endAngle, 2 * Math.PI);
  54. return angle * this.radius;
  55. };
  56. ArcSegment.prototype.findPoint = function(distanceToGo) {
  57. var angle, angleToGo;
  58. angleToGo = distanceToGo / this.radius;
  59. angle = this.startAngle + (this.direction === Util.Direction.CLOCKWISE ? angleToGo : -angleToGo);
  60. return this.center.plus(Point.polar(angle, this.radius));
  61. };
  62. ArcSegment.prototype.pointOnCircle = function(angle) {
  63. return this.center.plus(Point.polar(angle, this.radius));
  64. };
  65. ArcSegment.prototype.containsAngle = function(angle) {
  66. if (this.direction === Util.Direction.CLOCKWISE) {
  67. return Util.mod(this.endAngle - this.startAngle, 2 * Math.PI) > Util.mod(angle - this.startAngle, 2 * Math.PI);
  68. } else {
  69. return Util.mod(this.startAngle - this.endAngle, 2 * Math.PI) > Util.mod(this.startAngle - angle, 2 * Math.PI);
  70. }
  71. };
  72. ArcSegment.prototype.distanceToPoint = function(point) {
  73. var angle;
  74. angle = Math.atan2(point.y - this.center.y, point.x - this.center.x);
  75. if (this.containsAngle(angle)) {
  76. return Math.abs(point.distance(this.center) - this.radius);
  77. } else {
  78. return Math.min(point.distance(this.start), point.distance(this.end));
  79. }
  80. };
  81. ArcSegment.prototype.intersectsLineSegment = function(lineSegment) {
  82. var d, discriminant, dr, dx, dy, i1, i1x, i1y, i2, i2x, i2y, p1, p2;
  83. p1 = lineSegment.start.minus(this.center);
  84. p2 = lineSegment.end.minus(this.center);
  85. dx = p2.x - p1.x;
  86. dy = p2.y - p1.y;
  87. dr = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
  88. if (dr === 0) {
  89. return false;
  90. }
  91. d = p1.x * p2.y - p2.x * p1.y;
  92. discriminant = Math.pow(this.radius, 2) * Math.pow(dr, 2) - Math.pow(d, 2);
  93. if (discriminant < 0) {
  94. return false;
  95. } else {
  96. i1x = (d * dy + Util.sign(dy) * dx * Math.sqrt(discriminant)) / Math.pow(dr, 2);
  97. i1y = (-d * dx + Math.abs(dy) * Math.sqrt(discriminant)) / Math.pow(dr, 2);
  98. i1 = new Point(i1x, i1y).plus(this.center);
  99. if (lineSegment.distanceToPoint(i1) < Util.EPSILON && this.distanceToPoint(i1) < Util.EPSILON) {
  100. return true;
  101. }
  102. i2x = (d * dy - Util.sign(dy) * dx * Math.sqrt(discriminant)) / Math.pow(dr, 2);
  103. i2y = (-d * dx - Math.abs(dy) * Math.sqrt(discriminant)) / Math.pow(dr, 2);
  104. i2 = new Point(i2x, i2y).plus(this.center);
  105. if (lineSegment.distanceToPoint(i2) < Util.EPSILON && this.distanceToPoint(i2) < Util.EPSILON) {
  106. return true;
  107. }
  108. return false;
  109. }
  110. };
  111. ArcSegment.prototype.distanceToSegment = function(segment) {
  112. var angle1, angle2, centerDistance, pointNearestToCenter;
  113. if (segment instanceof ArcSegment) {
  114. if (this.center.distance(segment.center) > Util.EPSILON) {
  115. angle1 = Math.atan2(segment.center.y - this.center.y, segment.center.x - this.center.x);
  116. angle2 = Util.mod(angle1 + Math.PI, 2 * Math.PI);
  117. if (this.containsAngle(angle1) && segment.containsAngle(angle2)) {
  118. centerDistance = this.center.distance(segment.center);
  119. return Math.max(0, centerDistance - this.radius - segment.radius);
  120. }
  121. }
  122. return Math.min(this.distanceToPoint(segment.start), this.distanceToPoint(segment.end), segment.distanceToPoint(this.start), segment.distanceToPoint(this.end));
  123. } else {
  124. if (this.intersectsLineSegment(segment)) {
  125. return 0;
  126. } else {
  127. pointNearestToCenter = segment.findNearestPoint(this.center);
  128. return Math.min(this.distanceToPoint(pointNearestToCenter), this.distanceToPoint(segment.start), this.distanceToPoint(segment.end), segment.distanceToPoint(this.start), segment.distanceToPoint(this.end));
  129. }
  130. }
  131. };
  132. ArcSegment.prototype.clone = function() {
  133. return new ArcSegment(this.center.clone(), this.radius, this.startAngle, this.endAngle, this.direction);
  134. };
  135. ArcSegment.fromObject = function(obj) {
  136. return new ArcSegment(Point.fromObject(obj.center), obj.radius, obj.startAngle, obj.endAngle, obj.direction);
  137. };
  138. return ArcSegment;
  139. })();
  140. window.gearsketch.ArcSegment = ArcSegment;
  141. LineSegment = (function() {
  142. function LineSegment(start, end) {
  143. this.start = start;
  144. this.end = end;
  145. }
  146. LineSegment.prototype.getLength = function() {
  147. return this.start.distance(this.end);
  148. };
  149. LineSegment.prototype.findPoint = function(distanceToGo) {
  150. var fraction;
  151. fraction = distanceToGo / this.start.distance(this.end);
  152. return this.start.plus(this.end.minus(this.start).times(fraction));
  153. };
  154. LineSegment.prototype.findNearestPoint = function(p) {
  155. var segmentLength, t;
  156. segmentLength = this.getLength();
  157. if (segmentLength === 0) {
  158. return this.start;
  159. } else {
  160. t = ((p.x - this.start.x) * (this.end.x - this.start.x) + (p.y - this.start.y) * (this.end.y - this.start.y)) / Math.pow(segmentLength, 2);
  161. if (t < 0) {
  162. return this.start;
  163. } else if (t > 1) {
  164. return this.end;
  165. } else {
  166. return this.start.plus(this.end.minus(this.start).times(t));
  167. }
  168. }
  169. };
  170. LineSegment.prototype.distanceToPoint = function(point) {
  171. return point.distance(this.findNearestPoint(point));
  172. };
  173. LineSegment.prototype.findIntersection = function(lineSegment) {
  174. var crossRS, p, q, r, s, t, u;
  175. p = this.start;
  176. r = this.end.minus(p);
  177. q = lineSegment.start;
  178. s = lineSegment.end.minus(q);
  179. crossRS = r.cross(s);
  180. t = q.minus(p).cross(s) / crossRS;
  181. u = q.minus(p).cross(r) / crossRS;
  182. if (Math.abs(crossRS) > Util.EPSILON && 0 <= t && t <= 1 && 0 <= u && u <= 1) {
  183. return p.plus(r.times(t));
  184. } else {
  185. return null;
  186. }
  187. };
  188. LineSegment.prototype.distanceToSegment = function(segment) {
  189. if (segment instanceof LineSegment) {
  190. if (this.findIntersection(segment)) {
  191. return 0;
  192. } else {
  193. return Math.min(this.distanceToPoint(segment.start), this.distanceToPoint(segment.end), segment.distanceToPoint(this.start), segment.distanceToPoint(this.end));
  194. }
  195. } else {
  196. return segment.distanceToSegment(this);
  197. }
  198. };
  199. LineSegment.prototype.clone = function() {
  200. return new LineSegment(this.start.clone(), this.end.clone());
  201. };
  202. LineSegment.fromObject = function(obj) {
  203. return new LineSegment(Point.fromObject(obj.start), Point.fromObject(obj.end));
  204. };
  205. return LineSegment;
  206. })();
  207. window.gearsketch.LineSegment = LineSegment;
  208. Util = (function() {
  209. function Util() {}
  210. Point = window.gearsketch.Point;
  211. Util.MODULE = 6;
  212. Util.AXIS_RADIUS = 1.5 * Util.MODULE;
  213. Util.MIN_STACKED_GEARS_TEETH_DIFFERENCE = 4;
  214. Util.SNAPPING_DISTANCE = 2 * Util.MODULE;
  215. Util.EPSILON = 0.000001;
  216. Util.Direction = {
  217. CLOCKWISE: "clockwise",
  218. COUNTER_CLOCKWISE: "counterclockwise"
  219. };
  220. Util.Side = {
  221. LEFT: "left",
  222. RIGHT: "right"
  223. };
  224. Util.clone = function(obj) {
  225. var copy, i, key, knownClasses, _i, _ref, _ref1;
  226. if ((obj == null) || (typeof obj !== "object")) {
  227. return obj;
  228. }
  229. knownClasses = ["Point", "Gear", "ArcSegment", "LineSegment", "Chain"];
  230. if (_ref = obj.constructor.name, __indexOf.call(knownClasses, _ref) >= 0) {
  231. return obj.clone();
  232. }
  233. if (obj instanceof Array) {
  234. copy = [];
  235. for (i = _i = 0, _ref1 = obj.length; 0 <= _ref1 ? _i < _ref1 : _i > _ref1; i = 0 <= _ref1 ? ++_i : --_i) {
  236. copy[i] = this.clone(obj[i]);
  237. }
  238. return copy;
  239. }
  240. if (obj instanceof Object) {
  241. copy = {};
  242. for (key in obj) {
  243. if (!__hasProp.call(obj, key)) continue;
  244. copy[key] = this.clone(obj[key]);
  245. }
  246. return copy;
  247. }
  248. throw new Error("Unable to clone object. Its type is not supported.");
  249. };
  250. Util.createUUID = function() {
  251. return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
  252. var r, v;
  253. r = Math.random() * 16 | 0;
  254. v = c === "x" ? r : r & 0x3 | 0x8;
  255. return v.toString(16);
  256. });
  257. };
  258. Util.mod = function(a, b) {
  259. return (a % b + b) % b;
  260. };
  261. Util.sign = function(x) {
  262. if (x < 0) {
  263. return -1;
  264. } else {
  265. return 1;
  266. }
  267. };
  268. Util.addAll = function(set, elements) {
  269. var element, _i, _len;
  270. for (_i = 0, _len = elements.length; _i < _len; _i++) {
  271. element = elements[_i];
  272. set[element] = true;
  273. }
  274. return set;
  275. };
  276. Util.makeSetFromList = function(elements) {
  277. return this.addAll({}, elements);
  278. };
  279. Util.makeSet = function() {
  280. var elements;
  281. elements = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  282. return this.makeSetFromList(elements);
  283. };
  284. Util.findPointOnPath = function(path, distance) {
  285. var distanceToGo, i, j, numberOfPoints, segment, segmentLength;
  286. distanceToGo = distance;
  287. i = 0;
  288. numberOfPoints = path.length;
  289. while (distanceToGo > 0) {
  290. j = (i + 1) % numberOfPoints;
  291. segment = new LineSegment(path[i], path[j]);
  292. segmentLength = segment.getLength();
  293. if (distanceToGo <= segmentLength) {
  294. return segment.findPoint(distanceToGo);
  295. } else {
  296. i = j;
  297. distanceToGo -= segmentLength;
  298. }
  299. }
  300. return null;
  301. };
  302. Util.getLength = function(path, isPathClosed) {
  303. var finalIndex, i, j, length, numberOfPoints, _i;
  304. if (isPathClosed == null) {
  305. isPathClosed = true;
  306. }
  307. length = 0;
  308. numberOfPoints = path.length;
  309. finalIndex = numberOfPoints - (isPathClosed ? 0 : 1);
  310. for (i = _i = 0; 0 <= finalIndex ? _i < finalIndex : _i > finalIndex; i = 0 <= finalIndex ? ++_i : --_i) {
  311. j = (i + 1) % numberOfPoints;
  312. length += path[i].distance(path[j]);
  313. }
  314. return length;
  315. };
  316. Util.isPointInsidePolygon = function(point, polygon) {
  317. var i, isPointInPolygon, j, numberOfVertices, pix, piy, pjx, pjy, x, y, _i;
  318. isPointInPolygon = false;
  319. x = point.x;
  320. y = point.y;
  321. numberOfVertices = polygon.length;
  322. j = numberOfVertices - 1;
  323. for (i = _i = 0; 0 <= numberOfVertices ? _i < numberOfVertices : _i > numberOfVertices; i = 0 <= numberOfVertices ? ++_i : --_i) {
  324. pix = polygon[i].x;
  325. piy = polygon[i].y;
  326. pjx = polygon[j].x;
  327. pjy = polygon[j].y;
  328. if (((piy > y) !== (pjy > y)) && (x < ((pjx - pix) * (y - piy) / (pjy - piy) + pix))) {
  329. isPointInPolygon = !isPointInPolygon;
  330. }
  331. j = i;
  332. }
  333. return isPointInPolygon;
  334. };
  335. Util.isGearInsidePolygon = function(gear, polygon) {
  336. var edgePointAtAngle, edgePoints, i,
  337. _this = this;
  338. edgePointAtAngle = function(angle) {
  339. return gear.location.plus(Point.polar(angle, gear.innerRadius));
  340. };
  341. edgePoints = (function() {
  342. var _i, _results;
  343. _results = [];
  344. for (i = _i = 0; _i < 8; i = ++_i) {
  345. _results.push(edgePointAtAngle(0.25 * Math.PI * i));
  346. }
  347. return _results;
  348. })();
  349. return edgePoints.every(function(p) {
  350. return _this.isPointInsidePolygon(p, polygon);
  351. });
  352. };
  353. Util.findGearsInsidePolygon = function(polygon, gears) {
  354. var gear, id, _results;
  355. _results = [];
  356. for (id in gears) {
  357. if (!__hasProp.call(gears, id)) continue;
  358. gear = gears[id];
  359. if (this.isGearInsidePolygon(gear, polygon)) {
  360. _results.push(gear);
  361. }
  362. }
  363. return _results;
  364. };
  365. Util.doesGearIntersectLineSegment = function(gear, segment) {
  366. return segment.distanceToPoint(gear.location) < (gear.pitchRadius + Util.EPSILON);
  367. };
  368. Util.findGearsIntersectingSegment = function(gears, segment) {
  369. var gear, id, _results;
  370. _results = [];
  371. for (id in gears) {
  372. if (!__hasProp.call(gears, id)) continue;
  373. gear = gears[id];
  374. if (this.doesGearIntersectLineSegment(gear, segment)) {
  375. _results.push(gear);
  376. }
  377. }
  378. return _results;
  379. };
  380. Util.pointPathDistance = function(point, path, isPathClosed) {
  381. var d, distance, finalIndex, i, j, numberOfPoints, segment, _i;
  382. if (isPathClosed == null) {
  383. isPathClosed = true;
  384. }
  385. distance = Number.MAX_VALUE;
  386. numberOfPoints = path.length;
  387. finalIndex = numberOfPoints - (isPathClosed ? 0 : 1);
  388. for (i = _i = 0; 0 <= finalIndex ? _i < finalIndex : _i > finalIndex; i = 0 <= finalIndex ? ++_i : --_i) {
  389. j = (i + 1) % numberOfPoints;
  390. segment = new LineSegment(path[i], path[j]);
  391. d = Math.max(0, segment.distanceToPoint(point));
  392. distance = Math.min(distance, d);
  393. }
  394. return distance;
  395. };
  396. Util.findNearestIntersectingGear = function(gears, lineSegment, ignoredGearIds) {
  397. var intersectingGear, intersectingGears, _i, _len,
  398. _this = this;
  399. if (ignoredGearIds == null) {
  400. ignoredGearIds = {};
  401. }
  402. intersectingGears = this.findGearsIntersectingSegment(gears, lineSegment);
  403. intersectingGears.sort(function(g1, g2) {
  404. return g1.distanceToPoint(lineSegment.start) - g2.distanceToPoint(lineSegment.start);
  405. });
  406. for (_i = 0, _len = intersectingGears.length; _i < _len; _i++) {
  407. intersectingGear = intersectingGears[_i];
  408. if (!(intersectingGear.id in ignoredGearIds)) {
  409. return intersectingGear;
  410. }
  411. }
  412. return null;
  413. };
  414. Util.findDirection = function(polygon) {
  415. var doubleArea, i, j, numberOfPoints, _i;
  416. numberOfPoints = polygon.length;
  417. doubleArea = 0;
  418. for (i = _i = 0; 0 <= numberOfPoints ? _i < numberOfPoints : _i > numberOfPoints; i = 0 <= numberOfPoints ? ++_i : --_i) {
  419. j = (i + 1) % numberOfPoints;
  420. doubleArea += polygon[i].x * polygon[j].y;
  421. doubleArea -= polygon[i].y * polygon[j].x;
  422. }
  423. if (doubleArea > 0) {
  424. return this.Direction.CLOCKWISE;
  425. } else {
  426. return this.Direction.COUNTER_CLOCKWISE;
  427. }
  428. };
  429. Util.findTangentPoints = function(p, c, r) {
  430. var alpha, beta, d, l, tangentPoints;
  431. tangentPoints = {};
  432. d = p.distance(c);
  433. if (Math.abs(d - r) < Util.EPSILON) {
  434. tangentPoints[this.Side.RIGHT] = p.clone();
  435. tangentPoints[this.Side.LEFT] = p.clone();
  436. } else {
  437. l = Math.sqrt(d * d - r * r);
  438. alpha = Math.atan2(c.y - p.y, c.x - p.x);
  439. beta = Math.asin(r / d);
  440. tangentPoints[this.Side.RIGHT] = p.plus(Point.polar(alpha + beta, l));
  441. tangentPoints[this.Side.LEFT] = p.plus(Point.polar(alpha - beta, l));
  442. }
  443. return tangentPoints;
  444. };
  445. Util.findGearTangentPoints = function(p, gear) {
  446. return this.findTangentPoints(p, gear.location, gear.pitchRadius);
  447. };
  448. Util.findExternalTangents = function(centers, radii) {
  449. var angle, largest, o1, o2, offset1, offset2, r1, r2, r3, ratio, tangentLine1, tangentLine2, tangentLines, tangentPoints, tpl, tpr;
  450. largest = radii[0] >= radii[1] ? 0 : 1;
  451. o1 = centers[largest];
  452. o2 = centers[1 - largest];
  453. r1 = radii[largest];
  454. r2 = radii[1 - largest];
  455. r3 = r1 - r2;
  456. if (r3 === 0) {
  457. tangentPoints = {};
  458. tangentPoints[this.Side.LEFT] = o1;
  459. tangentPoints[this.Side.RIGHT] = o1;
  460. angle = Math.atan2(o2.y - o1.y, o2.x - o1.x);
  461. offset1 = Point.polar(angle + 0.5 * Math.PI, r1);
  462. offset2 = Point.polar(angle - 0.5 * Math.PI, r1);
  463. } else {
  464. tangentPoints = this.findTangentPoints(o2, o1, r3);
  465. ratio = r2 / r3;
  466. tpl = tangentPoints[this.Side.LEFT];
  467. tpr = tangentPoints[this.Side.RIGHT];
  468. offset1 = tpl.minus(o1).times(ratio);
  469. offset2 = tpr.minus(o1).times(ratio);
  470. }
  471. tangentLine1 = [tangentPoints[this.Side.LEFT].plus(offset1), o2.plus(offset1)];
  472. tangentLine2 = [tangentPoints[this.Side.RIGHT].plus(offset2), o2.plus(offset2)];
  473. tangentLines = {};
  474. if (o1 === centers[0]) {
  475. tangentLines[this.Side.RIGHT] = new LineSegment(tangentLine1[0], tangentLine1[1]);
  476. tangentLines[this.Side.LEFT] = new LineSegment(tangentLine2[0], tangentLine2[1]);
  477. } else {
  478. tangentLines[this.Side.RIGHT] = new LineSegment(tangentLine2[1], tangentLine2[0]);
  479. tangentLines[this.Side.LEFT] = new LineSegment(tangentLine1[1], tangentLine1[0]);
  480. }
  481. return tangentLines;
  482. };
  483. Util.findInternalTangents = function(centers, radii) {
  484. var largest, o1, o2, offset1, offset2, r1, r2, r3, ratio, tangentLine1, tangentLine2, tangentLines, tangentPoints, tpl, tpr;
  485. largest = radii[0] >= radii[1] ? 0 : 1;
  486. o1 = centers[largest];
  487. o2 = centers[1 - largest];
  488. r1 = radii[largest];
  489. r2 = radii[1 - largest];
  490. r3 = r1 + r2;
  491. tangentPoints = this.findTangentPoints(o2, o1, r3);
  492. ratio = r2 / r3;
  493. tpl = tangentPoints[this.Side.LEFT];
  494. tpr = tangentPoints[this.Side.RIGHT];
  495. offset1 = o1.minus(tpl).times(ratio);
  496. offset2 = o1.minus(tpr).times(ratio);
  497. tangentLine1 = [tpl.plus(offset1), o2.plus(offset1)];
  498. tangentLine2 = [tpr.plus(offset2), o2.plus(offset2)];
  499. tangentLines = {};
  500. if (o1 === centers[0]) {
  501. tangentLines[this.Side.RIGHT] = new LineSegment(tangentLine1[0], tangentLine1[1]);
  502. tangentLines[this.Side.LEFT] = new LineSegment(tangentLine2[0], tangentLine2[1]);
  503. } else {
  504. tangentLines[this.Side.RIGHT] = new LineSegment(tangentLine1[1], tangentLine1[0]);
  505. tangentLines[this.Side.LEFT] = new LineSegment(tangentLine2[1], tangentLine2[0]);
  506. }
  507. return tangentLines;
  508. };
  509. Util.findExternalTangentsOfGears = function(gear1, gear2) {
  510. return this.findExternalTangents([gear1.location, gear2.location], [gear1.pitchRadius, gear2.pitchRadius]);
  511. };
  512. Util.findInternalTangentsOfGears = function(gear1, gear2) {
  513. return this.findInternalTangents([gear1.location, gear2.location], [gear1.pitchRadius, gear2.pitchRadius]);
  514. };
  515. Util.findTangentLine = function(gear1, gear2, innerGearIds, direction) {
  516. var gear1isInnerGear, side;
  517. gear1isInnerGear = gear1.id in innerGearIds;
  518. if (gear1isInnerGear === (direction === this.Direction.CLOCKWISE)) {
  519. side = this.Side.LEFT;
  520. } else {
  521. side = this.Side.RIGHT;
  522. }
  523. if (gear1isInnerGear === (gear2.id in innerGearIds)) {
  524. return this.findExternalTangentsOfGears(gear1, gear2)[side];
  525. } else {
  526. return this.findInternalTangentsOfGears(gear1, gear2)[side];
  527. }
  528. };
  529. Util.findAllSimplePathsForNodes = function(turningObjects, goalNode, nodesVisited) {
  530. var currentNode, neighbor, neighborId, paths, updatedNodesVisited, _ref;
  531. paths = [];
  532. currentNode = nodesVisited[nodesVisited.length - 1];
  533. _ref = currentNode.connections;
  534. for (neighborId in _ref) {
  535. if (!__hasProp.call(_ref, neighborId)) continue;
  536. neighbor = turningObjects[neighborId];
  537. if (__indexOf.call(nodesVisited, neighbor) < 0) {
  538. updatedNodesVisited = nodesVisited.slice(0);
  539. updatedNodesVisited.push(neighbor);
  540. if (neighbor === goalNode) {
  541. paths.push(updatedNodesVisited);
  542. } else {
  543. paths = paths.concat(this.findAllSimplePathsForNodes(turningObjects, goalNode, updatedNodesVisited));
  544. }
  545. }
  546. }
  547. return paths;
  548. };
  549. Util.findAllSimplePathsBetweenNeighbors = function(turningObjects) {
  550. var i, id, j, nodes, paths, turningObject, _i, _j, _k, _ref, _ref1, _ref2, _ref3;
  551. paths = [];
  552. nodes = (function() {
  553. var _results;
  554. _results = [];
  555. for (id in turningObjects) {
  556. if (!__hasProp.call(turningObjects, id)) continue;
  557. turningObject = turningObjects[id];
  558. _results.push(turningObject);
  559. }
  560. return _results;
  561. })();
  562. if (nodes.length < 2) {
  563. return [];
  564. }
  565. for (i = _i = 0, _ref = nodes.length - 1; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
  566. for (j = _j = _ref1 = i + 1, _ref2 = nodes.length; _ref1 <= _ref2 ? _j < _ref2 : _j > _ref2; j = _ref1 <= _ref2 ? ++_j : --_j) {
  567. if (nodes[i].connections[nodes[j].id] != null) {
  568. paths = paths.concat(this.findAllSimplePathsForNodes(turningObjects, nodes[j], [nodes[i]]));
  569. }
  570. }
  571. }
  572. for (i = _k = 0, _ref3 = paths.length; 0 <= _ref3 ? _k < _ref3 : _k > _ref3; i = 0 <= _ref3 ? ++_k : --_k) {
  573. paths.push(paths[i].slice(0).reverse());
  574. }
  575. return paths;
  576. };
  577. Util.sendGetRequest = function(url) {
  578. var request;
  579. request = new XMLHttpRequest();
  580. request.open("GET", url, false);
  581. request.send(null);
  582. return request.responseText;
  583. };
  584. Util.sendPostRequest = function(data, url, callback) {
  585. var request;
  586. request = new XMLHttpRequest();
  587. request.open("POST", url, true);
  588. request.setRequestHeader("Content-type", "application/json; charset=UTF-8");
  589. request.onload = callback;
  590. return request.send(data);
  591. };
  592. return Util;
  593. })();
  594. window.gearsketch.Util = Util;
  595. (function() {
  596. var lastTime, vendor, vendors, _i, _len;
  597. lastTime = 0;
  598. vendors = ["ms", "moz", "webkit", "o"];
  599. for (_i = 0, _len = vendors.length; _i < _len; _i++) {
  600. vendor = vendors[_i];
  601. if (!(!window.requestAnimationFrame)) {
  602. continue;
  603. }
  604. window.requestAnimationFrame = window[vendor + "RequestAnimationFrame"];
  605. window.cancelAnimationFrame = window[vendor + "CancelAnimationFrame"] || window[vendor + "CancelRequestAnimationFrame"];
  606. }
  607. if (!window.requestAnimationFrame) {
  608. window.requestAnimationFrame = function(callback) {
  609. var currTime, id, timeToCall;
  610. currTime = new Date().getTime();
  611. timeToCall = Math.max(0, 16 - (currTime - lastTime));
  612. id = window.setTimeout((function() {
  613. return callback(currTime + timeToCall);
  614. }), timeToCall);
  615. lastTime = currTime + timeToCall;
  616. return id;
  617. };
  618. }
  619. if (!window.cancelAnimationFrame) {
  620. return window.cancelAnimationFrame = function(id) {
  621. return clearTimeout(id);
  622. };
  623. }
  624. })();
  625. (function() {
  626. if ((Function.prototype.name == null) && (Object.defineProperty != null)) {
  627. return Object.defineProperty(Function.prototype, "name", {
  628. get: function() {
  629. var funcNameRegex, results;
  630. funcNameRegex = /function\s([^(]{1,})\(/;
  631. results = funcNameRegex.exec(this.toString());
  632. if ((results != null) && results.length > 1) {
  633. return results[1].trim();
  634. } else {
  635. return "";
  636. }
  637. },
  638. set: function(value) {}
  639. });
  640. }
  641. })();
  642. }).call(this);
  643. /*
  644. //@ sourceMappingURL=gearsketch_util.map
  645. */