Comments
Description
Transcript
視空間・認知空間への拡張
視空間・認知空間への拡張 視空間・認知空間への拡張 -双曲幾何ツールの試作に向けて- 双曲幾何ツ ルの試作に向けて 2011年 12月 20日 筑波大学システム情報系 渡辺 俊 地理情報科学と都市工学を融合した空間解析手法の新展開 Page 1 視空間・認知空間への拡張 活動 概要 活動の概要 • 仮想空間・実空間の一体化 – AR技術を利用した実空間GISの開発 – 3次元都市モデルの整備・SketchUpの活用 • e-Learningコンテンツの更新 – ArcGIS10・Pythonへの対応 – アルゴリズム教材の開発 • 視空間・認知空間への拡張 視空間 認知空間への拡張 – 双曲幾何ツールの試作に向けて 地理情報科学と都市工学を融合した空間解析手法の新展開 Page 2 視空間・認知空間への拡張 はじめに (距離空間) • 図面(建築空間) – ユークリッド距離 • 地図(都市空間) – 球面距離(大円距離)・...... • 時間軸変形地図(1969:杉浦康平) – 時間距離 • 空間的相互作用モデル(アクティビティのマクロな視点) – 距離減衰関数(冪乗関数・指数関数) • 視空間・認知空間のモデル(アクティビティのミクロな視点) – 双曲的距離(?) 地理情報科学と都市工学を融合した空間解析手法の新展開 Page 3 重力モデル 地理情報科学と都市工学を融合した空間解析手法の新展開 視空間・認知空間への拡張 Page 4 ArcGISによる正距方位図 地理情報科学と都市工学を融合した空間解析手法の新展開 視空間・認知空間への拡張 Page 5 ポアンカレ円板の双曲タイル張り 地理情報科学と都市工学を融合した空間解析手法の新展開 視空間・認知空間への拡張 Page 6 視空間・認知空間への拡張 幾何学と プリケ 幾何学とアプリケーション • ユークリッド幾何学 – 初等幾何学(CAD) • 非ユークリッド幾何学 非 クリ ド幾何学 – 楕円幾何学(GIS?) 幾 ( ) • 球面幾何学 – 双曲幾何学 – 射影幾何学(CG) 地理情報科学と都市工学を融合した空間解析手法の新展開 Page 7 コンパスと定規による描画方法(Chaim Goodman-Strauss) 地理情報科学と都市工学を融合した空間解析手法の新展開 視空間・認知空間への拡張 Page 8 視空間・認知空間への拡張 双曲タイル貼り (双曲幾何学への招待:複素数で視る) 地理情報科学と都市工学を融合した空間解析手法の新展開 Page 9 アルゴリズムによる描画方法 地理情報科学と都市工学を融合した空間解析手法の新展開 視空間・認知空間への拡張 Page 10 双曲タイル貼りのプログラム from math import * from Tkinter import * class Point: def __init__(self, x1, y1): self.x = float(x1) self.y = float(y1) def __repr__(self): return "Point(%f, %f)¥n" % (self.x, self.y) def __eq__(self, pt): return (self.x == pt.x and self.y == pt.y) def __add__(self, pt): return Point(self.x + pt.x, self.y + pt.y) def __sub__(self, sub (self, pt): return Point(self.x - pt.x, self.y - pt.y) def __mul__(self, n): return Point(self.x * n, self.y * n) def __div__(self, n): return Point(self.x / n, self.y / n) def sq_sum(self): return self.x**2 + self.y**2 def pro_sum(self, pt): return self.x * pt.x + self.y * pt.y def ex_pro(self, pt): return self.x * pt.y - self.y * pt.x def normal(self): d = sqrt(self.sq_sum()) return Point(self.x / d, self.y / d) def rotate(self, t): u = self.x * cos(t) - self.y * sin(t) v = self.x * sin(t) + self.y * cos(t) return Point(u,v) class Line: def __init__(self, start, end): self.p1 = start self.p2 lf 2 = end d def __repr__(self): return "Line((%f, %f), (%f, %f))¥n"¥ % (self.p1.x, self.p1.y, self.p2.x, self.p2.y) class Circle: def __init__(self, center, radius): self.c = center self.r = float(radius) def __repr__(self): return "Circle((%f, %f),%f)¥n" % (self.c.x, self.c.y, self.r) def clip(self, clip(self circle): d = sqrt((self.c - circle.c).sq_sum()) phi = acos((d**2 + self.r**2 - circle.r**2)/(2*d*self.r)) theta = atan2(circle.c.y - self.c.y, circle.c.x - self.c.x) return [(theta - phi)*180/pi, (phi*180/pi) * 2] class Arc(Circle): def __init__(self, center, radius, p1, p2): Circle.__init__(self, center, radius) self.p1 = p1 self.p2 = p2 def __repr__(self): repr (self): ag = self.angle() return "Arc((%f, %f),%f, %f, %f)¥n"¥ % (self.c.x, self.c.y, self.r, ag[0], ag[1]) def angle(self): theta1 = atan2(self.p1.y - self.c.y, self.p1.x - self.c.x) theta2 = atan2(self.p2.y - self.c.y, self.p2.x - self.c.x) phi = abs(theta2 - theta1) if phi <= pi: return [min(theta1, theta2)*180/pi, phi*180/pi] else: return [max(theta1, theta2)*180/pi, (2*pi - phi)*180/pi] def circleInversion(axis, target): # point on circle if isinstance(axis, isinstance(axis Circle) and isinstance(target, isinstance(target Point): v = target - axis.c return axis.c + v/v.sq_sum()*axis.r**2 # point on line if isinstance(axis, Line) and isinstance(target, Point): unitv = (axis.p2 - axis.p1).normal() par = unitv*((target - axis.p1).pro_sum(unitv)) perp = (target - axis.p1) - par return axis.p1 + par - perp # line on circle if isinstance(axis, Circle) and isinstance(target, Line): s = (target.p2 (target p2 - target.p1).ex_pro(target.p2 target p1) ex pro(target p2 - axis.c) axis c) if abs(s) > (10**-8): v = target.p1 - target.p2 cx = (2*s*axis.c.x + v.y*axis.r**2)/(2*s) cy = (2*s*axis.c.y - v.x*axis.r**2)/(2*s) r = axis.r**2*sqrt((v.sq_sum())/s**2)/2 p1 = circleInversion(axis, target.p1) p2 = circleInversion(axis, target.p2) return Arc(Point(cx,cy), r, p2, p1) else: p1 = circleInversion(axis, target.p1) p2 = circleInversion(axis, target.p2) return Line(p2, p1) # circle on circle if isinstance(axis, Circle) and isinstance(target, Arc): if axis.c == target.c and axis.r == target.r: return Circle(axis.c, axis.r) elif abs((axis.c - target.c).sq_sum() - target.r**2) > (10**-8): dis = sqrt((target.c - axis.c).sq_sum()) ri = (target.c - axis.c)/dis c1 = axis.r**2/(dis + target.r) c2 = axis.r**2/(dis - target.r) p1 = circleInversion(axis, target.p1) p2 2 = circleInversion(axis, l I ( target.p2) 2) return Arc((axis.c + ri*(c1 + c2)/2),abs(c1 - c2)/2, p2, p1) else: p1 = circleInversion(axis, target.p1) p2 = circleInversion(axis, target.p2) return Line(p2, p1) # circle on line if isinstance(axis, Line) and isinstance(target, Arc): unitv = (axis.p2 - axis.p1).normal() par = unitv*(target.c - axis.p1).pro_sum(unitv) perp = (target.c - axis.p1) - par a1 = circleInversion(axis, circleInversion(axis target.p1) target p1) a2 = circleInversion(axis, target.p2) return Arc(axis.p1 + par - perp, target.r, a2, a1) #line on line if isinstance(axis, Line) and isinstance(target, Line): if axis.p1 == target.p1 and axis.p2 == target.p2: return Line(target.p1, target.p2) else: unitv = (axis.p2 - axis.p1).normal() par = unitv*(target.p1 - axis.p1).pro_sum(unitv) perp = (target.p1 - axis.p1) - par pars = unitv*(target.p2 unitv*(target p2 - target.p1).pro_sum(unitv) target p1) pro sum(unitv) perps = (target.p2 - target.p1) - pars p1 = axis.p1 + par - perp return Line(p1, p1 + pars - perps) 視空間・認知空間への拡張 def hyperbolicTriangle(p, q, r): if (1.0/p + 1.0/q + 1.0/r) < 1: a = pi / p b = pi / q c = pi / r rB = tanh(1.0/2*acosh((cos(a)*cos(b)+cos(c))/(sin(a)*sin(b)))) rC = tanh(1.0/2*acosh((cos(a)*cos(c)+cos(b))/(sin(a)*sin(c)))) p2 = Point(sin(a), cos(a))*rC/rB mp = Point(((rB*(1.0 + rC**2)/sin(a)-rC*(1.0 + rB**2)/tan(a))/rC), (1+rB**2))/(2*rB) ro = sqrt((mp - Point(0,rB)).sq_sum())/rB mp = mp/rB p0 = Point(0, 0) p1 = Point(0, 1) return [[p0,p2,p1],[Line(p0,p2),Arc(mp,ro,p1,p2),Line(p0,p1)],[p,q,r]] def hyperbolicTransform(triangle): neighbors = [] for i in [[0,2,1],[1,0,2],[2,1,0]]: p0 = triangle[0][i[0]] p1 = circleInversion(triangle[1][i[0]],triangle[0][i[1]]) p2 = triangle[0][i[2]] e0 = circleInversion(triangle[1][i[0]],triangle[1][i[1]]) e1 = circleInversion(triangle[1][i[0]],triangle[1][i[2]]) e2 = triangle[1][i[0]] neighbors.append([[p0,p1,p2],[e0,e1,e2]]) return neighbors def recursion(n): if n == 0: global mplist global layers points = startTriangle[0] mplist = [(points[0] + points[1] + points[2])/3] layers = [[startTriangle]] return layers else: l angle = tan(pi/2 - 2*pi/startTriangle[2][0]) inverse = [] for piece in recursion(n - 1)[-1]: inverse = inverse + hyperbolicTransform(piece) select = [] for piece in inverse: points = piece[0] mp = (points[0] + points[1] + points[2])/3 if mp.y / mp.x < angle: continue if include(mp): continue mplist.append(mp) select.append(piece) layers.append(select) return layers def include(np): for p in mplist: if (np - p).sq_sum() < (10**-8): return True return False 地理情報科学と都市工学を融合した空間解析手法の新展開 def show(tesserae, size): c = Canvas(width=size, height=size) c.pack() sc = startTriangle[1][1].c sr = startTriangle[1][1].r lr = sqrt(sc.sq_sum()-sr**2) q q_ scale = (size/2 - 50) / lr unitc = Circle(Point(0,0),lr*scale) x1 = -lr*scale + size/2 y1 = size/2 + lr*scale x2 = lr*scale + size/2 y2 = size/2 - lr*scale c.create_oval(x1, y1, x2, y2) for i in range(startTriangle[2][0]): for layer in tesserae: for j in range(len(layer)): ( ( )) for shape in layer[j][1]: if isinstance(shape, Arc): nc = shape.c.rotate(i*2*pi / startTriangle[2][0]) ag = (Circle(nc*scale, shape.r*scale)).clip(unitc) x1 = (nc.x - shape.r)*scale + size/2 y1 = size/2 - (nc.y - shape.r)*scale x2 = (nc.x + shape.r)*scale + size/2 y2 = size/2 - (nc.y + shape.r)*scale c.create_arc(x1, y1, x2, y2,¥ start=ag[0], extent=ag[1], style='arc') n2 = Point(0, Point(0 lr).rotate((i*2-1)*pi/startTriangle[2][0]) lr) rotate((i*2 1)*pi/startTriangle[2][0]) x2 = n2.x*scale + size/2 y2 = size/2 - n2.y*scale c.create_line(size/2, size/2, x2, y2, width=1) n2 = Point(0, lr).rotate(i*2*pi/startTriangle[2][0]) x2 = n2.x*scale + size/2 y2 = size/2 - n2.y*scale c.create_line(size/2, size/2, x2, y2) mainloop() def hypergolicTessellation(p, q, r, n): global startTriangle startTriangle = hyperbolicTriangle(p, q, r) show(recursion(n), 700) Page 11 ArcGIS上での実装 地理情報科学と都市工学を融合した空間解析手法の新展開 視空間・認知空間への拡張 Page 12 バリエーション 地理情報科学と都市工学を融合した空間解析手法の新展開 視空間・認知空間への拡張 Page 13 情報化と都市の将来 参考文献 • 双曲幾何学への招待 ―複素数で視る 谷口雅彦・奥村善英 著 培風館 (1996/10) • 双曲幾何 (現代数学への入門) 深谷賢治 著 岩波書店 (2004/9/7) • Compass C and d straightedge t i ht d iin th the P Poincare i di disk k Chaim Goodman-Strauss, Amer. Math. Monthly 108 (2001), 38–49 38 49. • M. C. Escher’s Legacy A Centennial Celebration D. Schattschneider and M. Emmer(eds.), Springer(2003) • The Mathematica GuideBook for Graphics Michael Trott, Springer (2004) 地理情報科学と都市工学を融合した空間解析手法の新展開 Page 14