class Bubble: @staticmethod def getDir(key): # key is pair of Bubbles return Vector2(key[0].ring.pos, key[1].ring.pos).unit() @staticmethod def getArc(key): # key is pair of Bubbles a, b = key[0].ring, key[1].ring return math.asin(1.0 * b.r / (a.r + b.r)) dirs = None # Cache arcs = None def __init__(self): # Group Topology self.parent = None # Noke # not Bubble: for Group.buildGeometry() self.childs = [] # Nokes self.upper = False # Upper level - first child self.group = None # Parent Group of Bubble # Geometry and Correction self.ring = Ring((0, 0), 1) # For building Geometry self.tight = 0 # Left (Parents) and right (Childs) Tights self.corr = 0 # Correction of Radius self.angles = {} # dict {Bubble:angle} # Eating self.fading = None # Fading object def __repr__(self): return 'Bubble: %s' % self.ring def neighbor(self, n): "Returns previous or next neighbor (or parent if not); n = -1 or 1" if self.parent: nokes = self.parent().childs + [self.parent] bubbles = map(Noke.get, nokes) return nokes[bubbles.index(self) + n] def neighbors(self): "Iterates all neighbor Nokes" if self.childs: for n in self.childs: yield n if self.parent: yield self.parent for n in (-1, 1): neighbor = self.neighbor(n) if neighbor != self.parent: yield neighbor #def strongParents( self ): # "Skips first Parent if Bubble is not on upper level" # return self.parents[ self.upper^1 :] def lightCopy(self): "Copies main attributes of Bubble" bubble = Bubble() bubble.group = self.group bubble.ring = self.ring.copy() bubble.fading = self.fading return bubble def markUpperChilds(self, mark): self.upper = mark if self.childs: upper = self.childs[0] for c in self.childs: c().markUpperChilds(c == upper) def detTights(self): def arc(noke): return Bubble.arcs[(self, noke())] if self.parent: self.tight += arc(self.neighbor(-1)) self.tight += arc(self.neighbor(1)) if self.childs: self.tight += arc(self.childs[0]) self.tight += arc(self.childs[-1]) if not self.upper: a = self.parent() # Bubbles: Parent c = self.neighbor(-1)() # Prev Neighbor ra = c.ring.r + self.ring.r # Radiuses rb = a.ring.r + c.ring.r rc = a.ring.r + self.ring.r # Cosines ca = 1.0 * (rb**2 + rc**2 - ra**2) / (2 * rb * rc) cc = 1.0 * (ra**2 + rb**2 - rc**2) / (2 * ra * rb) aa = math.acos(ca) # Angles ac = math.acos(cc) ab = math.pi - (aa + ac) a.tight += aa # Increase Tights c.tight += ac self.tight += ab # Save angle aa for detPosition() a.angles[self] = aa def detCorrections(self): "Dets Correction values. Returns False if Correction is not needed." if not (self.parent or self.childs): # Skip single Bubbles return False minChink = math.pi * 0.2 # ?? maybe to Constants # Set tight as chink self.tight = math.pi * 2 - self.tight self.tight /= 2 if self.tight < minChink: # Correction needed self.corr += 2 for n in self.neighbors(): n( ).corr -= 0.2 # ?? Here may be wrong values, and some Figures may be unbuildable return True return False # Correction is not needed def correct(self): "Corrects Radius of Ring." if self.corr: self.ring.r *= math.exp(self.corr * 0.06) def detPosition(self): "Dets Position of Bubble. Calculates initial values of Chinks." if self.upper: if not self.parent: # Root of Group self.ring.pos = Vector2((0, 0)) return else: parent = self.parent() # Parent Bubble if not parent.parent: dir = Vector2((1, 0)) # Default direction else: parent1 = parent.neighbor(-1)() a = parent.tight + Bubble.arcs[ (parent, self)] + Bubble.arcs[(parent, parent1)] - math.pi dir = Bubble.dirs[(parent1, parent)] dir = dir.rotate(Vector2(angle=-a)) # Det direction else: parent = self.parent() prev = self.neighbor(-1)() a = parent.angles[self] dir = Bubble.dirs[(parent, prev)] dir = dir.rotate(Vector2(angle=-a)) # Det direction Bubble.dirs[(parent, self)] = dir self.ring.pos = parent.ring.pos + dir * (parent.ring.r + self.ring.r) def transform(self): """ Returns transformation Matrix of Bubble, includes transformation Matrix of Group if is. """ # Default transformation is Unit # (Variable or Lambda inside another Lambda) matrix = TransformMatrix() matrix.unit() # Group reference may not exist # (Variable or Lambda inside fading Let-Bound Variable ??) if self.group: matrix *= self.group.transformMatrix if self.ring: matrix *= TransformMatrix(ring=self.ring) return matrix
class Bubble: @staticmethod def getDir( key ): # key is pair of Bubbles return Vector2( key[0].ring.pos, key[1].ring.pos ).unit() @staticmethod def getArc( key ): # key is pair of Bubbles a,b = key[0].ring, key[1].ring return math.asin( 1.0 * b.r / (a.r + b.r) ) dirs = None # Cache arcs = None def __init__( self ): # Group Topology self.parent = None # Noke # not Bubble: for Group.buildGeometry() self.childs = [] # Nokes self.upper = False # Upper level - first child self.group = None # Parent Group of Bubble # Geometry and Correction self.ring = Ring((0,0),1) # For building Geometry self.tight = 0 # Left (Parents) and right (Childs) Tights self.corr = 0 # Correction of Radius self.angles = {} # dict {Bubble:angle} # Eating self.fading = None # Fading object def __repr__( self ): return 'Bubble: %s' % self.ring def neighbor( self, n ): "Returns previous or next neighbor (or parent if not); n = -1 or 1" if self.parent: nokes = self.parent().childs + [self.parent] bubbles = map( Noke.get, nokes ) return nokes[ bubbles.index( self ) + n ] def neighbors( self ): "Iterates all neighbor Nokes" if self.childs: for n in self.childs: yield n if self.parent: yield self.parent for n in (-1,1): neighbor = self.neighbor( n ) if neighbor != self.parent: yield neighbor #def strongParents( self ): # "Skips first Parent if Bubble is not on upper level" # return self.parents[ self.upper^1 :] def lightCopy( self ): "Copies main attributes of Bubble" bubble = Bubble() bubble.group = self.group bubble.ring = self.ring.copy() bubble.fading = self.fading return bubble def markUpperChilds( self, mark ): self.upper = mark if self.childs: upper = self.childs[0] for c in self.childs: c().markUpperChilds( c == upper ) def detTights( self ): def arc( noke ): return Bubble.arcs[ ( self,noke() ) ] if self.parent: self.tight += arc( self.neighbor(-1) ) self.tight += arc( self.neighbor( 1) ) if self.childs: self.tight += arc( self.childs[ 0] ) self.tight += arc( self.childs[-1] ) if not self.upper: a = self.parent() # Bubbles: Parent c = self.neighbor(-1)() # Prev Neighbor ra = c.ring.r + self.ring.r # Radiuses rb = a.ring.r + c.ring.r rc = a.ring.r + self.ring.r # Cosines ca = 1.0 * ( rb**2 + rc**2 - ra**2 ) / ( 2 * rb * rc ) cc = 1.0 * ( ra**2 + rb**2 - rc**2 ) / ( 2 * ra * rb ) aa = math.acos( ca ) # Angles ac = math.acos( cc ) ab = math.pi - (aa + ac) a .tight += aa # Increase Tights c .tight += ac self.tight += ab # Save angle aa for detPosition() a.angles[ self ] = aa def detCorrections( self ): "Dets Correction values. Returns False if Correction is not needed." if not ( self.parent or self.childs ): # Skip single Bubbles return False minChink = math.pi * 0.2 # ?? maybe to Constants # Set tight as chink self.tight = math.pi*2 - self.tight self.tight /= 2 if self.tight < minChink: # Correction needed self.corr += 2 for n in self.neighbors(): n().corr -= 0.2 # ?? Here may be wrong values, and some Figures may be unbuildable return True return False # Correction is not needed def correct( self ): "Corrects Radius of Ring." if self.corr: self.ring.r *= math.exp( self.corr * 0.06 ) def detPosition( self ): "Dets Position of Bubble. Calculates initial values of Chinks." if self.upper: if not self.parent: # Root of Group self.ring.pos = Vector2((0,0)) return else: parent = self.parent() # Parent Bubble if not parent.parent: dir = Vector2((1,0)) # Default direction else: parent1 = parent.neighbor( -1 )() a = parent.tight + Bubble.arcs[(parent,self)] + Bubble.arcs[(parent,parent1)] - math.pi dir = Bubble.dirs[(parent1,parent)] dir = dir.rotate( Vector2( angle= -a ) ) # Det direction else: parent = self.parent() prev = self.neighbor(-1)() a = parent.angles[ self ] dir = Bubble.dirs[(parent,prev)] dir = dir.rotate( Vector2( angle= -a ) ) # Det direction Bubble.dirs[(parent,self)] = dir self.ring.pos = parent.ring.pos + dir * (parent.ring.r + self.ring.r) def transform( self ): """ Returns transformation Matrix of Bubble, includes transformation Matrix of Group if is. """ # Default transformation is Unit # (Variable or Lambda inside another Lambda) matrix = TransformMatrix() matrix.unit() # Group reference may not exist # (Variable or Lambda inside fading Let-Bound Variable ??) if self.group: matrix *= self.group.transformMatrix if self.ring: matrix *= TransformMatrix( ring= self.ring ) return matrix