Skip to content

Instantly share code, notes, and snippets.

@takehiko
Created October 20, 2012 20:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save takehiko/3924591 to your computer and use it in GitHub Desktop.
Save takehiko/3924591 to your computer and use it in GitHub Desktop.
Tripartition of equilateral triangle
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
# When you execute this Ruby script,
# two SVG files "tri3a.svg" and "tri3b.svg" will be generated.
# Those files show a tripartition of an equilateral triangle,
# and you can make sure it by SVG-readable browsers (Firefox),
# SVG drawers (Inkscape), or even text editors (Emacs).
class Point
def initialize(x_ = 0.0, y_ = 0.0, lab = "")
@x = x_.to_f
@y = y_.to_f
@label = lab
end
attr_accessor :x, :y
def to_s(lab = @label)
"%s(%8.6f, %8.6f)" % [lab, @x, @y]
end
def *(scale = 1.0)
self.class.new(@x * scale, @y * scale, @label)
end
def shortarc(to, angle_pm_deg = 5.0)
angle_pm = angle_pm_deg.to_f / 180.0 * Math::PI
d_x = to.x - @x
d_y = to.y - @y
r = Math.sqrt(d_x * d_x + d_y * d_y)
angle = Math.atan2(d_x, d_y)
p1 = Point.new(@x + r * Math.sin(angle - angle_pm),
@y + r * Math.cos(angle - angle_pm))
p2 = Point.new(@x + r * Math.sin(angle + angle_pm),
@y + r * Math.cos(angle + angle_pm))
[p1, p2]
end
end
module SVGHelper
module_function
def extend_line(p1, p2, ratio = 0.1)
p3 = Point.new(p2.x + (p2.x - p1.x) * ratio,
p2.y + (p2.y - p1.y) * ratio)
'<path d="M %g,%g L %g,%g" class="thinline"/>' % [p1.x, p1.y, p3.x, p3.y]
end
def draw_circle_and_segment(p1, p2)
r = Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2)
'<g style="fill:none;stroke:#666666;stroke-width:0.5"><line x1="%g" y1="%g" x2="%g" y2="%g"/><circle cx="%g" cy="%g" r="%g"/></g>' % [p1.x, p1.y, p2.x, p2.y, p1.x, p1.y, r]
end
def draw_shortarc(p1, p2, angle_pm_deg = 5.0)
p3, p4 = p1.shortarc(p2, angle_pm_deg)
(false ? draw_circle_and_segment(p1, p2) : "") +
'<path d="M %g,%g A 100 100 0 0 0 %g,%g" class="thinline"/>' % [p3.x, p3.y, p4.x, p4.y]
end
def draw_string(p, str, d_x = 0, d_y = 0)
'<g transform="translate(%g,%g) scale(1,-1)"><text x="0" y="0">%s</text></g>' % [p.x + d_x, p.y + d_y, str]
end
def l(level, line)
" " * (level * 2) + line + "\n"
# "\t" * level + line + "\n"
end
end
include SVGHelper
#### constants
r3 = Math.sqrt(3)
r3inv = 1.0 / r3
mag = 100
cmag = 1
#### points
b = Point.new(0, 0) * mag
c = Point.new(1, 0) * mag
a = Point.new(0.5, r3 * 0.5) * mag
d_x = 0.5 - 0.5 * r3inv
d_y = r3 * d_x
d = Point.new(d_x, d_y) * mag
e = Point.new(1.0 - d_x, d_y) * mag
f = Point.new(0.5, 0) * mag
g = Point.new(0.5, d_y) * mag
puts a.to_s("A")
puts b.to_s("B")
puts c.to_s("C")
puts d.to_s("D")
puts e.to_s("E")
puts f.to_s("F")
puts g.to_s("G")
if true
s_abc = 1 * (r3 / 2.0) * 0.5 * mag ** 2
s_ade = (e.x - d.x) * (a.y - d.y) * 0.5
puts("ABC = %8.6f" % s_abc)
puts("ADE = %8.6f" % s_ade)
puts("ADE/ABC = %8.6f" % (s_ade / s_abc))
end
if false
p, q = c.shortarc(a, 7)
# r, s = b.shortarc(a, 7)
puts p.to_s("P")
puts q.to_s("Q")
puts("CP^2 = %8.6f" % ((p.x - c.x) ** 2 + (p.y - c.y) ** 2))
end
#### triangle (partitioned & colored)
svg_name = "tri3a"
width = height = 400
trans_x, trans_y, scale = 20, 345, 3.6
code = <<'EOS'
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg"
width="__WIDTH__" height="__HEIGHT__" id="__SVGNAME__">
<style type="text/css" >
<![CDATA[
.thinline { fill:none; stroke:black; stroke-width:1; }
.thickline { fill:none; stroke:black; stroke-width:2; }
#bg { fill:#fffff0; stroke:none }
]]>
</style>
<!--G-->
</svg>
EOS
code.gsub!(/__WIDTH__/, width.to_s)
code.gsub!(/__HEIGHT__/, height.to_s)
code.gsub!(/__SVGNAME__/, svg_name)
code2 = ""
code2 += l(1, '<path d="M 0,0 L _W_,0 _W_,_H_ 0,_H_ z" id="bg"/>'.gsub("_W_", width.to_s).gsub("_H_", height.to_s))
code2 += l(1, '<g transform="translate(_Tx_,_Ty_) scale(_S_,-_S_)" class="thickline">'.gsub("_Tx_", trans_x.to_s).gsub("_Ty_", trans_y.to_s).gsub("_S_", scale.to_s))
code2 += l(2, '<path d="M %g,%g L %g,%g %g,%g z" style="fill:#ffcccc;stroke:none" id="ADE"/>' % [a.x, a.y, d.x, d.y, e.x, e.y])
code2 += l(2, '<path d="M %g,%g L %g,%g %g,%g %g,%g z" style="fill:#ccffcc;stroke:none" id="BFGD"/>' % [b.x, b.y, f.x, f.y, g.x, g.y, d.x, d.y])
code2 += l(2, '<path d="M %g,%g L %g,%g %g,%g %g,%g z" style="fill:#ccccff;stroke:none" id="CFGE"/>' % [c.x, c.y, f.x, f.y, g.x, g.y, e.x, e.y])
code2 += l(2, '<path d="M %g,%g L %g,%g %g,%g z" id="ABC"/>' % [a.x, a.y, b.x, b.y, c.x, c.y])
code2 += l(2, '<path d="M %g,%g L %g,%g" id="DE"/>' % [d.x, d.y, e.x, e.y])
code2 += l(2, '<path d="M %g,%g L %g,%g" id="FG"/>' % [f.x, f.y, g.x, g.y])
# code2 += l(2, '<path d="M %g,%g A 100 100 0 0 0 %g %g" id="arc1" class="thinline" style="stroke:blue"/>' % [p.x, p.y, q.x, q.y])
# code2 += l(2, '<path d="M %g,%g A 100 100 0 0 0 %g %g" id="arc2" class="thinline" style="stroke:blue"/>' % [r.x, r.y, s.x, s.y])
code2 += l(1, '</g>')
code["<!--G-->\n"] = code2
open("#{svg_name}.svg", "w") do |f_out|
f_out.print code
end
#### triangle (an answer of construction problem)
svg_name = "tri3b"
width, height = 370, 400
trans_x, trans_y, scale = 95, 308, 2.4
code = <<'EOS'
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg"
width="__WIDTH__" height="__HEIGHT__" id="__SVGNAME__">
<style type="text/css" >
<![CDATA[
.thinline { fill:none; stroke:black; stroke-width:1; }
.thickline { fill:none; stroke:black; stroke-width:2; }
#bg { fill:#fffff0; stroke:none }
text { font-size:10px; font-family:Serif; font-style:normal; font-weight:normal; fill:#000000; stroke:none; }
]]>
</style>
<!--G-->
</svg>
EOS
code.gsub!(/__WIDTH__/, width.to_s)
code.gsub!(/__HEIGHT__/, height.to_s)
code.gsub!(/__SVGNAME__/, svg_name)
code2 = ""
code2 += l(1, '<path d="M 0,0 L _W_,0 _W_,_H_ 0,_H_ z" id="bg"/>'.gsub("_W_", width.to_s).gsub("_H_", height.to_s))
code2 += l(1, '<g transform="translate(_Tx_,_Ty_) scale(_S_,-_S_)" class="thickline">'.gsub("_Tx_", trans_x.to_s).gsub("_Ty_", trans_y.to_s).gsub("_S_", scale.to_s))
p1 = Point.new(0, r3inv * a.x + a.y) # y - a.y = -r3inv * (x - a.x) => y = -r3inv * x + (r3inv * a.x + a.y)
code2 += l(2, extend_line(a, p1))
code2 += l(2, extend_line(b, p1))
code2 += l(2, draw_shortarc(a, d))
code2 += l(2, draw_shortarc(a, e))
p2 = Point.new(a.x, 0.3 * mag)
code2 += l(2, draw_shortarc(b, p2))
code2 += l(2, draw_shortarc(c, p2))
p3 = Point.new(a.x, -0.3 * mag)
code2 += l(2, draw_shortarc(b, p3))
code2 += l(2, draw_shortarc(c, p3))
code2 += l(2, extend_line(g, p3))
p4 = Point.new(-0.3 * mag, 0)
code2 += l(2, extend_line(b, p4))
code2 += l(2, draw_shortarc(b, p4))
p5 = Point.new(0.3 * mag, 0)
code2 += l(2, draw_shortarc(b, p5))
p6 = Point.new(0, 0.3 * mag)
code2 += l(2, draw_shortarc(p4, p6))
code2 += l(2, draw_shortarc(p5, p6))
v1 = Point.new(r3inv, 1) * mag
p7 = Point.new(a.x + 0.25 * v1.x, a.y + 0.25 * v1.y)
code2 += l(2, extend_line(a, p7))
code2 += l(2, draw_shortarc(a, p7))
p8 = Point.new(a.x - 0.25 * v1.x, a.y - 0.25 * v1.y)
code2 += l(2, draw_shortarc(a, p8))
v2 = Point.new(mag, -r3inv * mag)
p9 = Point.new(a.x - 0.3 * v2.x, a.y - 0.3 * v2.y)
code2 += l(2, draw_shortarc(p7, p9))
code2 += l(2, draw_shortarc(p8, p9))
code2 += l(2, draw_string(a, "A", 3 * cmag, -1 * cmag))
code2 += l(2, draw_string(b, "B", -3 * cmag, -9 * cmag))
code2 += l(2, draw_string(c, "C", -3 * cmag, -9 * cmag))
code2 += l(2, draw_string(d, "D", -5 * cmag, 6 * cmag))
code2 += l(2, draw_string(e, "E", -1 * cmag, 6 * cmag))
code2 += l(2, draw_string(f, "F", 1 * cmag, -9 * cmag))
code2 += l(2, draw_string(g, "G", -4 * cmag, 3 * cmag))
code2 += l(2, draw_string(p1, "H", 2 * cmag, 1 * cmag))
code2 += l(2, '<path d="M %g,%g L %g,%g %g,%g z" id="ABC"/>' % [a.x, a.y, b.x, b.y, c.x, c.y])
code2 += l(2, '<path d="M %g,%g L %g,%g" id="DE"/>' % [d.x, d.y, e.x, e.y])
code2 += l(2, '<path d="M %g,%g L %g,%g" id="FG"/>' % [f.x, f.y, g.x, g.y])
code2 += l(1, '</g>')
code["<!--G-->\n"] = code2
open("#{svg_name}.svg", "w") do |f_out|
f_out.print code
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment