Skip to content

Instantly share code, notes, and snippets.

@xnuk
Last active September 6, 2022 13:14
Show Gist options
  • Save xnuk/a54c42d312d4543fab21a721e3989b68 to your computer and use it in GitHub Desktop.
Save xnuk/a54c42d312d4543fab21a721e3989b68 to your computer and use it in GitHub Desktop.
GeoGebra Geometry .ggb file Generator
# vim: ts=4
require "./geo.cr"
PI = '\u03C0'
Geo.render(Path["./foo.ggb"]) do
d "poly = 2 * pi / 7" { hidden }
d "r = 10" { hidden }
angle_hidden = false
d "O = Intersect(xAxis, yAxis)"
d "A = O + (0, r)" { hidden :label if angle_hidden }
d "B = Rotate(A, -poly)" { hidden :label if angle_hidden }
d "C = Rotate(A, -2 * poly)" { hidden :label if angle_hidden }
d "D = Rotate(A, -3 * poly)" { hidden :label if angle_hidden }
d "E = Rotate(A, 3 * poly)" { hidden :label if angle_hidden }
d "F = Rotate(A, 2 * poly)" { hidden :label if angle_hidden }
d "G = Rotate(A, poly)" { hidden :label if angle_hidden }
d "cir = Circle(O, r)" { hidden }
d "p = PolyLine(A,B,C,D,E,F,G,A)"
d "l1 = Segment(B,F)" { decoration :line_pp }
d "l1_p = Segment(A,G)" { decoration :line_pp }
d "l2 = Segment(A,C)"
d "H = Intersect(l1, l2)"
d "a = CircleArc(O,C,B)" do
show
line type: dash_dot
color 0, 0
end
d "sixa = CircleArc(O,B,C)" { line type: long_dash, thickness: 3 }
angle "abf" do
show; caption "2a"; line opacity: 0.4
offset x: -30
arc_size 25
end
angle "fbc" do
show; caption "3a"; line opacity: 0.4
offset y: 20, x: -10
arc_size 30
end
angle "bca" do
show; caption "a"; line opacity: 0.4
offset y: -20, x: -10
end
angle "agf" do
show; caption "5a"; line opacity: 0.4
offset x: 20, y: 20
end
angle "gfb" do
show; caption "2a"; line opacity: 0.4
offset x: 20, y: -20
end
angle "cag" do
show; caption "4a"; line opacity: 0.4
arc_size 40
offset y: 30
end
angle "bac" do
show; caption "a"; line opacity: 0.4
offset x: 20, y: 17
end
angle "bhc" do
show; caption "3a"; line opacity: 0.4
offset x: 20
arc_size 25
color 0xff0000, 0.3
end
angle "ahb" do
show; caption "4a"; line opacity: 0.4
offset y: -20
arc_size 30
color 0xff0000, 0.3
end
angle "acd" do
show; caption "4a"; line opacity: 0.4
offset x: -35
arc_size 35
end
d "ch = Segment(C,H)" { decoration :line_s }
d "ab = Segment(A,B)" { decoration :line_s }
d "bc = Segment(B,C)" { decoration :line_s }
d "cd = Segment(C,D)" { decoration :line_s }
d "de = Segment(D,E)" { decoration :line_s }
d "ef = Segment(E,F)" { decoration :line_s }
d "fg = Segment(F,G)" { decoration :line_s }
d "dh = Segment(D,H)"
angle "dhc" do
show; caption "1.5a"; line opacity: 0.4
offset y: 30
color 0x6666ff, 0.4
end
angle "hdc" do
show; caption "1.5a"; line opacity: 0.4
offset y: -30
color 0x6666ff, 0.4
end
angle "hde" do
show; caption "3.5a = 7a/2 = #{PI}/2"; line opacity: 0.4
offset x: -120, y: -30
color 0x666600, 0.4
arc_size 40
no_right_angle
end
description = <<-'EOF'
회색: 원주각
빨간색: 삼각형의 외각
파란색: 이등변삼각형
EOF
example = %w[
\text{ex) }
\angle CAG = \stackrel{\large\frown}{GEC}
= 4 \times \stackrel{\large\frown}{BC}
= 4a
].join(' ')
d "description = \"#{description}\"" { start_point x: -5, y: 6 }
d "example = \"#{example}\"" { latex; start_point x: -6, y: 4.5 }
end
# vim: ts=4
require "xml"
require "compress/zip"
class Geo
TEMPLATE = %w{
<?xml version="1.0" encoding="utf-8"?>
<geogebra format="5.0" version="5.0.729.0" app="geometry"
xsi:noNamespaceSchemaLocation="http://www.geogebra.org/apps/xsd/ggb.xsd"
xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<scripting blocked="true" disabled="true"/>
<euclidianView>
<evSettings axes="false" grid="false" gridIsBold="false" />
</euclidianView>
<kernel>
<continuous val="false"/>
<usePathAndRegionParameters val="true"/>
<decimals val="1"/>
<angleUnit val="degree"/>
<coordStyle val="0"/>
</kernel>
<construction>{{}}</construction></geogebra>
}.join(' ').gsub("> <", "><")
enum LineType
Full = 5
ShortDash = 10
LongDash = 15
Dot = 20
DashDot = 30
end
def initialize(x : XML::Builder)
@x = x
end
def short_dash
LineType::ShortDash
end
def long_dash
LineType::LongDash
end
def dot
LineType::Dot
end
def dash_dot
LineType::DashDot
end
def angle(label : String) : Nil
up = label.upcase
d("#{label} = Angle(#{up[0]}, #{up[1]}, #{up[2]})")
end
def angle(label : String, &block) : Nil
angle(label)
@x.element("element", type: "", label: label) do
with self yield
end
end
def d(exp : String) : Nil
k, v = exp.split("=", 2).map(&.strip)
@x.element("expression", label: k, exp: v)
end
def d(exp : String, &block) : Nil
k, v = exp.split("=", 2).map(&.strip)
@x.element("expression", label: k, exp: v)
@x.element("element", type: "", label: k) do
with self yield
end
end
def caption(x : String)
@x.element("labelMode", val: 3)
@x.element("caption", val: x)
end
def hidden(what : Symbol = :object)
show_object = what != :object
@x.element("show", object: show_object, label: false)
end
def show
@x.element("show", object: true, label: true)
end
def arc_size(val : UInt16)
@x.element("arcSize", val: val)
end
def color(r : UInt8, g : UInt8, b : UInt8, a : Float32 = 0.1)
@x.element("objColor", r: r, g: g, b: b, alpha: a)
end
def color(rgb : UInt32, alpha : Float32 = 0.1)
color(
((rgb & 0xff0000) >> 16).to_u8,
((rgb & 0x00ff00) >> 8).to_u8,
(rgb & 0x0000ff).to_u8,
alpha
)
end
def line(
*,
thickness : UInt8 = 5,
type : LineType = LineType::Full,
opacity : Float32 = 0.8
)
@x.element("lineStyle",
thickness: thickness, type: type.value,
typeHidden: 1, opacity: (opacity * 255).round.to_u
)
end
def no_right_angle
@x.element("emphasizeRightAngle", val: false)
end
def offset(*, x : Int32 | Nil = 0, y : Int32 | Nil = 0)
@x.element("labelOffset", x: x, y: y)
end
DECO_LINES =
[:none, :line_s, :line_ss, :line_sss, :line_p, :line_pp, :line_ppp]
DECO_ANGLES =
[:none, :angle_rr, :angle_rrr,
:angle_s, :angle_ss, :angle_sss, :angle_up, :angle_down]
def decoration(ty : Symbol = :none)
deco = DECO_LINES.index(ty) || DECO_ANGLES.index(ty) || 0
@x.element("decoration", type: deco)
end
def start_point(*, x : Float32, y : Float32, z : Float32 = 1)
@x.element("startPoint", x: x, y: y, z: z)
end
def latex
@x.element("isLaTeX", val: true)
@x.element("font", serif: true, sizeM: 1, size: 0, style: 0)
end
def self.render(sink : IO | Path | Nil = nil) : String
t = XML.build_fragment do |x|
d = self.new(x)
with d yield
end
t = TEMPLATE.sub("{{}}", t.strip)
unless sink.nil?
Compress::Zip::Writer.open(sink) do |w|
w.add(
Compress::Zip::Writer::Entry.new(
filename: "geogebra.xml",
time: Time.utc(2000, 1, 1)
),
t
)
end
end
t
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment