1. Cédric Bonhomme
  2. pyClique

Commits

Cédric Bonhomme  committed b9bcc07

First commit. Project name: pyClique. Tools and operations for graphs with Python.

  • Participants
  • Branches default

Comments (0)

Files changed (13)

File dijkstra.py

View file
  • Ignore whitespace
+#! /usr/local/bin/python
+# -*- coding: utf-8 -*-
+
+from priodict import priorityDictionary
+
+def Dijkstra(G,start,end=None):
+	"""
+	Find shortest paths from the start vertex to all
+	vertices nearer than or equal to the end.
+
+	The input graph G is assumed to have the following
+	representation: A vertex can be any object that can
+	be used as an index into a dictionary.  G is a
+	dictionary, indexed by vertices.  For any vertex v,
+	G[v] is itself a dictionary, indexed by the neighbors
+	of v.  For any edge v->w, G[v][w] is the length of
+	the edge.  This is related to the representation in
+	<http://www.python.org/doc/essays/graphs.html>
+	where Guido van Rossum suggests representing graphs
+	as dictionaries mapping vertices to lists of neighbors,
+	however dictionaries of edges have many advantages
+	over lists: they can store extra information (here,
+	the lengths), they support fast existence tests,
+	and they allow easy modification of the graph by edge
+	insertion and removal.  Such modifications are not
+	needed here but are important in other graph algorithms.
+	Since dictionaries obey iterator protocol, a graph
+	represented as described here could be handed without
+	modification to an algorithm using Guido's representation.
+
+	Of course, G and G[v] need not be Python dict objects;
+	they can be any other object that obeys dict protocol,
+	for instance a wrapper in which vertices are URLs
+	and a call to G[v] loads the web page and finds its links.
+	
+	The output is a pair (D,P) where D[v] is the distance
+	from start to v and P[v] is the predecessor of v along
+	the shortest path from s to v.
+	
+	Dijkstra's algorithm is only guaranteed to work correctly
+	when all edge lengths are positive. This code does not
+	verify this property for all edges (only the edges seen
+ 	before the end vertex is reached), but will correctly
+	compute shortest paths even for some graphs with negative
+	edges, and will raise an exception if it discovers that
+	a negative edge has caused it to make a mistake.
+	"""
+
+	D = {}	# dictionary of final distances
+	P = {}	# dictionary of predecessors
+	Q = priorityDictionary()   # est.dist. of non-final vert.
+	Q[start] = 0
+	
+	for v in Q:
+		D[v] = Q[v]
+		if v == end: break
+
+		for w in G[v]:
+			vwLength = D[v] + G[v][w]
+			if w in D:
+				if vwLength < D[w]:
+					raise ValueError, \
+  "Dijkstra: found better path to already-final vertex"
+			elif w not in Q or vwLength < Q[w]:
+				Q[w] = vwLength
+				P[w] = v
+
+	return (D,P)
+
+def shortest_path(G,start,end):
+	"""
+	Find a single shortest path from the given start vertex
+	to the given end vertex.
+	The input has the same conventions as Dijkstra().
+	The output is a list of the vertices in order along
+	the shortest path.
+	"""
+
+	D,P = Dijkstra(G,start,end)
+	Path = []
+	while 1:
+		Path.append(end)
+		if end == start: break
+		end = P[end]
+	Path.reverse()
+	return Path

File graphe.py

View file
  • Ignore whitespace
+#! /usr/local/bin/python
+# -*- coding: utf-8 -*-
+
+__author__ = "Cedric Bonhomme"
+__date__ = "$Date: 2012/01/31 $"
+__license__ = "GPL v3"
+
+import dijkstra
+import shortest
+
+
+class Graph(object):
+	"""Classe représentant un graphe.
+
+	Un graphe est représenté par un dictionnaire.
+	http://www.python.org/doc/essays/graphs/
+	"""
+	def __init__(self):
+		"""Initialise le graphe à vide.
+		"""
+		self.graphe = {}
+
+	def ajouteSommet(self, sommet):
+		"""Ajoute un sommet au graphe sans aucun voisin.
+		"""
+		if sommet not in self.graphe.keys():
+			self.graphe[sommet] = {}
+
+	def ajouteArrete(self, sommet, sommetVoisin, p):
+		"""Crée une arrête en relliant sommet avec sommetVoisin en associant le poids p.
+		"""
+		if sommet != sommetVoisin:
+			try:
+				self.graphe[sommetVoisin][sommet] = p
+				self.graphe[sommet][sommetVoisin] = p
+			except KeyError:
+				pass
+
+	def supprimeSommet(self, sommet):
+		"""Supprime un sommet du graphe.
+		"""
+		for sommetVoisin in self.graphe[sommet].keys():
+			del self.graphe[sommetVoisin][sommet]
+		del self.graphe[sommet]
+
+	def supprimeArrete(self, sommet, sommetVoisin):
+		"""Supprime une arrête.
+		"""
+		if sommet in self.graphe[sommetVoisin]:
+			self.supprimeSommet(sommet)
+			self.supprimeSommet(sommetVoisin)
+
+	def toMatrice(self):
+		"""Affichage matriciel du graphe.
+		"""
+		print " ",
+		for i in sorted(self.graphe.keys()):
+			print i,
+		print
+		for i in sorted(self.graphe.keys()):
+			print i,
+			for j in sorted(self.graphe.keys()):
+				if i in self.graphe[j].keys():
+					print '1',
+				else:
+					print '0',
+			print
+
+	def toListe(self):
+		"""Affiche le graphe sous forme de listes d'adjacences.
+		"""
+		for i in sorted(self.graphe.keys()):
+			print i, " --> ",
+			print self.graphe[i].keys()
+
+	def toXML(self):
+		"""Affiche le graphe sous une structure XML.
+		"""
+		from xml.dom.minidom import Document
+
+		try:
+			racine = doc.getElementsByName('graphe').item(0)
+		except:
+			doc = Document()
+			racine = doc.createElement("graphe")
+			doc.appendChild(racine)
+
+		for sommet in sorted(self.graphe.keys()):
+			try:
+				noeud = doc.getElementsByName(sommet)
+			except:
+				noeud = doc.createElement(sommet)
+				racine.appendChild(noeud)
+
+			if len(self.graphe[sommet].keys()) == 0:
+				element = doc.createTextNode("")
+				noeud.appendChild(element)
+
+			for voisin in sorted(self.graphe[sommet].keys()):
+				try:
+					element = doc.createElement("voisin")
+					element.setAttribute("nom", voisin)
+					element.setAttribute("poids", str(self.graphe[sommet][voisin]))
+					noeud.appendChild(element)
+				except:
+					pass
+
+		return doc.toprettyxml()
+	
+	def fromXML(self, fichier = "./var/graphe-example1.xml"):
+		"""Crée un graphe à partir d'un fichier XML.
+		"""
+		from xml.dom.minidom import parse
+		doc = None
+		doc = parse(fichier)
+		for sommet in doc.getElementsByTagName("graphe").item(0).childNodes:
+			for voisin in sommet.childNodes:
+				self.ajouteSommet(sommet.childNodes.item(0))
+				self.ajouteArrete(sommet, voisin, voisin)
+
+	def __eq__(self, graphe1):
+		"""Compare deux graphes.
+		"""
+		return self.graphe == graphe1
+
+	def __str__(self):
+		"""Affichage du graphe.
+		"""
+		return repr(self.graphe)
+	
+	def __repr__(self):
+		"""Représentation du graphe.
+		"""
+		return repr(self.graphe)
+
+
+if __name__ == "__main__":
+	# Point d'entrée en exécution.
+	graph = Graph()
+	graph.ajouteSommet('A')
+	graph.ajouteSommet('B')
+	graph.ajouteSommet('C')
+	graph.ajouteSommet('D')
+	graph.ajouteSommet('E')
+	graph.ajouteSommet('F')
+
+	graph.ajouteArrete('A', 'C', 2)
+	graph.ajouteArrete('D', 'B', 2)
+	graph.ajouteArrete('B', 'C', 800)
+	graph.ajouteArrete('B', 'D', 7)
+	graph.ajouteArrete('C', 'D', 7)
+	graph.ajouteArrete('F', 'A', 7)
+	print graph
+	graph.toMatrice()
+	graph.toListe()
+	#print graph.toXML()
+	#grapheXML = open('graphe.xml', 'w')
+	#grapheXML.write(graph.toXML())
+	#grapheXML.close()
+	#graph = Graph()
+	#graph.fromXML()
+	#print graph
+	print dijkstra.shortest_path(graph.graphe, 'A', 'B')
+	print shortest.find_shortest_path(graph.graphe, 'A', 'B')
+	print shortest.find_all_paths(graph.graphe, 'A', 'B')

File priodict.py

View file
  • Ignore whitespace
+from __future__ import generators
+
+class priorityDictionary(dict):
+    def __init__(self):
+        '''Initialize priorityDictionary by creating binary heap
+of pairs (value,key).  Note that changing or removing a dict entry will
+not remove the old pair from the heap until it is found by smallest() or
+until the heap is rebuilt.'''
+        self.__heap = []
+        dict.__init__(self)
+
+    def smallest(self):
+        '''Find smallest item after removing deleted items from heap.'''
+        if len(self) == 0:
+            raise IndexError, "smallest of empty priorityDictionary"
+        heap = self.__heap
+        while heap[0][1] not in self or self[heap[0][1]] != heap[0][0]:
+            lastItem = heap.pop()
+            insertionPoint = 0
+            while 1:
+                smallChild = 2*insertionPoint+1
+                if smallChild+1 < len(heap) and \
+                        heap[smallChild] > heap[smallChild+1]:
+                    smallChild += 1
+                if smallChild >= len(heap) or lastItem <= heap[smallChild]:
+                    heap[insertionPoint] = lastItem
+                    break
+                heap[insertionPoint] = heap[smallChild]
+                insertionPoint = smallChild
+        return heap[0][1]
+
+    def __iter__(self):
+        '''Create destructive sorted iterator of priorityDictionary.'''
+        def iterfn():
+            while len(self) > 0:
+                x = self.smallest()
+                yield x
+                del self[x]
+        return iterfn()
+
+    def __setitem__(self,key,val):
+        '''Change value stored in dictionary and add corresponding
+pair to heap.  Rebuilds the heap if the number of deleted items grows
+too large, to avoid memory leakage.'''
+        dict.__setitem__(self,key,val)
+        heap = self.__heap
+        if len(heap) > 2 * len(self):
+            self.__heap = [(v,k) for k,v in self.iteritems()]
+            self.__heap.sort()  # builtin sort likely faster than O(n) heapify
+        else:
+            newPair = (val,key)
+            insertionPoint = len(heap)
+            heap.append(None)
+            while insertionPoint > 0 and \
+                    newPair < heap[(insertionPoint-1)//2]:
+                heap[insertionPoint] = heap[(insertionPoint-1)//2]
+                insertionPoint = (insertionPoint-1)//2
+            heap[insertionPoint] = newPair
+
+    def setdefault(self,key,val):
+        '''Reimplement setdefault to call our customized __setitem__.'''
+        if key not in self:
+            self[key] = val
+        return self[key]

File rtgraph3d/__init__.py

View file
  • Ignore whitespace
+"""IP-Link
+
+Visualiser les relations entre les differentes IP d'une capture.
+"""
+
+__all__ = ['rtgraph3d']
+
+__version__ = '0.1'

File rtgraph3d/hydra.py

View file
  • Ignore whitespace
+#!/usr/bin/env python
+
+
+import gobject
+
+import dbus
+import dbus.mainloop.glib
+
+
+def sclick_signal_handler(node):
+    global rtg
+    for i in range(4):
+        rtg.new_edge(node,{}, "%s%i" % (node,i),{})
+
+
+
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+bus = dbus.SessionBus()
+control= bus.get_object("org.secdev.rtgraph3d","/control")
+control.connect_to_signal("node_shift_click", sclick_signal_handler, dbus_interface="org.secdev.rtgraph3d.events")
+rtg = dbus.Interface(control, "org.secdev.rtgraph3d.command")
+
+
+loop = gobject.MainLoop()
+loop.run()

File rtgraph3d/povexport.py

View file
  • Ignore whitespace
+# ruth chabay, carnegie mellon university (rchabay@andrew.cmu.edu)
+# v1.0 2000-12-17
+
+# Markus Gritsch (gritsch@iue.tuwien.ac.at)
+# v.1.1   2001-03-09
+#   *) replaced 'scene' by 'display' everywhere
+#   *) added spheres at the joints of a curve
+#   *) consistent pov_texture usage in process_arrow() also for the shaft
+#   *) ambient light, light sources, up, and fov are now handled correctly
+#   *) some cosmetic changes to the code
+# v.1.1.1 2001-03-22
+#   *) added 'shadowless' keyword to export()
+
+# Ruth Chabay
+# 2001-06-23
+# hack to fix error in export_curve introduced by Python 2.1
+# now can't assign obj.color = array(...)
+
+# Markus Gritsch (gritsch@iue.tuwien.ac.at)
+# v.1.2   2001-11-23
+#   *) added 'xy_ratio' and 'custom_text' keywords to export()
+#   *) the pov-strings are now directly written to a file
+
+# Bruce Sherwood
+# 2004-07-18
+# add dictionary ("legal") for identifying an object so that
+# povexport will continue to work with the new Boost-based VPython
+# which changes the details returned by object.__class__
+
+## NOTE: when changing this module please change the following string:
+POVEXPORT_VERSION = "povexport 2004-07-18"
+
+"""This module exports a VPython scene as POV-Ray scene description code.
+Lights and camera location from the current visual scene are included.
+Optionally, you may specify a list of include files, and pov textures for
+objects.
+For an example of its use, see 'povexample.py'
+convex objects are not exported.
+"""
+
+from visual import *
+from string import rfind
+
+legal = {frame:'frame', sphere:'sphere', box:'box', cylinder:'cylinder',
+                   curve:'curve', ring:'ring', arrow:'arrow',
+                   cone:'cone'}
+ihat=vector(1, 0, 0)
+jhat=vector(0, 1, 0)
+khat=vector(0, 0, 1)
+
+def version():
+    return POVEXPORT_VERSION
+
+def getpolar(a):
+    # a is a vector
+    # find rotation angles (standard polar coord)
+    xy = sqrt(a.x**2 + a.y**2)
+    theta = atan2(xy, a.z)
+    phi = atan2(a.y, a.x)
+    return [theta, phi]
+
+def process_frame(a, code):
+    # add in frame rotations & translations (may be nested)
+    frame_code = ''
+    fr = a.frame
+    while fr:
+        # orientation of frame.axis
+        ang = getpolar(fr.axis)
+        theta=ang[0]
+        phi=ang[1]
+        aup = fr.up*1.0
+        # find rotation around x-axis (if fr.up <> jhat)
+        # "undo" theta & phi rotations so can find alpha
+        aup = rotate(aup, axis=khat, angle=-phi)
+        aup = rotate(aup, axis=jhat, angle=pi/2.0-theta)
+        a_sin = dot(cross(jhat, norm(aup)), ihat)
+        a_cos = dot(norm(aup), jhat)
+        alpha = atan2(a_sin, a_cos)
+        frx=alpha*180./pi
+        fry=-90+theta*180./pi
+        frz=phi*180./pi
+        rrot = '    rotate <%f, %f, %f>\n'
+        ttrn = '    translate <%f, %f, %f>\n'
+        frame_code += rrot % (frx, fry, frz)
+        frame_code += ttrn % (fr.x, fr.y, fr.z)
+        fr = fr.frame
+
+    # insert frame_code at end (these rot's must be done last)
+    end = rfind(code, '}')
+    code = code[:end] + frame_code + code[end:]
+    return code
+
+def add_texture(a, code):
+    # add in user-specified texture (will override color)
+    if hasattr(a, 'pov_texture'):
+        tstring = '    texture { '+ a.pov_texture + ' }\n'
+        end = rfind(code, '}')
+        code = code[:end] + tstring + code[end:]
+    return code
+
+def export_sphere(a):
+    sphere_template = """
+sphere {
+    <%(posx)f, %(posy)f, %(posz)f>, %(radius)f
+    pigment { color rgb <%(red)f, %(green)f, %(blue)f> }
+}
+"""
+    object_code = sphere_template % { 'posx':a.x, 'posy':a.y, 'posz':a.z,
+                                      'radius':a.radius,
+                                      'red':a.red, 'green':a.green, 'blue':a.blue }
+    object_code = process_frame(a, object_code)
+    object_code = add_texture(a, object_code)
+    return object_code
+
+def export_box(a):
+    # create box at origin along x-axis
+    # then rotate around x,y,z axes
+    # then translate to final location
+    box_template = """
+box {
+    <%(posx)f, %(posy)f, %(posz)f>, <%(pos2x)f, %(pos2y)f, %(pos2z)f>
+    pigment {color rgb <%(red)f, %(green)f, %(blue)f>}
+    rotate <%(rotx)f, %(roty)f, %(rotz)f>
+    translate <%(transx)f, %(transy)f, %(transz)f>
+}
+"""
+    # find rotations
+    ang = getpolar(a.axis)
+    theta = ang[0]
+    phi = ang[1]
+    # find rotation around x-axis (if a.up <> jhat)
+    # "undo" theta & phi rotations so can find alpha
+    aup = a.up*1.0
+    aup = rotate(aup, axis=khat, angle=-phi)
+    aup = rotate(aup, axis=jhat, angle=pi/2.0-theta)
+    a_sin = dot(cross(jhat, norm(aup)), ihat)
+    a_cos = dot(norm(aup), jhat)
+    alpha = atan2(a_sin, a_cos)
+    # pos of visual box is at center
+    # generate two opposite corners for povray
+    pos1=vector(0, 0, 0) - a.size / 2.0
+    pos2=vector(0, 0, 0) + a.size / 2.0
+
+    object_code = box_template % { 'posx':pos1.x, 'posy':pos1.y, 'posz':pos1.z,
+                                   'pos2x':pos2.x, 'pos2y':pos2.y, 'pos2z':pos2.z,
+                                   'rotx':alpha*180./pi, 'roty':-90.+theta*180./pi, 'rotz':phi*180./pi,
+                                   'transx':a.x, 'transy':a.y, 'transz':a.z,
+                                   'red':a.red, 'green':a.green, 'blue':a.blue }
+    object_code = process_frame(a, object_code)
+    object_code = add_texture(a, object_code)
+    return object_code
+
+
+def export_cylinder(a):
+    cylinder_template = """
+cylinder {
+    <%(posx)f, %(posy)f, %(posz)f>,<%(pos2x)f, %(pos2y)f, %(pos2z)f>, %(radius)f
+    pigment { color rgb <%(red)f, %(green)f, %(blue)f> }
+}
+"""
+    endpt1=a.pos
+    endpt2=a.pos+a.axis
+    object_code = cylinder_template % { 'posx':a.x, 'posy':a.y, 'posz':a.z,
+                                        'pos2x':endpt2.x, 'pos2y':endpt2.y, 'pos2z':endpt2.z,
+                                        'red':a.red, 'green':a.green, 'blue':a.blue,
+                                        'radius':a.radius }
+    object_code = process_frame(a, object_code)
+    object_code = add_texture(a, object_code)
+    return object_code
+
+def export_curve(a):
+    object_code = ''
+    if len(a.pos) > 1:
+        ii = 0
+        while ii < len(a.pos)-1:
+            endpt1 = a.pos[ii]
+            endpt2 = a.pos[ii+1]
+            if a.radius > 0:
+                rr = a.radius
+            else:
+                rr = mag(endpt1-endpt2)/200.
+            # create a dummy cylinder to export
+            ccyl = cylinder(pos=endpt1, axis=endpt2-endpt1, radius=rr, color=tuple(a.color[ii]),
+                            frame=a.frame, visible=0)
+            csph = sphere(pos=endpt1, radius=rr, color=tuple(a.color[ii]),
+                          frame=a.frame, visible=0)
+            if hasattr(a, 'pov_texture'):
+                ccyl.pov_texture = a.pov_texture
+                csph.pov_texture = a.pov_texture
+            object_code += export_cylinder(ccyl) + export_sphere(csph)
+            ii = ii+1
+        endpt1 = a.pos[ii]
+        csph = sphere(pos=endpt1, radius=rr, color=tuple(a.color[ii]),
+                      frame=a.frame, visible=0)
+        if hasattr(a, 'pov_texture'):
+            csph.pov_texture = a.pov_texture
+        object_code += export_sphere(csph)
+    del(ccyl)
+    del(csph)
+    return object_code
+
+def export_ring(a):
+    torus_template = """
+torus {
+    %(radius)f, %(minorradius)f
+    pigment { color rgb <%(red)f, %(green)f, %(blue)f> }
+    rotate <0.0, 0.0, -90.0> // align with x-axis
+    rotate <%(rotx)f, %(roty)f, %(rotz)f>
+    translate <%(transx)f, %(transy)f, %(transz)f>
+}
+"""
+    ang = getpolar(a.axis)
+    theta = ang[0]
+    phi = ang[1]
+    object_code = torus_template % { 'radius':a.radius, 'minorradius':a.thickness,
+                                     'transx':a.x, 'transy':a.y, 'transz':a.z,
+                                     'rotx':0.0, 'roty':-90.+theta*180./pi, 'rotz':phi*180./pi,
+                                     'red':a.red, 'green':a.green, 'blue':a.blue }
+    object_code = process_frame(a, object_code)
+    object_code = add_texture(a, object_code)
+    return object_code
+
+def export_arrow(a):
+    pyramid_template = """
+object {Pyramid
+    pigment { color rgb <%(red)f, %(green)f, %(blue)f> }
+    scale <%(scalex)f, %(scaley)f, %(scalez)f>
+    rotate <0, 0, -90> // align with x-axis
+    rotate <%(rotx)f, %(roty)f, %(rotz)f>
+    translate <%(transx)f, %(transy)f, %(transz)f>
+}
+"""
+    al = a.length
+    hl = a.headlength
+    sl = al-hl # length of shaft
+    hw = a.headwidth
+    sw = a.shaftwidth
+    # head is a pyramid
+    ppos = a.pos+a.axis*(sl/al)
+    ang = getpolar(a.axis)
+    theta=ang[0]
+    phi=ang[1]
+    m1 = pyramid_template % { 'scalex':hw, 'scaley':hl, 'scalez':hw,
+                              'rotx':0., 'roty':-90.+theta*180./pi, 'rotz':phi*180./pi,
+                              'red':a.red, 'green':a.green, 'blue':a.blue,
+                              'transx':ppos.x, 'transy':ppos.y, 'transz':ppos.z }
+    m1 = process_frame(a, m1)
+    m1 = add_texture(a, m1)
+
+    # shaft is a box; need to create a dummy box
+    abox = box(pos=a.pos+a.axis*(sl/al)/2.0, axis=a.axis*(sl/al),
+               up = a.up, width=a.shaftwidth, height=a.shaftwidth,
+               color=a.color, frame=a.frame, visible = 0)
+    m2 = export_box(abox)
+    m2 = add_texture(a, m2)
+    del(abox)
+    # concatenate pyramid & box
+    object_code = m1 + m2
+    return object_code
+
+def export_cone(a):
+    cone_template = """
+cone {
+    <%(posx)f, %(posy)f, %(posz)f>, %(radius)f
+    <%(pos2x)f, %(pos2y)f, %(pos2z)f>, %(minorradius)f
+    pigment { color rgb <%(red)f, %(green)f, %(blue)f> }
+}
+"""
+    pos2 = a.pos+a.axis
+    object_code = cone_template % { 'radius':a.radius, 'minorradius':0.0,
+                                    'posx':a.x, 'posy':a.y, 'posz':a.z,
+                                    'pos2x':pos2.x, 'pos2y':pos2.y, 'pos2z':pos2.z,
+                                    'red':a.red, 'green':a.green, 'blue':a.blue }
+    object_code = process_frame(a,object_code)
+    object_code = add_texture(a,object_code)
+    return object_code
+
+def export(display=None, filename=None, include_list=None, xy_ratio=4./3., custom_text='', shadowless=0):
+    if display == None:         # no display specified so find active display
+        dummy = sphere(visible=0)
+        display = dummy.display
+        del(dummy)
+
+    if filename == None:
+        filename = display.title + '.pov'
+
+    if include_list == None:
+        include_text = ''
+    else:
+        include_text = '\n'
+        for x in include_list:
+            include_text = include_text + '#include "'+ x + '"\n'
+
+    initial_comment = """// povray code generated by povexport.py
+"""
+
+    pyramid_def = """
+// Four-sided pyramid from shapes2.inc, slightly modified.
+#declare Pyramid = union {
+    triangle { <-1, 0, -1>, <+1, 0, -1>, <0, 1, 0> }
+    triangle { <+1, 0, -1>, <+1, 0, +1>, <0, 1, 0> }
+    triangle { <-1, 0, +1>, <+1, 0, +1>, <0, 1, 0> }
+    triangle { <-1, 0, +1>, <-1, 0, -1>, <0, 1, 0> }
+    triangle { <-1, 0, -1>, <-1, 0, +1>, <1, 0, 1> }
+    triangle { <-1, 0, -1>, <+1, 0, -1>, <1, 0, 1> }
+    scale <.5, 1, .5>        // so height = width = 1
+}
+"""
+
+    ambient_template = """
+global_settings { ambient_light rgb <%(amb)f, %(amb)f, %(amb)f> }
+"""
+
+    background_template = """
+background { color rgb <%(red)f, %(green)f, %(blue)f> }
+"""
+
+    light_template = """
+light_source { <%(posx)f, %(posy)f, %(posz)f>
+    color rgb <%(int)f, %(int)f, %(int)f>
+}
+"""
+
+    camera_template = """
+camera {
+    right <-%(xyratio)f, 0, 0>      //visual uses right-handed coord. system
+    location <%(posx)f, %(posy)f, %(posz)f>
+    sky <%(upx)f, %(upy)f, %(upz)f>
+    look_at <%(pos2x)f, %(pos2y)f, %(pos2z)f>
+    angle %(fov)f
+    rotate <0, 0, 0>
+}
+"""
+
+    # begin povray setup
+    file = open(filename, 'wt')
+
+    file.write( initial_comment + include_text + custom_text + pyramid_def )
+    file.write( ambient_template % { 'amb':display.ambient*10 } )
+    file.write( background_template % { 'red':display.background[0],
+                                        'green':display.background[1],
+                                        'blue':display.background[2] } )
+
+    for i in arange(len(display.lights)): # reproduce visual lighting (not ideal, but good approximation)
+        light = display.lights[i] # vector in direction of light
+        intensity = mag(light) # intensity of light (all lights are white)
+        pos = norm(light) * max(display.range) * 100.0 # far away to simulate parallel light
+        light_code = light_template % { 'posx':pos.x, 'posy':pos.y, 'posz':pos.z,
+                                        'int':intensity*5/3. }
+        if shadowless:
+            # insert frame_code at end (these rot's must be done last)
+            end = rfind(light_code, '}')
+            light_code = light_code[:end] + '    shadowless\n' + light_code[end:]
+
+        file.write( light_code )
+
+    cpos = display.mouse.camera
+    ctr = display.center
+    cup = display.up
+    file.write( camera_template % { 'xyratio':xy_ratio,
+                                    'posx':cpos.x, 'posy':cpos.y, 'posz':cpos.z,
+                                    'upx':cup.x, 'upy':cup.y, 'upz':cup.z,
+                                    'pos2x':ctr.x, 'pos2y':ctr.y, 'pos2z':ctr.z,
+                                    'fov':display.fov*180/pi } )
+
+    for obj in display.objects:
+        key = obj.__class__
+        if legal.has_key(key):
+            obj_name = legal[key]
+            if obj_name != 'frame':
+                function_name = 'export_' + obj_name
+                function = globals().get(function_name)
+                object_code = function(obj)
+                file.write( object_code )
+        else:
+            print 'WARNING: export function for ' + obj_name + ' not implemented'
+
+    file.close()
+    return 'The export() function no longer returns the scene as an\n' \
+           'endless POV-Ray string, but saves it to a file instead.'
+
+
+if __name__ == '__main__':
+    print __doc__
+

File rtgraph3d/rtg/c60.rtg

View file
  • Ignore whitespace
+('A1', {'color': (0.5288119912147522, 0.0014943141723051667, 0.94067728519439697), 'pos': vector(-5.75041961938597, -4.79292337548697, -9.9097238836336)}, ['A5', 'A2', 'B1'])
+('A2', {'color': (0.8534393310546875, 0.8629874587059021, 0.95241141319274902), 'pos': vector(-3.75536764896122, -1.25354317181289, -11.8892683346245)}, ['C1', 'A3', 'A1'])
+('A3', {'color': (0.55395221710205078, 0.4473986029624939, 0.5079423189163208), 'pos': vector(0.568659127931001, -2.51414760302106, -12.2604555153539)}, ['A4', 'A2', 'D1'])
+('A4', {'color': (0.84864950180053711, 0.068213574588298798, 0.5807260274887085), 'pos': vector(1.2941203469892, -6.58934443814073, -10.4107022807807)}, ['E1', 'A5', 'A3'])
+('A5', {'color': (0.79558813571929932, 0.79201358556747437, 0.25907176733016968), 'pos': vector(-2.6984290476277, -8.02526512460131, -8.94187849865042)}, ['A1', 'F1', 'A4'])
+('B1', {'color': (0.78570371866226196, 0.96952646970748901, 0.95666450262069702), 'pos': vector(-9.14928433719951, -3.89984214503641, -7.01152524824169)}, ['B5', 'A1', 'B2'])
+('B2', {'color': (0.018302997574210167, 0.51547414064407349, 0.68078017234802246), 'pos': vector(-10.3245928737962, 0.394577151020054, -6.10762419878371)}, ['B3', 'B1', 'C5'])
+('B3', {'color': (0.48238483071327209, 0.28379625082015991, 0.99357622861862183), 'pos': vector(-11.323920716696, 0.677837694654808, -1.72026264161551)}, ['B4', 'B2', 'H4'])
+('B4', {'color': (0.75676578283309937, 0.52294635772705078, 0.45939895510673523), 'pos': vector(-10.802473759631, -3.42136697144488, 0.0970940870357408)}, ['B5', 'B3', 'L3'])
+('B5', {'color': (0.33439448475837708, 0.94400590658187866, 0.2257886528968811), 'pos': vector(-9.44571578442312, -6.27086053809863, -3.16517264869)}, ['B1', 'B4', 'F2'])
+('C1', {'color': (0.78768080472946167, 0.57124727964401245, 0.70245343446731567), 'pos': vector(-4.8980332990346, 3.09745569184395, -10.9592507008482)}, ['C5', 'C2', 'A2'])
+('C2', {'color': (0.15810728073120117, 0.089891001582145691, 0.43403103947639465), 'pos': vector(-1.74996925015104, 6.2975926493581, -10.37774700179)}, ['C3', 'D5', 'C1'])
+('C3', {'color': (0.57907092571258545, 0.94743114709854126, 0.065551631152629852), 'pos': vector(-3.0323965686624, 9.1588468282073, -7.08827552438996)}, ['C4', 'C2', 'I4'])
+('C4', {'color': (0.8374364972114563, 0.7492184042930603, 0.97029954195022583), 'pos': vector(-7.03090397671513, 7.63660383861178, -5.61654127031408)}, ['C5', 'C3', 'H3'])
+('C5', {'color': (0.071561455726623535, 0.053099974989891052, 0.95170038938522339), 'pos': vector(-8.20805994116073, 3.96036749403861, -8.01692292503474)}, ['C1', 'C4', 'B2'])
+('D1', {'color': (0.43409013748168945, 0.98366063833236694, 0.44179171323776245), 'pos': vector(3.75952619949964, 0.663336540220428, -11.7143453013506)}, ['D5', 'D2', 'A3'])
+('D2', {'color': (0.39974689483642578, 0.49173489212989807, 0.9547111988067627), 'pos': vector(7.50376004796992, -0.378642564046194, -9.39595727571328)}, ['E5', 'D3', 'D1'])
+('D3', {'color': (0.02708711102604866, 0.45735785365104675, 0.69146114587783813), 'pos': vector(8.6813808445609, 3.35146047980754, -7.13145553449154)}, ['D4', 'D2', 'J4'])
+('D4', {'color': (0.7434954047203064, 0.61181068420410156, 0.70276641845703125), 'pos': vector(5.65264010592973, 6.6205791071258, -7.94058613600765)}, ['D5', 'I3', 'D3'])
+('D5', {'color': (0.061684295535087585, 0.93714064359664917, 0.37149882316589355), 'pos': vector(2.59246249045951, 4.95877937935412, -10.8123107605197)}, ['D1', 'D4', 'C2'])
+('E1', {'color': (0.68346905708312988, 0.18877114355564117, 0.31489062309265137), 'pos': vector(4.99670176729045, -7.63356141674402, -7.95568226755933)}, ['E5', 'E2', 'A4'])
+('E2', {'color': (0.45309817790985107, 0.94601017236709595, 0.47324943542480469), 'pos': vector(4.93118944844085, -9.94040984456063, -4.06620657757943)}, ['E3', 'F5', 'E1'])
+('E3', {'color': (0.82244402170181274, 0.2589360773563385, 0.2898920476436615), 'pos': vector(7.92127914221386, -8.17995011365961, -1.15595225652145)}, ['E4', 'K4', 'E2'])
+('E4', {'color': (0.031205417588353157, 0.97831195592880249, 0.45049569010734558), 'pos': vector(9.89198503117583, -4.75510718181198, -3.3126872732264)}, ['E5', 'J3', 'E3'])
+('E5', {'color': (0.85365021228790283, 0.96471840143203735, 0.1532878577709198), 'pos': vector(8.12984236533998, -4.45837470444955, -7.4653334847761)}, ['D2', 'E1', 'E4'])
+('F1', {'color': (0.58582842350006104, 0.12518537044525146, 0.79959595203399658), 'pos': vector(-2.86622569026019, -10.431198129197, -5.06042469431076)}, ['F5', 'F2', 'A5'])
+('F2', {'color': (0.12375100702047348, 0.040815010666847229, 0.25237429141998291), 'pos': vector(-6.29574782203164, -9.48800599544796, -2.27443256332564)}, ['F3', 'F1', 'B5'])
+('F3', {'color': (0.83960872888565063, 0.66493827104568481, 0.64959514141082764), 'pos': vector(-4.59378659413496, -9.95602488914404, 1.88756956407376)}, ['L4', 'F4', 'F2'])
+('F4', {'color': (0.64987140893936157, 0.80985808372497559, 0.95005273818969727), 'pos': vector(-0.189222277972581, -10.9980566140569, 1.75453091939394)}, ['K3', 'F5', 'F3'])
+('F5', {'color': (0.96724951267242432, 0.57107686996459961, 0.21005354821681976), 'pos': vector(0.862214093838212, -11.3707343285419, -2.61431561573656)}, ['F1', 'F4', 'E2'])
+('G1', {'color': (0.39067023992538452, 0.10142167657613754, 0.52496713399887085), 'pos': vector(-1.47564425909985, 6.15208895798514, 7.97146609982354)}, ['G5', 'G2', 'H1'])
+('G2', {'color': (0.99607980251312256, 0.42234858870506287, 0.26000547409057617), 'pos': vector(2.55481320392445, 7.65792102501915, 6.54829937118636)}, ['G3', 'G1', 'I1'])
+('G3', {'color': (0.9601292610168457, 0.22007711231708527, 0.15265272557735443), 'pos': vector(5.6217118316048, 4.43524410588727, 7.39569656215687)}, ['G4', 'J1', 'G2'])
+('G4', {'color': (0.35058405995368958, 0.49233174324035645, 0.89550822973251343), 'pos': vector(3.49882074838787, 0.962827614705135, 9.40891988224667)}, ['G5', 'G3', 'K1'])
+('G5', {'color': (0.30028191208839417, 0.13836249709129333, 0.61283838748931885), 'pos': vector(-0.904661122003135, 2.02028123936907, 9.70455371853507)}, ['L1', 'G1', 'G4'])
+('H1', {'color': (0.34566661715507507, 0.83833503723144531, 0.30386561155319214), 'pos': vector(-5.28052195964338, 7.14140690021744, 5.60832822019765)}, ['G1', 'H5', 'H2'])
+('H2', {'color': (0.37186014652252197, 0.24269390106201172, 0.44595912098884583), 'pos': vector(-4.96214027397137, 9.56251763209535, 1.78306728750745)}, ['H3', 'H1', 'I5'])
+('H3', {'color': (0.45144650340080261, 0.36701208353042603, 0.031509537249803543), 'pos': vector(-7.96131690837421, 7.86093429959301, -1.16288092900329)}, ['H4', 'H2', 'C4'])
+('H4', {'color': (0.26787015795707703, 0.15736475586891174, 0.57579261064529419), 'pos': vector(-10.1453558950515, 4.36827201301856, 0.719807493682286)}, ['H5', 'H3', 'B3'])
+('H5', {'color': (0.32426288723945618, 0.50729620456695557, 0.62528800964355469), 'pos': vector(-8.49881079278152, 4.00320452572021, 4.91921184148759)}, ['L2', 'H1', 'H4'])
+('I1', {'color': (0.61970055103302002, 0.68172252178192139, 0.64993083477020264), 'pos': vector(2.85580049958522, 10.076849414712, 2.65833960807583)}, ['I5', 'G2', 'I2'])
+('I2', {'color': (0.61368495225906372, 0.38326111435890198, 0.20596811175346375), 'pos': vector(6.04038821485295, 9.15414245169247, -0.448043799107332)}, ['J5', 'I3', 'I1'])
+('I3', {'color': (0.34201914072036743, 0.63736271858215332, 0.19487765431404114), 'pos': vector(4.350913943678, 9.5085889651021, -4.62518775719538)}, ['I4', 'D4', 'I2'])
+('I4', {'color': (0.35329991579055786, 0.74563401937484741, 0.8142130970954895), 'pos': vector(0.0425422898966718, 10.801379952987, -4.12239932638497)}, ['I5', 'C3', 'I3'])
+('I5', {'color': (0.76402384042739868, 0.6326027512550354, 0.42730686068534851), 'pos': vector(-0.897339005929546, 11.0530164656039, 0.313173490495978)}, ['I1', 'H2', 'I4'])
+('J1', {'color': (0.53307181596755981, 0.48841613531112671, 0.90623325109481812), 'pos': vector(8.87916321695092, 3.64949870121306, 4.28155408126558)}, ['J5', 'G3', 'J2'])
+('J2', {'color': (0.1710025817155838, 0.38105598092079163, 0.065373547375202179), 'pos': vector(10.0695863177086, -0.625888469110954, 3.43396753539652)}, ['J3', 'J1', 'K5'])
+('J3', {'color': (0.80599468946456909, 0.72783404588699341, 0.087705202400684357), 'pos': vector(10.98032186285, -1.00524755543055, -0.980969245896436)}, ['J4', 'E4', 'J2'])
+('J4', {'color': (0.98883450031280518, 0.38386327028274536, 0.89999485015869141), 'pos': vector(10.3856337758079, 3.02427184775937, -2.91478238996553)}, ['D3', 'J5', 'J3'])
+('J5', {'color': (0.89261460304260254, 0.95478874444961548, 0.20518945157527924), 'pos': vector(9.0902361521186, 5.88265578223707, 0.349109737709066)}, ['J1', 'J4', 'I2'])
+('K1', {'color': (0.18497276306152344, 0.47270146012306213, 0.32865938544273376), 'pos': vector(4.67502921681134, -3.35413127246726, 8.52135105162135)}, ['G4', 'K5', 'K2'])
+('K2', {'color': (0.86585414409637451, 0.63432514667510986, 0.37000554800033569), 'pos': vector(1.40066903524345, -6.44007018094993, 7.87897817892068)}, ['K3', 'K1', 'L5'])
+('K3', {'color': (0.18858514726161957, 0.40600433945655823, 0.80375367403030396), 'pos': vector(2.89022144037011, -9.29897801139711, 4.69801525489944)}, ['F4', 'K4', 'K2'])
+('K4', {'color': (0.67538529634475708, 0.79633748531341553, 0.92766422033309937), 'pos': vector(6.97076906716986, -7.85075698353994, 3.2939812253814)}, ['K5', 'E3', 'K3'])
+('K5', {'color': (0.22738288342952728, 0.65811049938201904, 0.080000489950180054), 'pos': vector(8.04863961045261, -4.10614997802396, 5.59440045366691)}, ['K1', 'J2', 'K4'])
+('L1', {'color': (0.2190314382314682, 0.38781893253326416, 0.7735326886177063), 'pos': vector(-4.22341019285126, -1.06966534809948, 9.01632978245361)}, ['L5', 'L2', 'G5'])
+('L2', {'color': (0.043577738106250763, 0.2308025062084198, 0.55921131372451782), 'pos': vector(-7.95295158527943, -0.156147938973735, 6.64289165031297)}, ['H5', 'L3', 'L1'])
+('L3', {'color': (0.60077375173568726, 0.96889418363571167, 0.51862996816635132), 'pos': vector(-9.08438719219513, -3.89340176170426, 4.31098157584704)}, ['L4', 'B4', 'L2'])
+('L4', {'color': (0.44440484046936035, 0.30687132477760315, 0.43811792135238647), 'pos': vector(-5.99414526227504, -7.07324508133054, 5.15062657720708)}, ['L5', 'L3', 'F3'])
+('L5', {'color': (0.18744073808193207, 0.11957890540361404, 0.60402709245681763), 'pos': vector(-3.02754625128855, -5.33710057590979, 8.10857361885559)}, ['L1', 'K2', 'L4'])

File rtgraph3d/rtg/hexadeca.rtg

View file
  • Ignore whitespace
+('A', {'color': (0.53832477331161499, 0.028497094288468361, 0.30656507611274719), 'pos': vector(5.02308181152768, 0.548893282389242, 6.05540171147495)}, ['F', 'B', 'G'])
+('B', {'color': (0.78027641773223877, 0.53699928522109985, 0.14628018438816071), 'pos': vector(5.7833469904685, -3.33367429803165, 3.8990128893597)}, ['C', 'I', 'A'])
+('C', {'color': (0.77930885553359985, 0.95466971397399902, 0.64567345380783081), 'pos': vector(2.33044911920017, -5.71124283267281, 2.24791622741361)}, ['K', 'D', 'B'])
+('D', {'color': (0.27973327040672302, 0.12553730607032776, 0.77922028303146362), 'pos': vector(-1.89637623413901, -4.36939081780662, 3.04422959938482)}, ['E', 'C', 'M'])
+('E', {'color': (0.51119899749755859, 0.48246952891349792, 0.043200548738241196), 'pos': vector(-2.66441301063822, -0.488052529871988, 5.20029190591126)}, ['F', 'O', 'D'])
+('F', {'color': (0.98406100273132324, 0.612834632396698, 0.54024356603622437), 'pos': vector(0.793616908194265, 1.88502559871578, 6.84650951586767)}, ['A', 'E', 'Q'])
+('G', {'color': (0.78614956140518188, 0.98416829109191895, 0.74568742513656616), 'pos': vector(7.10748313134284, 3.81534859287195, 3.80376643072677)}, ['R', 'H', 'A'])
+('H', {'color': (0.50195455551147461, 0.89574617147445679, 0.90470778942108154), 'pos': vector(9.16349317704401, 1.96320591226249, 0.248199490581331)}, ['I', 'G', 'U'])
+('I', {'color': (0.064780391752719879, 0.92252540588378906, 0.47775489091873169), 'pos': vector(8.48985203832061, -2.42492960722103, 0.490702926201756)}, ['B', 'H', 'J'])
+('J', {'color': (0.3304385244846344, 0.45957416296005249, 0.068607345223426819), 'pos': vector(6.65589028016715, -3.86489626298517, -3.29511384532013)}, ['K', 'V', 'I'])
+('K', {'color': (0.51258569955825806, 0.34402346611022949, 0.53464394807815552), 'pos': vector(2.86750696094991, -6.03908891241967, -2.18937608803947)}, ['C', 'J', 'L'])
+('L', {'color': (0.25311467051506042, 0.25962662696838379, 0.85773098468780518), 'pos': vector(-1.02605860637536, -4.90232129345365, -4.15191624014421)}, ['M', 'X', 'K'])
+('M', {'color': (0.83966416120529175, 0.47838014364242554, 0.46404877305030823), 'pos': vector(-3.94364811665185, -4.10273469559151, -0.893501227852572)}, ['D', 'L', 'N'])
+('N', {'color': (0.66194349527359009, 0.82902711629867554, 0.29912996292114258), 'pos': vector(-5.67297564937715, -0.0383417554811535, -1.40270525363608)}, ['Y', 'O', 'M'])
+('O', {'color': (0.55857157707214355, 0.60161340236663818, 0.14941194653511047), 'pos': vector(-4.99354245772244, 2.18344861186906, 2.4576840046352)}, ['E', 'N', 'P'])
+('P', {'color': (0.59492629766464233, 0.56297677755355835, 0.93960219621658325), 'pos': vector(-2.98318554674568, 6.21535791713535, 2.3983536213358)}, ['Q', 'O', '0'])
+('Q', {'color': (0.19157721102237701, 0.43291020393371582, 0.65718340873718262), 'pos': vector(0.412643283216813, 6.02165866870379, 5.26141611639147)}, ['R', 'F', 'P'])
+('R', {'color': (0.6686098575592041, 0.92766064405441284, 0.61679589748382568), 'pos': vector(4.17432224992282, 7.1807351857659, 3.19412622981615)}, ['S', 'G', 'Q'])
+('S', {'color': (0.27504226565361023, 0.75970423221588135, 0.38187870383262634), 'pos': vector(3.05153691457337, 8.46900538117418, -0.974931338506674)}, ['T', 'R', '0'])
+('T', {'color': (0.5984993577003479, 0.9949953556060791, 0.17446216940879822), 'pos': vector(5.11134186311761, 6.61091992175755, -4.52540443568764)}, ['U', 'S', '1'])
+('U', {'color': (0.85376894474029541, 0.74365717172622681, 0.49372762441635132), 'pos': vector(8.04530086301018, 3.24471247418457, -3.92412601458493)}, ['H', 'V', 'T'])
+('V', {'color': (0.27126821875572205, 0.43648210167884827, 0.66737180948257446), 'pos': vector(6.49763961801841, -0.34935296089916, -6.10870016112765)}, ['J', 'W', 'U'])
+('W', {'color': (0.18520122766494751, 0.63354730606079102, 0.19149826467037201), 'pos': vector(2.60097010909863, 0.781932490130645, -8.06760178221723)}, ['X', 'V', '1'])
+('X', {'color': (0.38405629992485046, 0.52697080373764038, 0.34567436575889587), 'pos': vector(-1.19154526401195, -1.3873397865221, -6.96623358777736)}, ['Y', 'L', 'W'])
+('Y', {'color': (0.090109735727310181, 0.10747531801462173, 0.23254844546318054), 'pos': vector(-4.05780085442844, 1.61218974361501, -5.27158561527887)}, ['Z', 'N', 'X'])
+('Z', {'color': (0.92275089025497437, 0.89229029417037964, 0.38553115725517273), 'pos': vector(-2.04710515738152, 5.64421290382642, -5.32148136484402)}, ['0', 'Y', '1'])
+('0', {'color': (0.84955865144729614, 0.0093942992389202118, 0.85034275054931641), 'pos': vector(-1.36299269220176, 7.87259717160166, -1.46561871569041)}, ['S', 'P', 'Z'])
+('1', {'color': (0.55446606874465942, 0.94825553894042969, 0.060505416244268417), 'pos': vector(1.92832786660185, 5.09753011678054, -7.23586518687469)}, ['Z', 'T', 'W'])

File rtgraph3d/rtg_cli.py

View file
  • Ignore whitespace
+#! /usr/bin/env python
+
+import sys,os,dbus
+import cmd
+
+import warnings
+warnings.filterwarnings("ignore","tempnam",RuntimeWarning, __name__)
+
+
+class Interp(cmd.Cmd):
+    prompt = "RTG> "
+    def __init__(self):
+        cmd.Cmd.__init__(self)
+        self.last_selection = []
+        try:
+            self.bus = dbus.SessionBus()
+            self.control = self.bus.get_object("org.secdev.rtgraph3d", "/control")
+            self.rtg = dbus.Interface(self.control, "org.secdev.rtgraph3d.command")
+        except dbus.DBusException,e:
+            print >>sys.stderr,"DBUS ERROR: %s" % e
+            raise SystemExit
+
+    def completedefault(self, text, line, begidx, endidx):
+        l = self.rtg.get_all_nodes()
+        return [n for n in l if n.startswith(text)]
+
+    def do_quit(self, args):
+        return True
+
+    def do_edge(self, args):
+        e=args.split()
+        for n1,n2 in zip(e[:-1],e[1:]):
+            self.rtg.new_edge(n1,{},n2,{})
+
+    def do_glow(self, args):
+        for n in args.split():
+            self.rtg.glow(n)
+    def do_unglow(self, args):
+        nodes = args.split()
+        if nodes:
+            for n in nodes:
+                self.rtg.unglow(n)
+        else:
+            self.rtg.unglow_all()
+
+    def do_find(self, args):
+        a,v = [x.strip() for x in args.split("=")]
+        self.last_selection = r = self.rtg.find(a,v)
+        print "Found %i nodes" % len(r)
+        for n in r:
+            self.rtg.glow(n)
+
+    def do_toggle(self, args):
+        nodes = args.split()
+        if not nodes:
+            nodes = self.last_selection
+        for n in nodes:
+            self.rtg.toggle(n)
+
+    def do_dotty(self, args):
+        dot = self.rtg.get_dot()
+        fname = os.tempnam()
+        open(fname,"w").write(dot)
+        os.spawnlp(os.P_NOWAIT, "dotty", "dotty", fname)
+
+    def do_set_attraction(self, args):
+        self.rtg.set_attraction(float(args))
+    def do_set_repulsion(self, args):
+        self.rtg.set_repulsion(float(args))
+    def do_set_ambient(self, args):
+        self.rtg.set_ambient(float(args))
+        
+    def do_remote_dump(self, args):
+        self.rtg.file_dump(args)
+    def do_remote_load(self, args):
+        self.rtg.file_load(args)
+
+    def do_reset(self, args):
+        self.rtg.reset_world()
+
+    def do_rotate(self, args):
+        if args:
+            r = float(args)
+        else:
+            r = 0.0
+        self.rtg.auto_rotate_scene(r)
+        
+    def do_rotate_stop(self, args):
+        self.rtg.stop_auto_rotate_scene()
+
+    def do_update(self, args):
+        node,val = args.strip().split(" ",1)
+        k,v = val.strip().split("=")
+        k = k.strip()
+        v = v.strip()
+        if k in ["color", "radius", "pos"]:
+            v = eval(v)
+        self.rtg.update_node(node,{k:v})
+        
+
+
+if __name__ == "__main__":
+    try:
+        import readline,atexit
+    except ImportError:
+        pass
+    else:
+        histfile = os.path.join(os.environ["HOME"], ".rtg_cli_history")
+        atexit.register(readline.write_history_file, histfile)
+        try:
+            readline.read_history_file(histfile)
+        except IOError:
+            pass
+
+    
+    interp = Interp()
+    while 1:
+        try:
+            interp.cmdloop()
+        except KeyboardInterrupt:
+            print
+        except Exception,e:
+            l = str(e).strip()
+            if l:
+                print >>sys.stderr,"ERROR: %s" % l.splitlines()[-1]
+            continue
+        break

File rtgraph3d/rtgraph3d.py

View file
  • Ignore whitespace
+#! /usr/bin/env python
+
+
+try:
+    from visual import *
+except:
+    print "Module python-visual manquant."
+    exit(0)
+from select import select
+import os,sys,time,traceback,string,random
+import logging,getopt,socket
+import dbus,dbus.glib,dbus.mainloop.glib,dbus.service,gobject
+import thread
+import povexport
+import struct,re
+
+
+
+log = logging.getLogger("rtgraph3d")
+console_handler = logging.StreamHandler()
+console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s"))
+log.addHandler(console_handler)
+log.setLevel(20)
+
+
+DT = 0.1 # time interval
+ACCEL = 5
+
+
+class python_physics_engine:
+    C_ENGINE = 0
+    FRICTION = -0.5
+    MIN_DIST = 16
+    
+    @staticmethod
+    def add_edge(e1,e2):
+        pass
+    @staticmethod
+    def update(the_world, pos, spd, changed, dt, ATTRACT, REPULS):
+        ln = len(pos)
+        for o in the_world.lst:
+            o.F = python_physics_engine.FRICTION*o.V
+        i = 0
+        while i < the_world.world_len:
+            o = the_world.lst[i]
+            i += 1
+            j = i
+            while j < the_world.world_len:
+                n = the_world.lst[j]
+                j += 1
+                d = n.pos-o.pos
+                if n in o.edges:
+                    F = d*ATTRACT
+                    o.F += F
+                    n.F -= F
+                    
+                l = d.mag2
+                l = l**2
+                if l < python_physics_engine.MIN_DIST:
+                    l = python_physics_engine.MIN_DIST
+                F = -REPULS*d/l
+                o.F += F
+                n.F -= F
+        for o in the_world.lst:
+            dV = o.F*dt
+            o.V += dV
+            o.pos += (dV/2+o.V)*dt
+        
+
+def get_physics_engine(mode=0): # 0:auto, 1:force python, 2: force C only, 3: force SSE
+    if mode != 1:
+        try:
+            import PyInline
+        except ImportError:
+            log.warning("PyInline module not found! Fallback to Python physics engine")
+            mode = 1
+        
+    if mode == 0:    
+        try:
+            mode = 2
+                           
+            test_sse = PyInline.build(language="C", code=r"""
+            int test_sse(void)
+            {
+                    int sse_support;
+                    asm("push %%ebx \n\t"  /* do not clobber PIC register */
+                        "mov $1, %%eax \n\t"
+                        "cpuid \n\t"
+                        "xor %%eax,%%eax \n\t"
+                        "test $0x02000000, %%edx \n\t" /* Test SSE presence */
+                        "jz end \n\t"
+                        "inc %%eax \n\t"
+                        "test $0x04000000, %%edx \n\t" /* Test SSE2 presence */
+                        "jz end \n\t"
+                        "inc %%eax \n\t"
+                        "end: \n\t"
+                        "pop %%ebx \n\t"
+                        : "=a"(sse_support) );
+                    return sse_support;
+            }""")
+            sse_support = test_sse.test_sse()
+            if  sse_support > 0:
+                mode = 3
+                log.info("Detected SSE%s compatible CPU" % ["?", "", "2"][sse_support])
+            else:
+                log.info("Did not detect any SSE compatible CPU")
+                mode = 2
+        except:
+            log.warning("x86 SSE test failed. Fallback to C physics engine")
+            mode = 2
+
+    log.info("Using %s physics engine" % ["??","Python","C","C+SSE"][mode])
+    if mode == 1:
+        log.warning("Python physics engine is 25 to 1000 times slower")
+
+    if mode >= 2:
+        sse_code = r"""
+#define MAXPTS 2000
+#define MIN_DIST 16
+#define MAX_DIST 10
+#define FRICTION -0.5
+#define ACCEL 1
+#define CN 4
+
+#ifndef USE_SSE  /********[ C ONLY ]********/
+
+float force[CN*MAXPTS];
+
+PyFloatObject *pf_coord[CN*MAXPTS];
+PyFloatObject *pf_speed[CN*MAXPTS];
+PyObject *pt_coord[MAXPTS];
+PyObject *pt_speed[MAXPTS];
+
+#define PTC(i) pt_coord[i]
+#define PTS(i) pt_speed[i]
+
+#define X(i) (PFX(i)->ob_fval)
+#define Y(i) (PFY(i)->ob_fval)
+#define Z(i) (PFZ(i)->ob_fval)
+#define C(i) (PF(i)->ob_fval)
+#define PFX(i) pf_coord[CN*i]
+#define PFY(i) pf_coord[CN*i+1]
+#define PFZ(i) pf_coord[CN*i+2]
+#define PF(i) pf_coord[i]
+     
+#define SX(i) (PFSX(i)->ob_fval)
+#define SY(i) (PFSY(i)->ob_fval)
+#define SZ(i) (PFSZ(i)->ob_fval)
+#define S(i) (PFS(i)->ob_fval)
+#define PFSX(i) pf_speed[CN*i]
+#define PFSY(i) pf_speed[CN*i+1]
+#define PFSZ(i) pf_speed[CN*i+2]
+#define PFS(i) pf_speed[i]
+
+#define FX(i) force[CN*i]
+#define FY(i) force[CN*i+1]
+#define FZ(i) force[CN*i+2]
+#define F(i) force[i]
+
+#else         /********[ C + SSE ]********/
+
+
+#define NEEDED_PTS (MAXPTS+4)
+
+float coordx[NEEDED_PTS];
+float coordy[NEEDED_PTS];
+float coordz[NEEDED_PTS];
+float speedx[NEEDED_PTS];
+float speedy[NEEDED_PTS];
+float speedz[NEEDED_PTS];
+float forcex[NEEDED_PTS];
+float forcey[NEEDED_PTS];
+float forcez[NEEDED_PTS];
+
+PyFloatObject *pf_coordx[MAXPTS];
+PyFloatObject *pf_coordy[MAXPTS];
+PyFloatObject *pf_coordz[MAXPTS];
+PyFloatObject *pf_speedx[MAXPTS];
+PyFloatObject *pf_speedy[MAXPTS];
+PyFloatObject *pf_speedz[MAXPTS];
+
+PyObject *pt_coord[MAXPTS];
+PyObject *pt_speed[MAXPTS];
+
+#define PTC(i) pt_coord[i]
+#define PTS(i) pt_speed[i]
+
+#define X(i) (coordx[i])
+#define Y(i) (coordy[i])
+#define Z(i) (coordz[i])
+
+#define PX(i) (PFX(i)->ob_fval)
+#define PY(i) (PFY(i)->ob_fval)
+#define PZ(i) (PFZ(i)->ob_fval)
+#define PFX(i) pf_coordx[i]
+#define PFY(i) pf_coordy[i]
+#define PFZ(i) pf_coordz[i]
+     
+#define SX(i) (speedx[i])
+#define SY(i) (speedy[i])
+#define SZ(i) (speedz[i])
+
+#define PSX(i) (PFSX(i)->ob_fval)
+#define PSY(i) (PFSY(i)->ob_fval)
+#define PSZ(i) (PFSZ(i)->ob_fval)
+#define PFSX(i) pf_speedx[i]
+#define PFSY(i) pf_speedy[i]
+#define PFSZ(i) pf_speedz[i]
+
+#define FX(i) forcex[i]
+#define FY(i) forcey[i]
+#define FZ(i) forcez[i]
+
+#define CONDADD(idx, len, arr) do{ switch (len-idx) { default: (arr)[2] += (arr)[3]; case 3: (arr)[1] += (arr)[2]; case 2: (arr)[0] += (arr)[1]; case 1:; } } while(0);
+
+int mmx_control_flags = 0x5f80; // 0x5fc0; // set FTZ and DAZ
+
+float tmpshow[4] __attribute__ ((aligned(32)));
+#define SHOW(r,fmt,args ...) do { __asm__("lea tmpshow,%%edx \n\t movaps " r ",(%%edx) \n\t":::"edx"); \
+          printf("[%+.3f %+.3f %+.3f %+.3f] " fmt "\n" , tmpshow[0],tmpshow[1],tmpshow[2],tmpshow[3], ## args );} while(0)
+
+#endif /**********************************/
+
+#define LOG(x ...)
+//#define LOG(x ...) printf(x)
+                                             
+int old_len;
+
+
+#define EDGEW1 16
+#define EDGELW1 4
+#define EDGEW2 16
+#define EDGELW2 4
+#define EDGEW3 (8*sizeof(int))
+#define EDGELW3 5
+
+struct edge_part2 {
+    int val[EDGEW2];
+};
+
+struct edge_part1 {
+    struct edge_part2 *next[EDGEW1];
+};
+
+
+struct edge_part1 *edges[MAXPTS];
+
+// we always have i <= j
+int check_edge(int i, int j)
+{
+        struct edge_part1 *p1;
+        struct edge_part2 *p2;
+        int n1,n2,n3;
+
+        p1 = edges[i];
+        if (!p1) return 0;
+
+        n1 = (j >> (2*EDGELW1)) & (EDGEW1-1);
+        p2 = p1->next[n1];
+        if (!p2) return 0;
+        
+        n2 = (j >> EDGELW2) & (EDGEW2-1);
+        n3 = j & (EDGEW3-1);
+
+        return (p2->val[n2] & (1<<n3)) != 0;
+}
+
+void do_add_edge(int i, int j)
+{
+        struct edge_part1 *p1;
+        struct edge_part2 *p2;
+        int n1,n2,n3;
+
+        n1 = (j >> (2*EDGELW1)) & (EDGEW1-1);
+        n2 = (j >> EDGELW2) & (EDGEW2-1);
+        n3 = j & (EDGEW3-1);
+        
+        p1 = edges[i];
+        if (!p1) {
+                p1 = edges[i] = malloc(sizeof(struct edge_part1));
+                bzero(p1, sizeof(struct edge_part1));
+        }
+        p2 = p1->next[n1];
+        if (!p2) {
+                p2 = p1->next[n1] = malloc(sizeof(struct edge_part2));
+                bzero(p2, sizeof(struct edge_part2));
+        }
+        p2->val[n2] |= 1<<n3;
+}
+
+
+void add_edge(int i, int j)
+{
+      if (i < j) { do_add_edge(i,j); } // check is always called with i < j
+      else { do_add_edge(j,i); }
+}
+
+
+#ifdef USE_SSE   /********[ C + SSE ]********/
+// SSE prepa
+
+float attract[4] __attribute__ ((aligned(32)));
+float repuls[4] __attribute__ ((aligned(32)));
+float min_dist[4] __attribute__ ((aligned(32))) = { MIN_DIST, MIN_DIST, MIN_DIST, MIN_DIST };
+float friction[4] __attribute__ ((aligned(32))) = { FRICTION, FRICTION, FRICTION };
+float zero[4] __attribute__ ((aligned(32))) = { 0.0, 0.0, 0.0, 0.0 };
+float half[4] __attribute__ ((aligned(32))) = { 0.5, 0.5, 0.5, 0.5 };
+float tmpsse1[4] __attribute__ ((aligned(32)));
+float tmpsse2[4] __attribute__ ((aligned(32)));
+float tmpsse3[4] __attribute__ ((aligned(32)));
+
+#endif           /***************************/
+
+
+float update(PyObject *the_world, PyObject *pos, PyObject *spd, int changed, float dt, float ATTRACT, float REPULS)
+{
+	PyObject *item;
+	int i,j,len;
+        float dA;
+#ifndef USE_SSE
+        float a,D,DD,dX,dY,dZ;
+#endif
+
+
+	len = PyList_GET_SIZE(pos);
+	if (len > MAXPTS) len = MAXPTS;
+#ifdef USE_SSE
+        repuls[0] = repuls[1] = repuls[2] = repuls[3] = REPULS;
+
+        LOG("=== changed=%i old_len=%04i len=%04i attract=%+.f repuls=%+.2f\n",
+               changed, old_len, len, ATTRACT, REPULS);
+#endif
+
+        if (changed  || (old_len != len)) {
+                for (i=old_len; i<len; i++) {
+                        PFX(i)  = (PyFloatObject *)PyFloat_FromDouble(0.0);
+                        PFY(i)  = (PyFloatObject *)PyFloat_FromDouble(0.0);
+                        PFZ(i)  = (PyFloatObject *)PyFloat_FromDouble(0.0);
+                        PTC(i) = item = PyTuple_New(3);
+                        PyTuple_SET_ITEM(item, 0, (PyObject *)PFX(i));
+                        PyTuple_SET_ITEM(item, 1, (PyObject *)PFY(i));
+                        PyTuple_SET_ITEM(item, 2, (PyObject *)PFZ(i));
+                        
+                        PFSX(i) = (PyFloatObject *)PyFloat_FromDouble(0.0);
+                        PFSY(i) = (PyFloatObject *)PyFloat_FromDouble(0.0);
+                        PFSZ(i) = (PyFloatObject *)PyFloat_FromDouble(0.0);
+                        PTS(i) = item = PyTuple_New(3);
+                        PyTuple_SET_ITEM(item, 0, (PyObject *)PFSX(i));
+                        PyTuple_SET_ITEM(item, 1, (PyObject *)PFSY(i));
+                        PyTuple_SET_ITEM(item, 2, (PyObject *)PFSZ(i));
+                }
+                old_len = len;
+	    	for (i=0; i<len; i++) {
+                        item = PyList_GET_ITEM(pos, i);
+                        if (PTC(i) != item) {
+                                X(i) = ((PyFloatObject *)PyTuple_GET_ITEM(item, 0))->ob_fval;
+                                Y(i) = ((PyFloatObject *)PyTuple_GET_ITEM(item, 1))->ob_fval;
+                                Z(i) = ((PyFloatObject *)PyTuple_GET_ITEM(item, 2))->ob_fval;
+                                Py_INCREF(PTC(i));
+                                PyList_SET_ITEM(pos, i, PTC(i));
+                        }
+                        
+                        item = PyList_GET_ITEM(spd, i);
+                        if (PTS(i) != item) {
+                                SX(i) = ((PyFloatObject *)PyTuple_GET_ITEM(item, 0))->ob_fval;
+                                SY(i) = ((PyFloatObject *)PyTuple_GET_ITEM(item, 1))->ob_fval;
+                                SZ(i) = ((PyFloatObject *)PyTuple_GET_ITEM(item, 2))->ob_fval;
+                                Py_INCREF(PTS(i));
+                                PyList_SET_ITEM(spd, i, PTS(i));
+                        }
+
+	    	}
+        }
+        
+
+#ifndef USE_SSE    /********[ C ONLY ]********/
+        bzero(force, sizeof(float)*CN*len);
+#else             /********[ C + SSE ]********/
+        asm("ldmxcsr %0 \n\t" :: "m"(mmx_control_flags)); // set DAZ and MTZ into MMX control reg
+
+        asm("movaps %0, %%xmm0 \n\t" ::"m"(friction[0]));
+	for (i=0; i<len; i+=4) {
+                asm("movups %0, %%xmm1"::"m"(SX(i)));
+                asm("movups %0, %%xmm2"::"m"(SY(i)));
+                asm("movups %0, %%xmm3"::"m"(SZ(i)));
+                asm("mulps %%xmm0, %%xmm1 \n\t"
+                    "mulps %%xmm0, %%xmm2 \n\t"
+                    "mulps %%xmm0, %%xmm3 \n\t":);
+                asm("movups %%xmm1,%0"::"m"(FX(i)));
+                asm("movups %%xmm2,%0"::"m"(FY(i)));
+                asm("movups %%xmm3,%0"::"m"(FZ(i)));
+        }
+#endif            /*****************************/
+                
+
+#ifndef USE_SSE   /********[ C ONLY ]********/
+        for (i=0; i<len; i++) {
+                FX(i) += FRICTION*SX(i);
+                FY(i) += FRICTION*SY(i);
+                FZ(i) += FRICTION*SZ(i);
+                for (j=i+1; j<len; j++) {
+                        dX = X(j)-X(i);
+                        dY = Y(j)-Y(i);
+                        dZ = Z(j)-Z(i);
+                        if (check_edge(i,j)) {
+                                a = ATTRACT*dX;
+                                FX(i) += a; FX(j) -= a;
+                                a = ATTRACT*dY;
+                                FY(i) += a; FY(j) -= a;
+                                a = ATTRACT*dZ;
+                                FZ(i) += a; FZ(j) -= a;
+                        }
+                        
+                        D = dX*dX+dY*dY+dZ*dZ;
+                        DD = D*D;
+                        if (DD < MIN_DIST) DD = MIN_DIST;
+                        
+
+                        a = REPULS*dX/DD;
+                        FX(i) -= a; FX(j) += a;
+                        a = REPULS*dY/DD;
+                        FY(i) -= a; FY(j) += a;
+                        a = REPULS*dZ/DD;
+                        FZ(i) -= a; FZ(j) += a;
+
+                }
+        }
+#else             /********[ C + SSE ]********/
+	for (i=0; i<len; i++) {
+
+                asm("movss %0,%%xmm0\n\t"
+                    "movss %1,%%xmm1\n\t"
+                    "movss %2,%%xmm2\n\t"
+                    "shufps $0, %%xmm0, %%xmm0 \n\t"
+                    "shufps $0, %%xmm1, %%xmm1 \n\t"
+                    "shufps $0, %%xmm2, %%xmm2 \n\t"
+                    ::"m"(X(i)),"m"(Y(i)),"m"(Z(i)));
+
+		for (j=i+1; j<len; j+=4) {
+
+                        asm("movups %0, %%xmm3 \n\t"
+                            "movups %1, %%xmm4 \n\t"
+                            "movups %2, %%xmm5 \n\t"
+                            "subps %%xmm0, %%xmm3 \n\t" // xmm3=dX
+                            "subps %%xmm1, %%xmm4 \n\t" // xmm4=dY
+                            "subps %%xmm2, %%xmm5 \n\t" // xmm5=dZ
+                            ::"m"(X(j)),"m"(Y(j)),"m"(Z(j)));
+
+                        attract[0] = ATTRACT*check_edge(i,j);
+                        attract[1] = ATTRACT*check_edge(i,j+1);
+                        attract[2] = ATTRACT*check_edge(i,j+2);
+                        attract[3] = ATTRACT*check_edge(i,j+3);
+
+                        LOG("attract %2i %2i: %5i %5i %5i %5i\n", i,j,attract[0],attract[1],attract[2],attract[3]);
+
+			if (attract[0] || attract[1] || attract[2] || attract[3]) {
+                                asm("movaps %0, %%xmm6 \n\t"
+                                    "mulps %%xmm3, %%xmm6 \n\t"
+                                    "movups %2, %%xmm7 \n\t"
+                                    "movaps %%xmm6, %1 \n\t"
+                                    "subps %%xmm6, %%xmm7 \n\t"
+                                    "movups %%xmm7, %2 \n\t"::"m"(attract[0]), "m"(tmpsse1[0]), "m"(FX(j)));
+                                LOG("attract X: %+.3f %+.3f %+.3f %+.3f\n",
+                                       tmpsse1[0], tmpsse1[1], tmpsse1[2], tmpsse1[3]);
+                                       
+                                asm("movaps %0, %%xmm6 \n\t"
+                                    "mulps %%xmm4, %%xmm6 \n\t"
+                                    "movups %2, %%xmm7 \n\t"
+                                    "movaps %%xmm6, %1 \n\t"
+                                    "subps %%xmm6, %%xmm7 \n\t"
+                                    "movups %%xmm7, %2 \n\t"::"m"(attract[0]), "m"(tmpsse2[0]), "m"(FY(j)));
+                                LOG("attract Y: %+.3f %+.3f %+.3f %+.3f\n",
+                                       tmpsse2[0], tmpsse2[1], tmpsse2[2], tmpsse2[3]);    
+
+                                asm("movaps %0, %%xmm6 \n\t"
+                                    "mulps %%xmm5, %%xmm6 \n\t"
+                                    "movups %2, %%xmm7 \n\t"
+                                    "movaps %%xmm6, %1 \n\t"
+                                    "subps %%xmm6, %%xmm7 \n\t"
+                                    "movups %%xmm7, %2 \n\t"::"m"(attract[0]), "m"(tmpsse3[0]), "m"(FZ(j)));
+                                LOG("attract Z: %+.3f %+.3f %+.3f %+.3f\n",
+                                       tmpsse3[0], tmpsse3[1], tmpsse3[2], tmpsse3[3]);
+
+
+                                if (attract[0]) { FX(i) += tmpsse1[0]; FY(i) += tmpsse2[0]; FZ(i) += tmpsse3[0];}
+                                if (attract[1]) { FX(i) += tmpsse1[1]; FY(i) += tmpsse2[1]; FZ(i) += tmpsse3[1];}
+                                if (attract[2]) { FX(i) += tmpsse1[2]; FY(i) += tmpsse2[2]; FZ(i) += tmpsse3[2];}
+                                if (attract[3]) { FX(i) += tmpsse1[3]; FY(i) += tmpsse2[3]; FZ(i) += tmpsse3[3];}
+
+			}
+
+
+                        asm("movaps %%xmm3, %%xmm7 \n\t"
+                            "movaps %%xmm4, %%xmm6 \n\t"
+                            "mulps %%xmm3, %%xmm7 \n\t"
+                            "mulps %%xmm4, %%xmm6 \n\t"
+                            "addps %%xmm6, %%xmm7 \n\t"
+                            "movaps %%xmm5, %%xmm6 \n\t"
+                            "mulps %%xmm5, %%xmm6 \n\t"
+                            "addps %%xmm6, %%xmm7 \n\t" // xmm7 = D = dX*dX+dY*dY+dZ*dZ
+                            "mulps %%xmm7, %%xmm7 \n\t"
+                            "maxps %0, %%xmm7 \n\t"     // xmm7 = max(MIN_DIST, D^2)
+                            ::"m"(min_dist[0])); 
+
+                        asm("movaps %0, %%xmm6 \n\t"  // xmm6 = repuls
+                            "divps %%xmm7, %%xmm3 \n\t"
+                            "divps %%xmm7, %%xmm4 \n\t"
+                            "divps %%xmm7, %%xmm5 \n\t"
+                            "mulps %%xmm6, %%xmm3 \n\t"
+                            "mulps %%xmm6, %%xmm4 \n\t"
+                            "mulps %%xmm6, %%xmm5 \n\t" // xmm3,4,5 = dfx,dfy,dfz
+                            :: "m"(repuls[0]));
+
+                        asm("movaps %%xmm3, %0\n\t"
+                            "movaps %%xmm4, %1\n\t"
+                            "movaps %%xmm5, %2\n\t"
+                            ::"m"(tmpsse1[0]),"m"(tmpsse2[0]),"m"(tmpsse3[0]));
+                            
+                        asm("movups %0, %%xmm6 \n\t"
+                            "movups %1, %%xmm7 \n\t"
+                            "addps %%xmm3, %%xmm6 \n\t"
+                            "addps %%xmm4, %%xmm7 \n\t"
+                            "movups %2, %%xmm3 \n\t"
+                            "movups %%xmm6, %0 \n\t"
+                            "addps %%xmm5, %%xmm3 \n\t"
+                            "movups %%xmm7, %1 \n\t"
+                            "movups %%xmm3, %2 \n\t"
+                            ::"m"(FX(j)), "m"(FY(j)), "m"(FZ(j)));
+                            
+                        CONDADD(j,len,tmpsse1);
+                        FX(i) -= tmpsse1[0];
+                        CONDADD(j,len,tmpsse2);
+                        FY(i) -= tmpsse2[0];
+                        CONDADD(j,len,tmpsse3);
+                        FZ(i) -= tmpsse3[0];
+		}
+	}
+#endif            /***************************/
+        dt *= ACCEL;
+
+
+#ifndef USE_SSE   /********[ C ONLY ]********/
+        dA = 0;
+	for (i=0; i<CN*len; i++) {
+                if (!F(i)) continue;
+		a = F(i)*dt; 
+		S(i) += a;
+		a = (S(i)+0.5*a)*dt;
+		C(i) += a;
+		dA += fabs(a);
+        }
+#else             /********[ C + SSE ]********/
+        asm("movaps %0, %%xmm7 \n\t"    // xmm7 = dA = 0
+            "movaps %1, %%xmm6 \n\t"    // xmm6 = 0.5
+            "movss %2,%%xmm0 \n\t"
+            "shufps $0, %%xmm0, %%xmm0 \n\t" // xmm1=(dt,dt,dt,dt)
+                    ::"m"(zero[0]),"m"(half[0]), "m"(dt));
+        
+	for (i=0; i<len; i+=4) {
+
+                asm("movups %0,%%xmm1 \n\t" // xmm1=FX
+                    "movups %1,%%xmm2 \n\t" // xmm2=SX
+                    "movups %2,%%xmm3 \n\t" // xmm3=X
+                    "mulps %%xmm0, %%xmm1 \n\t" // xmm1=F*dt
+                    "addps %%xmm1, %%xmm2 \n\t" // xmm2=S+dS=S+Fdt
+                    "mulps %%xmm6, %%xmm1 \n\t"
+                    "addps %%xmm2, %%xmm1 \n\t"
+                    "mulps %%xmm0, %%xmm1 \n\t" // xmm1 = (S+0.5*F*dt)*dt = dX
+                    "addps %%xmm1, %%xmm3 \n\t"
+                    "movups %%xmm3, %2 \n\t"
+                    "mulps %%xmm3,%%xmm3 \n\t"
+                    "movups %%xmm2, %1 \n\t"
+                    "addps %%xmm3, %%xmm7 \n\t" //xmm7 = dA += dX^2
+                    ::"m"(FX(i)),"m"(SX(i)),"m"(X(i)));
+
+                asm("movups %0,%%xmm1 \n\t" // xmm1=FY
+                    "movups %1,%%xmm2 \n\t" // xmm2=SY
+                    "movups %2,%%xmm3 \n\t" // xmm3=Y
+                    "mulps %%xmm0, %%xmm1 \n\t" // xmm1=F*dt
+                    "addps %%xmm1, %%xmm2 \n\t" // xmm2=S+dS=S+Fdt
+                    "mulps %%xmm6, %%xmm1 \n\t"
+                    "addps %%xmm2, %%xmm1 \n\t"
+                    "mulps %%xmm0, %%xmm1 \n\t" // xmm1 = (S+0.5*F*dt)*dt = dY
+                    "addps %%xmm1, %%xmm3 \n\t"
+                    "movups %%xmm3, %2 \n\t"
+                    "mulps %%xmm3,%%xmm3 \n\t"
+                    "movups %%xmm2, %1 \n\t"
+                    "addps %%xmm3, %%xmm7 \n\t" //xmm7 = dA += dX^2
+                    ::"m"(FY(i)),"m"(SY(i)),"m"(Y(i)));
+
+                asm("movups %0,%%xmm1 \n\t" // xmm1=FZ
+                    "movups %1,%%xmm2 \n\t" // xmm2=SZ
+                    "movups %2,%%xmm3 \n\t" // xmm3=Z
+                    "mulps %%xmm0, %%xmm1 \n\t" // xmm1=F*dt
+                    "addps %%xmm1, %%xmm2 \n\t" // xmm2=S+dS=S+Fdt
+                    "mulps %%xmm6, %%xmm1 \n\t"
+                    "addps %%xmm2, %%xmm1 \n\t"
+                    "mulps %%xmm0, %%xmm1 \n\t" // xmm1 = (S+0.5*F*dt)*dt = dZ
+                    "addps %%xmm1, %%xmm3 \n\t"
+                    "movups %%xmm3, %2 \n\t"
+                    "mulps %%xmm3,%%xmm3 \n\t"
+                    "movups %%xmm2, %1 \n\t"
+                    "addps %%xmm3, %%xmm7 \n\t" //xmm7 = dA += dX^2
+                    ::"m"(FZ(i)),"m"(SZ(i)),"m"(Z(i)));
+                    
+                }
+        asm("movaps %%xmm7, %0"::"m"(tmpsse1[0]));
+        dA = tmpsse1[0]+tmpsse1[1]+tmpsse1[2]+tmpsse1[3];
+
+        for (i=0; i<len; i++) {
+            PX(i) = X(i);
+            PY(i) = Y(i);
+            PZ(i) = Z(i);
+        }
+#endif            /***************************/
+        
+
+	return dA/(len+0.1);
+}
+		
+"""
+
+    
+        if mode == 3:
+            sse_code = "#define USE_SSE\r\n" + sse_code
+
+        physics_engine = PyInline.build(language="C", code=sse_code)
+        physics_engine.C_ENGINE=1
+    else:
+        physics_engine = python_physics_engine
+    return physics_engine
+
+
+class Edge(cylinder):
+    def __init__(self, o1, o2, *args, **kargs):
+        param={"radius":0.2, "color":(0.7,0.7,1)}
+        param.update(kargs)
+        self.o1=o1
+        self.o2=o2
+        cylinder.__init__(self, *args, **param)
+        self.update()
+        self.pickable = 0
+    def update(self):
+        self.pos = self.o1.pos
+        self.axis = self.o2.pos-self.o1.pos
+
+def randvect():
+    return vector(random.random(),random.random(),random.random())
+
+def randcol():
+    v = randvect()
+    s = v[0]+v[1]+v[2]
+    if s < 1:
+        v *= 1/(0.001+s)        
+    return v
+
+class Node(sphere):
+    def __init__(self, node_id, *args, **kargs):
+        self.param = {"radius":1, "pos": randvect(), "color": randcol() }
+        self.param.update(kargs)
+        self.id = node_id
+        self.edges = {}
+        self.pickable = 1
+        self.PV=vector()
+        self.V=vector()
+
+        sphere.__init__(self, *args, **self.param)
+
+        self.label=label(text=node_id, pos=self.pos, space=self.radius, xoffset=10, yoffset=20, visible=0)
+        self.update_label()
+
+
+    def update_label(self):
+        text = [self.id]
+        for k,v in self.param.iteritems():
+            if k in ["radius", "pos", "color"]:
+                setattr(self, k, v)
+            else:
+                text.append("%s = %s" % (k, v))
+        self.label.text = str("\n".join(text))
+
+    def update_param(self, **kargs):
+        self.param.update(kargs)
+        self.update_label()
+    def action(self):
+        self.label.pos=self.pos
+        self.label.visible ^= 1
+    def update(self, dt):
+        self.label.pos = self.pos
+    def get_state(self):
+        for k in self.param:
+            if hasattr(self, k):
+                self.param[k] = getattr(self,k)
+        return self.param
+    def dump(self):
+        return repr( (self.id, self.get_state(), map(lambda x:x.id,self.edges.keys())) )
+    @classmethod
+    def from_string(cls, s):
+        l = eval(s)
+        node_id,state,edges = l[:3]
+        o = cls(node_id, **state)
+        o._tmp_edges = edges
+        return o
+
+povexport.legal[Node] = povexport.legal[sphere]
+povexport.legal[Edge] = povexport.legal[cylinder]
+
+
+class World:
+    def __init__(self, physics_engine, friction=-0.5, attraction=1, repulsion=256):
+        self.physics_engine = physics_engine
+        self.friction = friction
+        self.attraction = attraction
+        self.repulsion = repulsion
+        self.reset_world()
+    def reset_world(self):
+        self.world={}
+        self.lst = []
+        self.world_len = 0
+        self.edges = []
+        self.coords = []
+        self.speeds = []
+        self.cinematic_change = 1        
+    def register(self, o):
+        self.world[o.id] = o
+        self.lst.append(o)
+        o.num = self.world_len
+        self.coords.append(o.pos.astuple())
+        self.speeds.append((0.0,0.0,0.0))
+        self.world_len += 1
+    def add_edge(self, o1, o2):
+        self.edges.append(Edge(o1,o2))
+        self.physics_engine.add_edge(o1.num, o2.num)
+    def __getitem__(self, item):
+        return self.world[item]
+    def __contains__(self,item):
+        return item in self.world
+    def get(self, *args):
+        return self.world.get(*args)
+    def dump_to_file(self, f):
+        for o in self.lst:
+            f.write(o.dump())
+            f.write("\n")
+        f.close()
+    def load_from_file(self, f):
+        while 1:
+            l = f.readline()
+            if not l:
+                break
+            o = Node.from_string(l)
+            self.register(o)
+        for o in self.lst:
+            if hasattr(o,"_tmp_edges"):
+                for e in o._tmp_edges:
+                    if e not in self.world:
+                        print >>sys.stderr, "%s: edge to [%s] not found" % (o.id,e)
+                        continue
+                    o2 = self.world[e]
+                    o.edges[o2] = None
+                    if o in o2.edges:
+                        self.add_edge(o,o2)
+                del(o._tmp_edges)
+    def update_edges(self):
+        for e in self.edges:
+            e.update()        
+    def update(self, dt):
+        self.physics_engine.update(self, self.coords, self.speeds, self.cinematic_change, dt, self.attraction, self.repulsion)
+        self.cinematic_change = 0
+        if self.physics_engine.C_ENGINE:
+            for i in xrange(self.world_len):
+                self.lst[i].pos = self.coords[i]
+                self.lst[i].update(dt)
+        else:
+            for i in xrange(self.world_len):
+                self.lst[i].update(dt)
+        self.update_edges()
+
+
+
+def mkcol():
+    def norm(x,y,z):
+        if x+y+z < 1:
+            t=1-max(x,y,z)
+            x,y,z = x+t,y+t,z+t
+        return x,y,z
+    return norm(random.random(), random.random(), random.random())
+
+def ip2num(ip):
+    a,b,c,d = struct.unpack("!lLlL",socket.inet_pton(socket.AF_INET6, ip))
+    return (a<<32L|b), (c<<32L|d)
+
+
+class GlowingService:
+    def __init__(self):
+        self.lst = {}
+        self.run=1
+        thread.start_new_thread(self.glowing_thread,())
+
+    def __del__(self):
+        self.run=0
+
+    def glow_node(self, node):
+        if node not in self.lst:
+            self.lst[node]=(node.radius, node.color)
+
+    def unglow_node(self, node):
+        if node in self.lst:
+            node.radius,node.color = self.lst.pop(node)
+
+    def toggle_glow(self, node):
+        if node in self.lst:
+            self.unglow_node(node)
+        else:
+            self.glow_node(node)
+
+    def glowing_thread(self):
+        t=0
+        while self.run:
+            rate(25)
+            mult = 1.1+0.3*cos(t*2*pi/25)
+            for n,v in self.lst.iteritems():
+                rad,col = v
+                n.radius = rad*mult
+                n.red = min(1,col[0]*mult)
+                n.green = min(1,col[1]*mult)
+                n.blue = min(1,col[2]*mult)
+            t += 1
+
+    def __iter__(self):
+        return iter(self.lst)
+
+class RotateService:
+    def __init__(self, scene, angle=pi/300):
+        self.lock = thread.allocate_lock()
+        self.lock.acquire()
+        self.scene=scene
+        self.angle=angle
+        thread.start_new_thread(self.rotate_thread,())
+
+
+    def rotate(self):
+        if self.lock.locked():
+            self.lock.release()
+    def stop_rotate(self):
+        self.lock.acquire(0)
+    def set_angle(self, angle):
+        self.angle = angle
+
+    def rotate_thread(self):
+        t=0.0
+        while 1:
+            rate(50)
+            if self.lock.locked():
+                self.lock.acquire()
+                self.lock.release()
+            self.scene.forward = (cos(t), 0, sin(t))
+            t += self.angle
+
+
+class RTGraphService(dbus.service.Object):
+    def __init__(self, bus, dbpath,
+                 physics_engine, input=[sys.stdin], startfile=None, savefile=None, stereo=None):
+        dbus.service.Object.__init__(self, bus, dbpath)
+        self.scene = display()
+        self.scene.title="RealTime Graph 3D"
+        self.scene.exit=0
+        self.scene.ambient=0.3
+        if stereo is not None:
+            self.scene.stereo = stereo
+            self.scene.stereodepth = 2
+    #        self.scene.width=100
+    #        self.scene.height=50
+        self.scene.visible=1
+        self.cinematic_lock = thread.allocate_lock()
+
+        self.glow=GlowingService()
+        self.rotate_service = RotateService(self.scene)
+
+        self.the_world = World(physics_engine)
+        self.the_world.scene = self.scene
+        if startfile is not None:
+            self.the_world.load_from_file(open(startfile))
+        if savefile is not None:
+            atexit.register(self.the_world.dump_to_file, open(savefile,"w"))
+
+
+    @dbus.service.signal("org.secdev.rtgraph3d.events", signature="s")
+    def node_click(self, message):
+        pass
+
+    @dbus.service.signal("org.secdev.rtgraph3d.events", signature="s")
+    def node_shift_click(self, message):
+        pass
+
+    @dbus.service.signal("org.secdev.rtgraph3d.events", signature="s")
+    def node_ctrl_click(self, message):
+        pass
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="s", out_signature="")
+    def file_dump(self, fname):
+        self.cinematic_lock.acquire()
+        self.the_world.dump_to_file(open(fname,"w"))
+        self.cinematic_lock.release()
+        log.info("Dumped world to [%s]" % fname)
+    
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="s", out_signature="")
+    def file_load(self, fname):
+        self.cinematic_lock.acquire()
+        self.the_world.load_from_file(open(fname))
+        self.cinematic_lock.release()
+        log.info("Loaded world from [%s]" % fname)
+    
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="", out_signature="s")
+    def get_dump(self):
+        return "not implemented..."
+
+    
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="", out_signature="s")
+    def get_dot(self):
+        s = 'graph "rtgraph" { \n'
+        
+        for e in self.the_world.edges:
+            s += '\t "%s" -- "%s";\n' % (e.o1.id, e.o2.id)
+        s += '}\n'
+        return s
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="", out_signature="")
+    def reset_world(self):
+        self.cinematic_lock.acquire()
+        self.the_world.reset_world()
+        for o in self.scene.objects:
+            o.visible=0
+        self.cinematic_lock.release()
+        log.info("Reseted world")
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="d", out_signature="")
+    def set_attraction(self, attract):
+        self.the_world.attraction = attract
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="d", out_signature="")
+    def set_repulsion(self, repuls):
+        self.the_world.repulsion = repuls
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="d", out_signature="")
+    def set_ambient(self, ambient):
+        self.scene.ambient = ambient
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="d", out_signature="")
+    def auto_rotate_scene(self, angle):
+        if angle:
+            self.rotate_service.set_angle(angle)
+        self.rotate_service.rotate()
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="", out_signature="")
+    def stop_auto_rotate_scene(self):
+        self.rotate_service.stop_rotate()
+        
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="s", out_signature="s")
+    def execute(self, cmd):
+        log.info("--- Begin exec [%s]" % cmd) 
+        res=eval(cmd)
+        log.info(res)
+        log.info("--- End exec [%s]" % cmd)
+        return "%s" % res
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="", out_signature="")
+    def check(self):
+        for o in self.the_world.lst:
+            for o2 in o.edges:
+                if o not in o2.edges:
+                    log.error("%s ==> %s \t %s ==> %s"% (o.id,o2.id, id(o),id(o2)))
+            log.info("Checked %i nodes, %i edges." % (len(self.the_world.lst),len(self.the_world.edges)))
+        
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="sa{sv}sa{sv}", out_signature="")
+    def new_edge(self, id1, attr1, id2, attr2):
+        id1=str(id1)
+        id2=str(id2)
+        attr1=dict([ (str(a),b.__class__.__base__(b)) for a,b in attr1.iteritems()])
+        attr2=dict([ (str(a),b.__class__.__base__(b)) for a,b in attr2.iteritems()])
+    
+        if id1 == id2:
+            raise Exception("Nodes are identical")
+    
+        n1 = self.the_world.get(id1)
+        n2 = self.the_world.get(id2)
+        if n1 is None and n2 is not None:
+            n2,n1=n1,n2
+            id1,id2=id2,id1
+            attr1,attr2=attr2,attr1
+    
+        if n1 is None:
+            n1 = Node(id1, **attr1)
+            self.the_world.register(n1)
+        if n2 is None:
+            if "pos" not in attr2:
+                attr2["pos"] = n1.pos+randvect()
+            n2 = Node(id2, **attr2)
+            self.the_world.register(n2)
+    
+        if n1 in n2.edges:
+            raise Exception("Edge %s-%s alread exists" % (id1,id2))
+    
+        n1.edges[n2] = None
+        n2.edges[n1] = None
+        self.the_world.add_edge(n1,n2)
+        self.the_world.cinematic_change = 1
+            
+        log.info("Ok for [%s]-[%s]" % (id1,id2))
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="sa{sv}", out_signature="")
+    def update_node(self, node_id, attr):
+        attr=dict([ (str(a),b.__class__.__base__(b)) for a,b in attr.iteritems()])
+        node = self.the_world.get(node_id)
+        node.update_param(**attr)
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="s", out_signature="")
+    def toggle(self, node_id):
+        self.the_world[str(node_id)].action()
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="s", out_signature="")
+    def glow(self, node_id):
+        self.glow.glow_node(self.the_world[str(node_id)])
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="s", out_signature="")
+    def unglow(self, node_id):
+        self.glow.unglow_node(self.the_world[str(node_id)])
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="", out_signature="")
+    def unglow_all(self):
+        for n in self.the_world.lst:
+            self.glow.unglow_node(n)
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="ss", out_signature="as")
+    def find(self, attr, val):
+        res = []
+        rval = re.compile(str(val))
+        attr = str(attr)
+        for n in self.the_world.lst:
+            if attr in n.param:
+                v = n.param[attr]
+                if type(v) is not str:
+                    v = repr(v)
+                if rval.search(v):
+                    res.append(n.id)
+        return res
+
+    @dbus.service.method("org.secdev.rtgraph3d.command",
+                         in_signature="", out_signature="as")
+    def get_all_nodes(self):
+        return [n.id for n in self.the_world.lst]
+        
+
+def cinematic_thread(svc, POVdump=None, ACCEL=ACCEL, DT=DT):
+    log.info("Cinematic thread started")
+    the_world = svc.the_world
+    scene = the_world.scene
+    picked = None
+    frames=-1
+    while 1:
+        frames += 1
+        rate(ACCEL/DT)
+        svc.cinematic_lock.acquire()
+        try:
+            if scene.kb.keys:
+                k = scene.kb.getkey()
+                if k == "Q":
+                    #send event
+                    return
+            if scene.mouse.events:
+                ev = scene.mouse.getevent()
+                if ev.release == "left":
+                    if picked:
+                        the_world.speeds[picked.num]=((scene.mouse.pos-picked.PV)/DT).astuple()
+                        the_world.cinematic_change = 1
+                        picked = None
+                    else:
+                        o = ev.pick
+                        if ev.shift and o:
+                            if hasattr(o,"id"):
+                                svc.node_shift_click(o.id)
+                        elif ev.ctrl and o:
+                            if hasattr(o,"id"):
+                                svc.node_ctrl_click(o.id)
+                        else:
+                            if hasattr(o, "action"):
+                                o.action()
+                if ev.drag == "left":
+                    if ev.pick and ev.pick.pickable:
+                        picked = ev.pick
+
+    
+            if picked:
+                picked.PV = picked.pos
+                picked.pos=scene.mouse.pos
+                picked.V = vector()
+