Category talk:Wren-ellipse
Source code
<lang ecmascript>/* Module "ellipse.wren" */
import "graphics" for Canvas, Color import "math" for Math, Point import "./polygon" for Polygon
/* Ellipse represents an ellipse in 2 dimensional space. */ class Ellipse {
// Constructs a new Ellipse object with center (cx, cy), // horizontal radius rx and vertical radius ry. construct new(cx, cy, rx, ry) { if (!((cx is Num) && (cy is Num) && (rx is Num) && (ry is Num))) { Fiber.abort("All arguments must be numbers.") } _cx = cx _cy = cy _rx = rx _ry = ry }
// Properties cx { _cx } cy { _cy } rx { _rx } ry { _ry }
center { Point.new(_cx, _cy) } horizDiameter { 2 * _rx } vertiDiameter { 2 * _ry } circumference { Num.pi * (3*(_rx + _ry) - ((3*_rx + _ry)*(_rx + 3*_ry)).sqrt) } // approx area { Num.pi * _rx * _ry }
// Private helper method to determine status of a point (x, y) relative to current instance. det_(x, y) { (x - _cx) * (x - _cx) / (_rx * _rx) + (y - _cy) * (y - _cy) / (_ry * _ry) }
// Returns whether the current instance contains a point (x, y). // Points on the boundary are considered to be contained by the ellipse. contains(x, y) { det_(x, y) <= 1 }
// Returns whether a point (x, y) is on the boundary of the current instance. hasEdgePoint(x, y) { det_(x,y) == 1 }
// Returns whether a point (x, y) is an interior point of the current instance. // Points on the boundary are not considered to be interior ponts. hasInteriorPoint(x, y) { det_(x, y) < 1 }
// Draws the current instance in a given color. draw(c) { Canvas.ellipse(_cx - _rx, _cy - _ry, _cx + _rx, _cy + _ry, c) }
// Draws the current instance using a given fill color and border color. drawfill(fillColor, borderColor) { Canvas.ellipsefill(_cx - _rx, _cy - _ry, _cx + _rx, _cy + _ry, fillColor) draw(borderColor) }
// Convenience version of drawfill which uses the same fill and border colors. drawfill(c) { Canvas.ellipsefill(_cx - _rx, _cy - _ry, _cx + _rx, _cy + _ry, c) }
// Draws an arc of the current instance in a given color from startAngle to endAngle in degrees. // Angles are measured clockwise from the radius drawn to the current instance's rightmost point. drawArc(c, startAngle, endAngle) { var t = startAngle if (endAngle < startAngle) { while (endAngle < startAngle) endAngle = endAngle + 360 } var step = (endAngle - startAngle) / 1080 if (step == 0) return while (t <= endAngle) { var a = t * Num.pi / 180 var x = Math.cos(a) * _rx + _cx var y = Math.sin(a) * _ry + _cy Canvas.pset(x, y, c) t = t + step } }
// Draws a segment of the current instance in a given color from // startAngle to endAngle in degrees. Angles are measured as in drawArc. drawSegment(c, startAngle, endAngle) { drawArc(c, startAngle, endAngle) var sa = startAngle * Num.pi / 180 var sx = Math.cos(sa) * _rx + _cx var sy = Math.sin(sa) * _ry + _cy if (endAngle < startAngle) { while (endAngle < startAngle) endAngle = endAngle + 360 } var ea = endAngle * Num.pi / 180 var ex = Math.cos(ea) * _rx + _cx var ey = Math.sin(ea) * _ry + _cy Canvas.line(sx, sy, ex, ey, c) }
// Draws a segment of the current instance in a given color from // startAngle to endAngle in degrees. Angles are measured as in drawArc. drawSegmentfill(c, startAngle, endAngle) { drawArc(c, startAngle, endAngle) var t = startAngle if (endAngle < startAngle) { while (endAngle < startAngle) endAngle = endAngle + 360 } var step = (endAngle - startAngle) / 1080 if (step == 0) return var u = endAngle while (t <= u) { var ta = t * Num.pi / 180 var sx = Math.cos(ta) * _rx + _cx var sy = Math.sin(ta) * _ry + _cy var ua = u * Num.pi / 180 var ex = Math.cos(ua) * _rx + _cx var ey = Math.sin(ua) * _ry + _cy Canvas.line(sx, sy, ex, ey, c, 2) t = t + step u = u - step } }
// Draws a segment of the current instance in a given fill color and border color from // startAngle to endAngle in degrees. Angles are measured as in drawArc. drawSegmentfill(fillColor, startAngle, endAngle, borderColor) { drawSegmentfill(fillColor, startAngle, endAngle) drawSegment(borderColor, startAngle, endAngle) }
// Draws a sector of the current instance in a given color from // startAngle to endAngle in degrees. Angles are measured as in drawArc. drawSector(c, startAngle, endAngle) { drawArc(c, startAngle, endAngle) var sa = startAngle * Num.pi / 180 var sx = Math.cos(sa) * _rx + _cx var sy = Math.sin(sa) * _ry + _cy Canvas.line(_cx, _cy, sx, sy, c) if (endAngle < startAngle) { while (endAngle < startAngle) endAngle = endAngle + 360 } var ea = endAngle * Num.pi / 180 var ex = Math.cos(ea) * _rx + _cx var ey = Math.sin(ea) * _ry + _cy Canvas.line(_cx, _cy, ex, ey, c) }
// Draws a filled sector of the current instance in a given color from // startAngle to endAngle in degrees. Angles are measured as in drawArc. drawSectorfill(c, startAngle, endAngle) { drawSegmentfill(c, startAngle, endAngle) var sa = startAngle * Num.pi / 180 var sx = Math.cos(sa) * _rx + _cx var sy = Math.sin(sa) * _ry + _cy if (endAngle < startAngle) { while (endAngle < startAngle) endAngle = endAngle + 360 } var ea = endAngle * Num.pi / 180 var ex = Math.cos(ea) * _rx + _cx var ey = Math.sin(ea) * _ry + _cy var tri = Polygon.quick([[_cx, _cy], [sx, sy], [ex, ey]]) tri.drawfill(c) }
// Draws a sector of the current instance in a fill color and border color from // startAngle to endAngle in degrees. Angles are measured as in drawArc. drawSectorfill(fillColor, startAngle, endAngle, borderColor) { drawSectorfill(fillColor, startAngle, endAngle) drawSector(borderColor, startAngle, endAngle) }
// Draws the current instance as a pie using a list of colors and // associated start angles in degrees. drawPie(colors, startAngles) { var slices = startAngles.count for (i in 0...slices-1) { var delta = startAngles[i + 1] - startAngles[i] if (delta < 0) delta = delta + 360 if (delta <= 180) { drawSectorfill(colors[i], startAngles[i], startAngles[i] + delta) } else { drawSectorfill(colors[i], startAngles[i], startAngles[i] + 180) drawSectorfill(colors[i], startAngles[i] + 180, startAngles[i] + delta) } } var delta = startAngles[0] - startAngles[-1] if (delta < 0) delta = delta + 360 if (delta <= 180) { drawSectorfill(colors[-1], startAngles[-1], startAngles[-1] + delta) } else { drawSectorfill(colors[-1], startAngles[-1], startAngles[-1] + 180) } }
}
/* Circle represents a circle in 2 dimensional space. */ class Circle is Ellipse {
// Constructs a new Circle object with center (x, y) and radius r. construct new(cx, cy, r) { super(cx, cy, r, r) _r = r }
// Properties r { _r }
diameter { _r * 2 } circumference { 2 * Num.pi * _r }
// Draws the current instance in a given color and thickness. draw(c, size) { var t = _r - size if (t < 0) t = 0 for (s in _r...t) Canvas.circle(cx, cy, s, c) }
// Convenience version of draw which uses a default thickness of 1 pixel. draw(c) { draw(c, 1) }
// Draws the current instance using a given fill color, border color and border thickness. drawfill(fillColor, borderColor, borderSize) { Canvas.circlefill(cx, cy, _r, fillColor) draw(borderColor, borderSize) }
// Draws the current instance using a given fill color, border color and border thickness of 1. drawfill(fillColor, borderColor) { Canvas.circlefill(cx, cy, _r, fillColor) draw(borderColor) }
// Convenience version of drawfill which uses the same fill and border colors. drawfill(c) { Canvas.circlefill(cx, cy, _r, c) }
}
/* Button represents a rectangle with curved corners in 2 dimensional space. */ class Button {
// Constructs a new elliptical Button object with center (x, y), width w and height h. construct new(cx, cy, w, h) { if (!((cx is Num) && (cy is Num) && (w is Num) && (h is Num))) { Fiber.abort("All arguments must be numbers.") } _cx = cx _cy = cy _w = w _h = h }
// Convenience method which constructs a square button object with center (x, y) and width w. static new(cx, cy, w) { new(cx, cy, w, w) }
// Properties cx { _cx } cy { _cy } width { _w } height { _h }
// Draws the current instance in a given color. draw(c) { var rx = _w / 3 var ry = _h / 3 var cx = _cx - rx/2 var cy = _cy - ry/2 var angles = [[0, 90], [90, 180], [180, 270], [270, 360]] var centIncs = [[ rx, ry], [0, ry], [0, 0], [rx, 0]] var lineIncs = [[-rx, 0], [0, -ry], [rx, 0], [0, ry]] for (i in 0..3) { var e = Ellipse.new(cx + centIncs[i][0], cy + centIncs[i][1], rx, ry) var startAngle = angles[i][0] var endAngle = angles[i][1] e.drawArc(c, startAngle, endAngle) var a = endAngle * Num.pi / 180 var sx = Math.cos(a) * rx + e.cx var sy = Math.sin(a) * ry + e.cy Canvas.line(sx, sy, sx + lineIncs[i][0], sy + lineIncs[i][1], c) } }
// Draws the current instance filled with a given color and with a given border color. drawfill(fillColor, borderColor) { var rx = _w / 3 var ry = _h / 3 var cx = _cx - rx/2 var cy = _cy - ry/2 var angles = [[0, 90], [90, 180], [180, 270], [270, 360]] var centIncs = [[ rx, ry], [0, ry], [0, 0], [rx, 0]] var lineIncs = [[-rx, 0], [0, -ry], [rx, 0], [0, ry]] var rectIncs = [[-rx, -ry], [0, -ry], [0, 0], [-rx, 0]] for (i in 0..3) { var e = Ellipse.new(cx + centIncs[i][0], cy + centIncs[i][1], rx, ry) var startAngle = angles[i][0] var endAngle = angles[i][1] e.drawSectorfill(fillColor, startAngle, endAngle) e.drawArc(borderColor, startAngle, endAngle) var a = endAngle * Num.pi / 180 var sx = Math.cos(a) * rx + e.cx var sy = Math.sin(a) * ry + e.cy Canvas.line(sx, sy, sx + lineIncs[i][0], sy + lineIncs[i][1], borderColor, 2) Canvas.rectfill(sx + rectIncs[i][0], sy + rectIncs[i][1], rx, ry, fillColor) } Canvas.rectfill(cx, cy, rx, ry, fillColor) }
// Convenience version of drawfill method where the fill and border colors are the same. drawfill(c) { drawfill(c, c) }
}</lang>