This documentation is automatically generated by online-judge-tools/verification-helper
require "./real"
require "./object/*"
require "./distance"
module Geometric
extend self
def intersect?(c1 : Circle, c2 : Circle)
(distance(c1.center, c2.center) <=> (c1.radious + c2.radious)) < 0
end
def intersect?(l1 : Line, l2 : Line)
!l1.parallel?(l2)
end
def intersect?(s1 : Segment, s2 : Segment)
ccw(s1.begin, s1.end, s2.begin) * ccw(s1.begin, s1.end, s2.end) <= 0 &&
ccw(s2.begin, s2.end, s1.begin) * ccw(s2.begin, s2.end, s1.end) <= 0
end
end
# require "./real"
require "big"
alias Real = BigFloat
EPS = Real.new(1e-12)
struct Real
def <=>(other : Real)
{% if Real == BigFloat %}
if previous_def(other - EPS) < 0
-1
elsif previous_def(other + EPS) > 0
1
else
0
end
{% else %}
if self < other - EPS
-1
elsif self > other + EPS
1
else
0
end
{% end %}
end
def sign : Int32
self < -EPS ? -1 : self > EPS ? 1 : 0
end
def to_radian
self * Math::PI / 180
end
def to_degree
self * 180 / Math::PI
end
def self.scan(scanner, io : IO) : self
Real.new scanner.s(io)
end
end
# require "./object/*"
module Geometric
struct Circle
property center : Vec2, radious : Real
def initialize(center : Vec2, radious)
@center, @radious = center, Real.new(radious)
end
def initialize(x, y, radious)
initialize(Vec2.new(x, y), radious)
end
def self.scan(s, io : IO) : self
new Real.scan(s, io), Real.scan(s, io), Real.scan(s, io)
end
delegate x, y, to: center
{% for op in %w[+ - * /] %}
def {{op.id}}(other : Vec2)
Circel.new(x {{op.id}} other.x, y {{op.id}} other.y, radious)
end
def {{op.id}}(other : Real)
Circle.new(x {{op.id}} other, y {{op.id}} other, radious)
end
{% end %}
def area : Real
radious * radious * Math::PI
end
def contains?(v : Vec2)
((v - center).length <=> radious) < 0
end
def inspect(io : IO)
io << '(' << center << ", " << radious << ')'
end
end
end
# require "../real"
# require "./vec2"
# require "../real"
module Geometric
struct Vec2
include Comparable(Vec2)
property x : Real, y : Real
def self.zero
Vec2.new(Real.zero, Real.zero)
end
def initialize(x, y)
@x, @y = Real.new(x), Real.new(y)
end
def self.scan(scanner, io : IO) : self
Vec2.new(scanner.f(io), scanner.f(io))
end
def +
self
end
def -
Vec2.new(-x, -y)
end
{% for op in %w[+ - * /] %}
def {{op.id}}(other : Vec2)
Vec2.new(x {{op.id}} other.x, y {{op.id}} other.y)
end
def {{op.id}}(other)
Vec2.new(x {{op.id}} other, y {{op.id}} other)
end
{% end %}
def <=>(other : Vec2)
x_cmp = x <=> other.x
if x_cmp != 0
x_cmp
else
y <=> other.y
end
end
def [](index : Int)
return x if index == 0
return y if index == 1
raise IndexError.new
end
def length : Real
Math.hypot(x, y)
end
def dot(other : Vec2) : Real
x * other.x + y * other.y
end
def cross(other : Vec2) : Real
x * other.y - y * other.x
end
def angle : Real
Real.new Math.atan2(y, x)
end
def rotate(rad : Real) : Vec2
c, s = Math.cos(rad), Math.sin(rad)
Vec2.new(x * c - y * s, x * s + y * c)
end
def to_tuple
{x, y}
end
def inspect(io : IO)
io << '(' << x << ", " << y << ')'
end
end
end
module Geometric
private module LineBase
getter begin : Vec2, end : Vec2
def initialize(@begin, @end)
end
def initialize(begin_x, begin_y, end_x, end_y)
@begin = Vec2.new(begin_x, begin_y)
@end = Vec2.new(end_x, end_y)
end
def +(v : Vec2)
self.class.new(@begin + v, @end + v)
end
def -(v : Vec2)
self.class.new(@begin - v, @end - v)
end
def vec
@end - @begin
end
def counter_vec
@begin - @end
end
def parallel?(other : LineBase)
vec.cross(other.vec).sign == 0
end
def orthogonal?(other : LineBase)
vec.dot(other.vec).sign == 0
end
def to_tuple
{@begin, @end}
end
def inspect(io : IO) : Nil
io << '(' << @begin << ", " << @end << ')'
end
end
struct Line
include LineBase
def self.scan(s, io : IO) : self
new Real.scan(s, io), Real.scan(s, io), Real.scan(s, io), Real.scan(s, io)
end
end
struct Segment
include LineBase
def self.scan(scanner, io : IO) : self
new Real.scan(s, io), Real.scan(s, io), Real.scan(s, io), Real.scan(s, io)
end
end
end
module Geometric
class Polygon < Array(Vec2)
def initialize(points : Array(Vec2))
initialize(points.size)
concat points
end
def initialize
super
end
def initialize(initial_capacity : Int)
super
end
def initialize(size : Int, &block : Int32 -> Vec2)
initialize(size)
size.to_i.times do |i|
self << yield i
end
end
def after(i : Int32) : Vec2
self[i != size - 1 ? i + 1 : 0]
end
def area : Real
(0...size).sum { |i|
self[i].cross after(i)
}.abs / 2
end
def centroid : Vec2
sum / size
end
def contains?(v : Vec2)
(0...size).count { |i|
p1, p2 = {self[i], after(i)}.minmax_by &.y
(p1.y <=> v.y) <= 0 && (v.y <=> p2.y) < 0 && (p1 - v).cross(p2 - v).sign == -1
}.odd?
end
def convex_hull : Polygon
result = Polygon.new
points = sort
points.each do |point|
while result.size >= 2 && Geometric.ccw(result[-2], result[-1], point) != -1
result.pop
end
result << point
end
t = result.size + 1
(0...points.size - 1).reverse_each do |i|
while result.size >= t && Geometric.ccw(result[-2], result[-1], points[i]) != -1
result.pop
end
result << points[i]
end
result.pop
result
end
def inspect(io)
io << self
end
end
end
# require "./distance"
# require "./real"
# require "./object/*"
module Geometric
extend self
def distance(v1 : Vec2, v2 : Vec2) : Real
Math.hypot(v1.x - v2.x, v1.y - v2.y)
end
def distance(v : Vec2, c : Circle) : Real
(distance(v, c.center) - c.radious).abs
end
def distance(v : Vec2, l : Line) : Real
(l.vec.cross(v - l.begin) / l.vec.length).abs
end
def distance(v : Vec2, s : Segment) : Real
if s.vec.dot(v - s.begin).sign < 0
distance(v, s.begin)
elsif s.counter_vec.dot(v - s.end).sign < 0
distance(v, s.end)
else
distance(v, Line.new(s.begin, s.end))
end
end
def distance(c1 : Circle, c2 : Circle) : Real
d = distance(c1.center, c2.center)
r = c1.radious + c2.radious
if (d <=> r) > 0
d - r
elsif (d + c1.radious <=> c2.radious) < 0
c2.radious - (d + c1.radious)
elsif (d + c2.radious <=> c1.radious) < 0
c1.radious - (d + c2.radious)
else
Real.zero
end
end
def distance(obj1, obj2) : Real
distance(obj2, obj1)
end
end
module Geometric
extend self
def intersect?(c1 : Circle, c2 : Circle)
(distance(c1.center, c2.center) <=> (c1.radious + c2.radious)) < 0
end
def intersect?(l1 : Line, l2 : Line)
!l1.parallel?(l2)
end
def intersect?(s1 : Segment, s2 : Segment)
ccw(s1.begin, s1.end, s2.begin) * ccw(s1.begin, s1.end, s2.end) <= 0 &&
ccw(s2.begin, s2.end, s1.begin) * ccw(s2.begin, s2.end, s1.end) <= 0
end
end