// TODO: move to math lib private Vector2 PolarTolinear(Polar2 p) { var r = p.R; var a = p.A; a = MathHelper.ToRadians(((a + 360) % 360)); var x = (float)Math.Cos(a) * r; var y = -(float)Math.Sin(a) * r; return(new Vector2(x, y)); }
/// <param name="n">Number of teeth</param> /// <param name="d">Pitch diameter</param> /// <param name="p">Diametrical pitch</param> /// <param name="pa">Pressure angle (in degrees)</param> /// <param name="I">internal</param> public Gear(GraphicsDevice device, Vector2 position, int n, float d, float p, float pa, bool I = false) { // TODO: give everything a sensible name // TODO: do we need so many points, identify imporant points and remove others var outerDiameter = (n + (I ? 2.3f : 2.0f)) / p; var innerDiameter = (n - (I ? 2 : 2.3f)) / p; var bc = (float)(d * Math.Cos(pa * Math.PI / 180.0)); var radiusMin = innerDiameter / 2; var radiusMax = outerDiameter / 2; var rbase = bc / 2; var ac = 0.0f; var step = 0.1f; var first = true; var fix = 0; var polarPoints = new List <Polar2>(); polarPoints.Add(new Polar2(radiusMin, 0)); // All hard to follow since its in polar coordinates, TODO: describe better! // Create a single side of a single tooth, it is nicely curved /* * \ * \ * | * / */ for (var i = 1.0f; i < 100.0f; i += step) { var bpl = this.PolarTolinear(new Polar2(rbase, -i)); var len = rbase * MathHelper.Pi * 2 / 360.0f * i; var opl = this.PolarTolinear(new Polar2(len, -i + 90)); var np = this.LinearToPolar(new Vector2(bpl.X + opl.X, bpl.Y + opl.Y)); if (np.R >= radiusMin) { if (first) { first = false; step = (2 / (float)n) * 10; } if (np.R < d / 2) { ac = np.A; } if (np.R > radiusMax) { if (++fix < 10) { i -= step; step /= 2; continue; } np.R = radiusMax; polarPoints.Add(np); break; } polarPoints.Add(np); } } // Mirror the side and connect the two via along the top /* * /---\ * / \ * | | * \ / */ var fa = 360 / (float)n; var ma = (fa / 2) + (2 * ac); var fpa = (fa - ma) > 0 ? 0 : -(fa - ma) / 2; var m = polarPoints.Count; polarPoints[0] = new Polar2(radiusMin, fpa); // Is this part ever called? while (polarPoints[m - 1].A > ma / 2.0f) { Splice(polarPoints, m - 1, 1); m--; } for (var i = polarPoints.Count - 1; i >= 0; i--) { var bp = polarPoints[i]; var na = ma - bp.A; polarPoints.Add(new Polar2(bp.R, na)); } // Copy and paste these teeth equal along the entire gear // we now have a full gear, in polar coordinates m = polarPoints.Count; for (var i = 1; i < n; i++) { for (var pi = 0; pi < m; pi++) { var bp = polarPoints[pi]; var na = bp.A + fa * i; polarPoints.Add(new Polar2(bp.R, na)); } } // Convert back from polar to linear coordinates this.Points = new List <Vector2>(); for (var i = 0; i < polarPoints.Count; i++) { var point = this.PolarTolinear(polarPoints[i]); var x = point.X; var y = point.Y; this.Points.Add(new Vector2(x, y)); } this.Device = device; this.Position = position; this.N = n; // TODO: We're somehow mirroring something here which is why we need the weird minus in the ComputeRotation function this.Lines = new List <Line>(); for (var i = 1; i < this.Points.Count; i++) { var prev = this.Points[i - 1]; var curr = this.Points[i - 0]; var line = new Line(device, Color.Yellow, prev, curr); line.Position = new Vector3(position.X, 0, position.Y); line.Update(); this.Lines.Add(line); } var p0 = this.Points[this.Points.Count - 1]; var p1 = this.Points[0]; var closingLine = new Line(device, Color.Yellow, p0, p1); closingLine.Position = new Vector3(position.X, 0, position.Y); closingLine.Update(); this.Lines.Add(closingLine); this.Rsc = d * 1.0f / 2; this.baseAngle = ac; }