geosolver/workbench/prototypeObjects.py
2017-03-28 19:38:00 +02:00

1973 lines
86 KiB
Python

""" Creational Pattern: Prototype pattern"""
from copy import copy, deepcopy
from includes import *
from parameters import Settings
from quaternion import *
from singleton import *
import geosolver
from geosolver import GeometricDecomposition
import delaunay._qhull as qhull
import delaunay.core as dcore
from geosolver.matfunc import Vec
import numpy as Numeric
try:
from OpenGL.GL import *
from OpenGL.GLU import *
except ImportError:
app = QtGui.QApplication( sys.argv )
QtGui.QMessageBox.critical( None, "OpenGL grabber", "PyOpenGL must be installed to run this example.",
QtGui.QMessageBox.Ok | QtGui.QMessageBox.Default, QtGui.QMessageBox.NoButton )
sys.exit( 1 )
class PrototypeManager( Singleton ):
""" The prototype manager handles the objects needed for the different viewports. Also it handles the connection
with the geometric constraint solver, e.g. when a new object is added (deleted) it will also be added (deleted)
to (from) the constraint graph. Updates for visualisation or constraint solving is handled too."""
def __init__( self ):
""" The initilization of the class is done once, else the one and only instance is returned. """
Singleton.__init__( self )
if self._isNew:
self.prtObjects = []
self.clsObjects = []
self.importedObjs = []
self.copyOfObjects = []
self.transpPrtObjects = []
self.axis = Axis( [0.0, 0.0, 0.0], 1.0, 40.0 )
self.objectSelected = None
self.objectIsSelected = False
self.showAxis = False
self.objectNr = 1
self.geoProblem = geosolver.GeometricProblem( dimension=3 )
self.selectCounter = 0
self.panel = None
self.result = None
self.visualiseClusters = True
self.settings = Settings()
self.createTriggers()
self.nrOfImports = 0
def createTriggers(self):
QtCore.QObject.connect(self.settings.sketcherData,QtCore.SIGNAL("pointSizeChanged"), self.updateSize)
QtCore.QObject.connect(self.settings.sketcherData,QtCore.SIGNAL("fPointSizeChanged"), self.updateSize)
QtCore.QObject.connect(self.settings.sketcherData,QtCore.SIGNAL("lineSizeChanged"), self.updateSize)
QtCore.QObject.connect(self.settings.sketcherData,QtCore.SIGNAL("distanceSizeChanged"), self.updateSize)
QtCore.QObject.connect(self.settings.sketcherData,QtCore.SIGNAL("pointColorChanged"), self.updateColor)
QtCore.QObject.connect(self.settings.sketcherData,QtCore.SIGNAL("fPointColorChanged"), self.updateColor)
QtCore.QObject.connect(self.settings.sketcherData,QtCore.SIGNAL("lineColorChanged"), self.updateColor)
QtCore.QObject.connect(self.settings.sketcherData,QtCore.SIGNAL("angleColorChanged"), self.updateColor)
QtCore.QObject.connect(self.settings.sketcherData,QtCore.SIGNAL("selectionColorChanged"), self.updateColor)
QtCore.QObject.connect(self.settings.sketcherData,QtCore.SIGNAL("distanceColorChanged"), self.updateColor)
def updateSize(self):
for prtObject in self.prtObjects:
if prtObject.objType == ObjectType.POINT:
prtObject.radius = self.settings.sketcherData.pointRadius
elif prtObject.objType == ObjectType.FIXED_POINT:
prtObject.radius = self.settings.sketcherData.fPointRadius
elif prtObject.objType == ObjectType.DISTANCE_HELPER:
prtObject.radius = self.settings.sketcherData.lineRadius
elif prtObject.objType == ObjectType.DISTANCE_CONSTRAINT:
prtObject.radius = self.settings.sketcherData.distanceRadius
# Rick 20090519
#elif prtObject.objType == ObjectType.DISTANCE_CLUSTER:
# prtObject.radius = self.settings.sketcherData.distanceRadius * 1.5
# but which to choose for these?
#elif prtObject.objType == ObjectType.POINT_CLUSTER:
# prtObject.radius = self.settings.sketcherData.pointRadius * 1.5
# prtObject.radius = self.settings.sketcherData.fpointRadius * 1.5
def updateColor(self):
for prtObject in self.prtObjects:
if prtObject.objType == ObjectType.POINT:
prtObject.color = self.settings.sketcherData.pointColor
elif prtObject.objType == ObjectType.FIXED_POINT:
prtObject.color = self.settings.sketcherData.fPointColor
elif prtObject.objType == ObjectType.DISTANCE_HELPER:
prtObject.color = self.settings.sketcherData.lineColor
elif prtObject.objType == ObjectType.DISTANCE_CONSTRAINT:
prtObject.color = self.settings.sketcherData.distanceColor
elif prtObject.objType == ObjectType.ANGLE_CONSTRAINT:
prtObject.color = self.settings.sketcherData.angleColor
prtObject.selectColor = self.settings.sketcherData.selectColor
def addObject( self, prtobject ):
""" Try to add a new object to the constraint graph
Parameters:
prtobject - prototype object which must be added to the constraint graph
"""
if not prtobject.ghost:
if prtobject.objType == ObjectType.POINT:
self.geoProblem.add_point( prtobject.key, Vec( [prtobject.position[0], prtobject.position[1], prtobject.position[2]] ) )
elif prtobject.objType == ObjectType.FIXED_POINT:
self.geoProblem.add_point( prtobject.key, Vec( [prtobject.position[0], prtobject.position[1], prtobject.position[2]] ) )
self.geoProblem.add_constraint(geosolver.FixConstraint( prtobject.key, Vec ( [prtobject.position[0], prtobject.position[1], prtobject.position[2]] ) ) )
elif prtobject.objType == ObjectType.DISTANCE_CONSTRAINT:
prtobject.con = geosolver.DistanceConstraint( prtobject.pointBegin.key, prtobject.pointEnd.key, prtobject.distance )
self.geoProblem.add_constraint( prtobject.con )
elif prtobject.objType == ObjectType.ANGLE_CONSTRAINT:
prtobject.con = geosolver.AngleConstraint( prtobject.pointBegin.key, prtobject.pointMiddle.key, prtobject.pointEnd.key, prtobject.angle )
self.geoProblem.add_constraint( prtobject.con )
""" if the addition of the new object succeeds add it to the list in the panel """
self.panel.addItemToSelectionList( prtobject.name, prtobject.objType )
self.prtObjects += [prtobject]
self.objectNr += 1
def addClusterObject(self, clsObject):
if clsObject != None:
self.clsObjects += [clsObject]
def addTransparentObject( self, prtobject ):
self.transpPrtObjects += [prtobject]
self.objectNr += 1
def __handleResult(self):
""" Create the clusterobjects for the sketcher """
if self.result != None:
collPoints = []
clusters = []
#self.result.flag = GeometricDecomposition.S_OVER
if self.result.flag == GeometricDecomposition.I_UNDER or self.result.flag == GeometricDecomposition.S_UNDER:
clusters = self.result.subs
for cluster in clusters:
self.__createCluster(cluster)
elif self.result.flag == GeometricDecomposition.I_OVER or self.result.flag == GeometricDecomposition.S_OVER:
self.__getOverConstrainedClusters(self.result, clusters)
wellClusters = []
self.__getWellConstrainedClusters(self.result, wellClusters, 1)
for cluster in clusters:
self.__createCluster(cluster)
for wellCluster in wellClusters:
self.__createCluster(wellCluster)
elif self.result.flag == GeometricDecomposition.OK:
cluster = self.result
self.__createCluster(cluster)
def __createCluster(self, cluster):
collPoints = []
if len(cluster.variables) > 2:
ptObjects = filter(lambda x: x.key in cluster.variables, self.prtObjects)
prtCluster = ClusterI(cluster.flag)
prtCluster.clusterPoints = ptObjects
prtCluster.update()
self.clsObjects += [prtCluster]
elif len(cluster.variables) == 2:
collPoints = filter(lambda x: x.key in cluster.variables, self.prtObjects)
if len(collPoints) == 2:
prtCluster = DistanceCluster(collPoints[0], collPoints[1])
prtCluster.update()
self.clsObjects += [prtCluster]
elif len(cluster.variables) == 1:
collPoints = filter(lambda x: x.key in cluster.variables, self.prtObjects)
prtCluster = PointCluster(collPoints[0].position, collPoints[0].radius*1.5, collPoints[0])
self.clsObjects += [prtCluster]
def createCluster(self, variables, constrainedness = None):
""" Clusters are created from a list of variables """
prtCluster = None
if len(variables) == 1:
point = filter(lambda x: x.key in variables, self.prtObjects)
if point != []:
prtCluster = PointCluster(point[0].position, point[0].radius*1.5, point[0])
elif len(variables) == 2:
collPoints = filter(lambda x: x.key in variables, self.prtObjects)
if collPoints != []:
prtCluster = DistanceCluster(collPoints[0], collPoints[1])
elif len(variables) > 2:
prtCluster = ClusterI(constrainedness)
ptObjects = filter(lambda x: x.key in variables, self.prtObjects)
if ptObjects != []:
prtCluster.clusterPoints = ptObjects
else:
prtCluster = None
if prtCluster != None:
prtCluster.update()
self.clsObjects += [prtCluster]
return prtCluster
def __getOverConstrainedClusters(self,parent, ocClusters):
""" Get the highest cluster levels in the tree where overconstrainedness occurs.
This is a recursive function to receive the highest level overconstrained clusters.
Parameters:
parent - parent node
ocClusters - overconstrained clusters
Return:
level - highest level overconstrained clusters
"""
overconstrainedFound = False
for cluster in parent.subs:
if cluster.flag == GeometricDecomposition.I_OVER or cluster.flag == GeometricDecomposition.S_OVER:
self.__getOverConstrainedClusters(cluster, ocClusters)
overconstrainedFound = True
if not overconstrainedFound:
ocClusters += [parent]
def __getWellConstrainedClusters(self, parent, wellClusters, level=0, currentLevel=0):
if level == 0:
return
currentLevel += 1
for cluster in parent.subs:
if currentLevel != level:
self.__getWellConstrainedClusters(cluster, wellClusters, level, currentLevel)
elif cluster.flag == GeometricDecomposition.OK:
wellClusters += [cluster]
def getMergedConstraints(self, prtObj, withPrtObj):
""" Merge two points, with its constraints. Constraints which will merge or needs to be deleted, are returned.
Parameters:
prtObj - the point which needs to be merged with the withPrtObj
withPrtObj - the point which is merged with
Return:
list - list of merged or deleted constraints """
mergedDConstraints = []
mergedAConstraints = []
""" Filter all the distance constraints and distance helpers where the from and with objects
are represented in. The objects are first filtered, to minimize the comparison between the
constraints. """
dConstraints = filter(lambda x:(x.objType == ObjectType.DISTANCE_CONSTRAINT or x.objType == ObjectType.DISTANCE_HELPER) and (x.pointBegin == prtObj or x.pointEnd == prtObj or x.pointBegin == withPrtObj or x.pointEnd == withPrtObj), self.prtObjects)
""" Now the constraints are filtered they need to be checked whether they have points in common. When this is
the case and both of the constraints consist out of one of the parameters, then they should be
merged. """
for dConstraint in dConstraints:
for dConstraint2 in dConstraints:
if ((dConstraint.pointBegin == dConstraint2.pointBegin or dConstraint.pointEnd == dConstraint2.pointEnd) or \
(dConstraint.pointEnd == dConstraint2.pointBegin or dConstraint.pointBegin == dConstraint2.pointEnd)) and \
(dConstraint.pointBegin == prtObj or dConstraint.pointEnd == prtObj) and \
(dConstraint2.pointBegin == withPrtObj or dConstraint2.pointEnd == withPrtObj):
mergedDConstraints += [dConstraint]
break
#mergedDConstraints = self.__getMergedDistanceConstraints(mergedDConstraints, prtObj, withPrtObj)
""" Handling the angle constraint is similar to the distance constraint, only it needs to be
extended because the angle consists of 3 points instead of 2. """
aConstraints = filter(lambda x:x.objType == ObjectType.ANGLE_CONSTRAINT and (x.pointBegin == prtObj or x.pointMiddle == prtObj or x.pointEnd == prtObj or x.pointBegin == withPrtObj or x.pointMiddle == withPrtObj or x.pointEnd == withPrtObj), self.prtObjects)
for aConstraint in aConstraints:
for aConstraint2 in aConstraints:
if ((aConstraint.pointBegin == aConstraint2.pointBegin or aConstraint.pointMiddle == aConstraint2.pointMiddle or aConstraint.pointEnd == aConstraint2.pointEnd) or \
(aConstraint.pointBegin == aConstraint2.pointMiddle or aConstraint.pointBegin == aConstraint2.pointEnd) or \
(aConstraint.pointMiddle == aConstraint2.pointBegin or aConstraint.pointMiddle == aConstraint2.pointEnd) or \
(aConstraint.pointEnd == aConstraint2.pointBegin or aConstraint.pointEnd == aConstraint2.pointMiddle)) and \
(aConstraint.pointBegin == prtObj or aConstraint.pointMiddle == prtObj or aConstraint.pointEnd == prtObj) and \
(aConstraint2.pointBegin == withPrtObj or aConstraint2.pointMiddle == withPrtObj or aConstraint2.pointEnd == withPrtObj):
mergedAConstraints += [aConstraint]
break
#mergedAConstraints = self.__getMergedAngleConstraints(mergedAConstraints, prtObj, withPrtObj)
mergedConstraints = mergedAConstraints + mergedDConstraints
return mergedConstraints
def __getMergedDistanceConstraints(self,mergedDistanceConstraints, prtObj, withPrtObj):
deleteConstraints = []
dConstraints = filter(lambda x:((x.objType == ObjectType.DISTANCE_CONSTRAINT or x.objType == ObjectType.DISTANCE_HELPER) and (x.pointBegin == withPrtObj or x.pointEnd == withPrtObj)), self.prtObjects)
for mConstraint in mergedDistanceConstraints:
for dConstraint in dConstraints:
if (mConstraint.pointBegin == dConstraint.pointBegin and mConstraint.pointEnd == dConstraint.pointEnd) or \
(mConstraint.pointBegin == dConstraint.pointEnd and mConstraint.pointEnd == dConstraint.pointBegin):
deleteConstraints += [mConstraint]
break
return deleteConstraints
def __getMergedAngleConstraints(self,mergedAngleConstraints, prtObj, withPrtObj):
deleteConstraints = []
aConstraints = filter(lambda x:((x.objType == ObjectType.ANGLE_CONSTRAINT) and (x.pointBegin == withPrtObj or x.pointMiddle == withPrtObj or x.pointEnd == withPrtObj)), self.prtObjects)
for mConstraint in mergedAngleConstraints:
for aConstraint in aConstraints:
if (mConstraint.pointBegin == aConstraint.pointBegin and mConstraint.pointMiddle == aConstraint.pointMiddle and mConstraint.pointEnd == aConstraint.pointEnd) or \
(mConstraint.pointBegin == aConstraint.pointBegin and mConstraint.pointMiddle == aConstraint.pointEnd and mConstraint.pointEnd == aConstraint.pointMiddle) or \
(mConstraint.pointBegin == aConstraint.pointMiddle and mConstraint.pointMiddle == aConstraint.pointBegin and mConstraint.pointEnd == aConstraint.pointEnd) or \
(mConstraint.pointBegin == aConstraint.pointMiddle and mConstraint.pointMiddle == aConstraint.pointEnd and mConstraint.pointEnd == aConstraint.pointMiddle) or \
(mConstraint.pointBegin == aConstraint.pointEnd and mConstraint.pointMiddle == aConstraint.pointBegin and mConstraint.pointEnd == aConstraint.pointMiddle) or \
(mConstraint.pointBegin == aConstraint.pointEnd and mConstraint.pointMiddle == aConstraint.pointMiddle and mConstraint.pointEnd == aConstraint.pointBegin):
deleteConstraints += [mConstraint]
break
return deleteConstraints
def getConstraintInfoAsText(self):
if self.result != None:
if self.result.flag == GeometricDecomposition.I_UNDER:
return "Incidentally Underconstrained (change distance/angle values)"
elif self.result.flag == GeometricDecomposition.S_UNDER:
return "Structurally Underconstrained (assign more distances/angles)"
elif self.result.flag == GeometricDecomposition.I_OVER:
return "Incidentally Overconstrained (change distance/angle values)"
elif self.result.flag == GeometricDecomposition.S_OVER:
return "Structurally Overconstrained (remove distances/angles)"
elif self.result.flag == GeometricDecomposition.OK:
return "Well Constrained"
else:
return ""
else:
return ""
def removeAllObjects(self):
""" Removing all of the objects in the scene. """
self.removeObjects(self.prtObjects)
self.removeAllClusters()
self.objectNr = 1
def removeAllClusters(self):
self.removeClusterObjects(self.clsObjects)
def removeObjects( self, objects ):
""" Removing the objects from the list. The objects are also removed from the
constraint graph. The order of removal is important.
Parameters:
objects - objects that are to be removed
"""
for obj in objects:
if obj.objType == ObjectType.ANGLE_CONSTRAINT and not obj.ghost:
obj.con = self.geoProblem.get_angle( obj.pointBegin.key, obj.pointMiddle.key, obj.pointEnd.key )
self.geoProblem.rem_constraint( obj.con )
#print "removal of Angles succeeded """
for obj in objects:
if obj.objType == ObjectType.DISTANCE_CONSTRAINT and not obj.ghost:
#print " distance constr keys: ", obj.pointBegin.key, obj.pointEnd.key
obj.con = self.geoProblem.get_distance( obj.pointBegin.key, obj.pointEnd.key )
#print " got it "
self.geoProblem.rem_constraint( obj.con )
#print "removal of Distance Constraints succeeded """
for obj in objects:
if obj.objType == ObjectType.POINT and not obj.ghost:
self.geoProblem.rem_point( obj.key )
for obj in objects:
if obj.objType == ObjectType.FIXED_POINT and not obj.ghost:
self.geoProblem.rem_constraint( self.geoProblem.get_fix( obj.key ) )
#print "removal of Fixed points succeeded """
self.panel.removeItems( map( lambda x:x.name, objects ) )
self.prtObjects = filter( lambda x:x not in objects, self.prtObjects )
#print "removal of All other succeeded """
def removeClusterObjects(self, clsObjects, removeOnlyTemp=False, removeFixed=False):
if removeOnlyTemp and removeFixed:
self.clsObjects = filter(lambda x:x not in clsObjects or (not x.temporary or not x.fixed), self.clsObjects)
elif removeOnlyTemp:
self.clsObjects = filter(lambda x:x not in clsObjects or not x.temporary, self.clsObjects)
else:
self.clsObjects = filter(lambda x:x not in clsObjects, self.clsObjects)
def deleteObject( self, removeObject ):
""" Delete the object from the list of prototypes. If other objects are dependent on the deleted object, then
they will be removed too.
Paramaters:
removeObject - remove the object from the list of prototype objects.
"""
dellist = []
for prtObject in self.prtObjects:
if prtObject.objType == ObjectType.ANGLE_CONSTRAINT:
if prtObject.pointBegin == removeObject or prtObject.pointMiddle == removeObject or prtObject.pointEnd == removeObject:
dellist += [prtObject]
if prtObject.objType == ObjectType.DISTANCE_CONSTRAINT or prtObject.objType == ObjectType.DISTANCE_HELPER:
if prtObject.pointBegin == removeObject or prtObject.pointEnd == removeObject:
dellist += [prtObject]
dellist += [removeObject]
self.removeObjects( dellist )
def deleteSelectedObjects(self):
selectedObjects = self.getSelectedObjects()
for selObj in selectedObjects:
exists = filter(lambda x:x==selObj, self.prtObjects)
if len(exists) > 0:
self.deleteObject(selObj)
def getSelectedObjects(self):
return filter(lambda x:x.selected, self.prtObjects)
def updateObjects( self ):
""" Update all the objects, this might also be a ghost object (object that does not really exist, but is visualised). """
for prtObject in self.prtObjects:
prtObject.update()
if prtObject.objType == ObjectType.POINT and not prtObject.ghost:
pointPosition = self.geoProblem.get_point( prtObject.key )
pointPosition[0] = prtObject.position[0]
pointPosition[1] = prtObject.position[1]
pointPosition[2] = prtObject.position[2]
elif prtObject.objType == ObjectType.DISTANCE_CONSTRAINT and not prtObject.ghost:
if prtObject.distance != None:
self.updateConstraint(prtObject, prtObject.distance)
elif prtObject.objType == ObjectType.ANGLE_CONSTRAINT and not prtObject.ghost:
if prtObject.angle != None:
self.updateConstraint(prtObject, prtObject.angle)
for transpPrtObject in self.transpPrtObjects:
transpPrtObject.update()
def updateConstraint( self, obj, value ):
""" Update an existing constraint, with a new value. This value is also passed to the constraint graph.
Parameters:
obj - prototype object which needs to be updated.
value - the new value for the object.
"""
if obj.objType == ObjectType.DISTANCE_CONSTRAINT:
obj.distance = value
dConstraint = self.geoProblem.get_distance( obj.pointBegin.key, obj.pointEnd.key )
if dConstraint != None:
dConstraint._value = obj.distance
elif obj.objType == ObjectType.ANGLE_CONSTRAINT:
obj.angle = value
dAngle = self.geoProblem.get_angle( obj.pointBegin.key, obj.pointMiddle.key, obj.pointEnd.key )
if dAngle != None:
dAngle._value = math.radians(obj.angle)
def updateConstraintKeys(self, oldKey, newKey):
""" Update the keyvalues of a constraint. To update a key value, the constraints
must first be found which have the old key. Once found it must be replaced with the
new one. The constraint with the old key is therefore first to be removed from the graph
and then to be added again with the new key.
Parameters:
oldKey - the old key of the constraint, used for lookup of the constraints
newKey - the new key which has to be set for the constraints """
for prtObj in self.prtObjects:
if prtObj.objType == ObjectType.DISTANCE_CONSTRAINT:
if prtObj.pointBegin.key == oldKey or prtObj.pointEnd.key == oldKey:
dConstraint = self.geoProblem.get_distance(prtObj.pointBegin.key, prtObj.pointEnd.key)
if dConstraint != None:
self.geoProblem.rem_constraint(dConstraint)
if prtObj.pointBegin.key == oldKey:
prtObj.con = geosolver.DistanceConstraint( newKey, prtObj.pointEnd.key, prtObj.distance )
elif prtObj.pointEnd.key == oldKey:
prtObj.con = geosolver.DistanceConstraint( prtObj.pointBegin.key, newKey, prtObj.distance )
self.geoProblem.add_constraint(prtObj.con)
elif prtObj.objType == ObjectType.ANGLE_CONSTRAINT:
if prtObj.pointBegin.key == oldKey or prtObj.pointMiddle.key == oldKey or prtObj.pointEnd.key == oldKey:
aConstraint = self.geoProblem.get_angle(prtObj.pointBegin.key, prtObj.pointMiddle.key, prtObj.pointEnd.key)
self.geoProblem.rem_constraint(aConstraint)
if aConstraint != None:
if prtObj.pointBegin.key == oldKey:
prtObj.con = geosolver.AngleConstraint( newKey, prtObj.pointMiddle.key, prtObj.pointEnd.key, prtObj.angle )
elif prtObj.pointMiddle.key == oldKey:
prtObj.con = geosolver.AngleConstraint( prtObj.pointBegin.key, newKey, prtObj.pointEnd.key, prtObj.angle )
elif prtObj.pointEnd.key == oldKey:
prtObj.con = geosolver.AngleConstraint( prtObj.pointBegin.key, prtObj.pointMiddle.key, newKey, prtObj.angle )
self.geoProblem.add_constraint(prtObj.con)
def getImportedObjsByKey(self, key):
for impObj in self.importedObjs:
if (impObj.objType == ObjectType.POINT or impObj.objType == ObjectType.FIXED_POINT) and impObj.importKey == key:
return impObj
def addConstraint( self, obj ):
""" Add a constraint to an existing object.
Parameters:
obj - object for which the constraint must be added.
"""
if obj.objType == ObjectType.POINT:
self.geoProblem.add_constraint( geosolver.FixConstraint( obj.key, Vec( [obj.position[0], obj.position[1], obj.position[2]] ) ) )
newObj = FixedPoint( obj.key, obj.position, obj.radius )
self.replaceObject( obj, newObj )
def removeConstraint( self, obj ):
""" Remove a constraint from an existing object.
Parameters:
obj - object from which the constraint must be removed.
"""
if obj.objType == ObjectType.FIXED_POINT:
self.geoProblem.rem_constraint( self.geoProblem.get_fix( obj.key ) )
newObj = Point( obj.key, obj.position, obj.radius )
self.replaceObject( obj, newObj )
def replaceObject( self, oldObj, newObj ):
""" Replace object, when a constraint is added to an existing object it is replaced with a new type of object.
Because of this a new instance is created, which is not known by other prototype objects, so al the references
must be set correct.
Parameters:
oldObj - old object where some objects may reference to.
newObj - new object where must be referenced to.
"""
for prtObject in self.prtObjects:
prtObject.setNewReference( oldObj, newObj )
if self.objectSelected == oldObj:
self.objectSelected = newObj
self.prtObjects = filter( lambda x:x is not oldObj, self.prtObjects )
self.prtObjects += [newObj]
def replaceConstrainedObject( self, oldCstrObj, newCstrObj ):
""" Replace object, when a constraint is added to an existing object it is replaced with a new type of object.
Because of this a new instance is created, which is not known by other prototype objects, so al the references
must be set correct.
Parameters:
oldCstrObj - old object where some objects may reference to.
newCstrObj - new object where must be referenced to.
"""
mergedConstraints = self.getMergedConstraints(oldCstrObj, newCstrObj)
self.removeObjects(mergedConstraints)
self.updateConstraintKeys(oldCstrObj.key, newCstrObj.key)
for prtObject in self.prtObjects:
prtObject.setNewReference( oldCstrObj, newCstrObj )
if self.objectSelected == oldCstrObj:
self.objectSelected = newCstrObj
self.prtObjects = filter( lambda x:x is not oldCstrObj, self.prtObjects )
self.removeObjects([oldCstrObj])
def deselectObject( self ):
""" Deselect the selected object, which is selected """
if self.objectSelected != None:
self.objectSelected.selected = False
self.objectSelected = None
self.axis.selected = -1
self.showAxis = False
self.panel.updateEdit()
def deselectAllObjects(self, dsClObjects=True, onlyTemp=False):
""" Deselect all of the objects. """
for prtObject in self.prtObjects:
if onlyTemp:
if prtObject.temporarySelected:
prtObject.selected = False
prtObject.temporarySelected = False
else:
prtObject.selected = False
if dsClObjects:
for clsObject in self.clsObjects:
clsObject.selected = False
def drawObjects( self ):
""" Draw all of the objects. """
for prtObject in self.prtObjects:
if prtObject.selected and prtObject.showAxis and self.showAxis:
self.axis.draw()
if prtObject.isVisible:
prtObject.draw()
if self.visualiseClusters:
for clsObject in self.clsObjects:
if clsObject.isVisible:
clsObject.draw()
def drawTransparentObjects( self ):
""" Draw the transparent objects. (Obsolete) """
for transpPrtObject in self.transpPrtObjects:
if transpPrtObject.selected and transpPrtObject.showAxis and self.showAxis:
self.axis.draw()
transpPrtObject.draw()
def drawWithPicking( self ):
""" Draw objects with picking, so they can be selected with the mouse. This is done by setting an unique id for
every object. """
self.selectCounter=0
for prtObject in self.prtObjects:
if not prtObject.ghost:
glPushName( self.selectCounter )
prtObject.selectionId = self.selectCounter
if prtObject.selected:
self.axis.drawWithPicking()
prtObject.draw()
glPopName()
self.selectCounter += 1
def drawTransparentWithPicking( self ):
""" Draw transparent objects with picking, so they can be selected with the mouse. This is done by setting
an unique id for every object. """
for transpPrtObject in self.transpPrtObjects:
glPushName( self.selectCounter )
transpPrtObject.selectionId = self.selectCounter
if transpPrtObject.selected:
self.axis.drawWithPicking()
transpPrtObject.draw()
glPopName()
self.selectCounter += 1
def setVisibilityOfObjects(self, visible=True):
for prtObject in self.prtObjects:
prtObject.isVisible = visible
for clsObject in self.clsObjects:
clsObject.isVisible = visible
def setObjectVisibilityByClusters(self):
self.setVisibilityOfObjects(False)
found = False
for clsObject in self.clsObjects:
if clsObject.fixed == True:
found = True
if clsObject.objType == ObjectType.POINT:
points = filter(lambda x:(x.objType == ObjectType.POINT or x.objType == ObjectType.FIXED_POINT) and clsObject.relPoint==x, self.prtObjects)
for point in points:
point.isVisible = True
elif clsObject.objType == ObjectType.DISTANCE_HELPER:
distances = filter(lambda x:(x.objType == ObjectType.DISTANCE_CONSTRAINT or x.objType == ObjectType.DISTANCE_HELPER) and ((clsObject.pointBegin==x.pointBegin and clsObject.pointEnd == x.pointEnd) or (clsObject.pointBegin==x.pointEnd and clsObject.pointEnd == x.pointBegin)), self.prtObjects)
for distance in distances:
distance.isVisible = True
distance.pointBegin.isVisible = True
distance.pointEnd.isVisible = True
elif clsObject.objType == ObjectType.CLUSTER:
for point in clsObject.getClusterPoints():
pointObjs = filter(lambda x:(x.objType == ObjectType.POINT or x.objType == ObjectType.FIXED_POINT) and x == point,self.prtObjects)
for pointObj in pointObjs:
pointObj.isVisible = True
distances = filter(lambda x:x.objType == ObjectType.DISTANCE_CONSTRAINT or x.objType == ObjectType.DISTANCE_HELPER, self.prtObjects)
for distance in distances:
pBegin = filter(lambda x:x == distance.pointBegin, clsObject.getClusterPoints())
pEnd = filter(lambda x:x == distance.pointEnd, clsObject.getClusterPoints())
if len(pBegin) > 0 and len(pEnd) > 0:
distance.isVisible = True
angles = filter(lambda x:x.objType == ObjectType.ANGLE_CONSTRAINT, self.prtObjects)
for angle in angles:
pBegin = filter(lambda x:x == angle.pointBegin, clsObject.getClusterPoints())
pMiddle = filter(lambda x:x == angle.pointMiddle, clsObject.getClusterPoints())
pEnd = filter(lambda x:x == angle.pointEnd, clsObject.getClusterPoints())
if len(pBegin) > 0 and len(pMiddle) > 0 and len(pEnd) > 0:
angle.isVisible = True
for clsObject in self.clsObjects:
if clsObject.fixed == True:
clsObject.isVisible = True
if not found:
self.setVisibilityOfObjects(True)
def isObjectSelected( self ):
""" Check whether an object is selected. """
return self.objectIsSelected
def setObjectSelected( self, selected ):
""" Set whether the object is selected.
Parameters:
selected - whether the selected object is activated or not.
"""
self.objectIsSelected = selected
def selectObjectByName( self, name ):
""" Select an object by name. This name is NOT the key of an object, but the name which is filled in by
the user in the control panel.
Parameters:
name - the name of the object which must be selected
"""
for prtObject in self.prtObjects:
if prtObject.name == name:
self.deselectObject()
self.objectSelected = prtObject
self.objectSelected.selected = True
break
def selectObject(self, obj):
""" Select the given object.
Parameters:
obj - select this object.
"""
self.deselectObject()
self.objectSelected = obj
self.objectSelected.selected = True
self.panel.selectItemByName( obj.name )
def selectObjectsByKeys(self, variables):
""" Select multiple objects by their keys. These are unique and are the same as the keys in the solver.
Parameters:
variables - keys which needs to be selected
"""
#self.deselectAllObjects()
for prtobject in self.prtObjects:
keyfound = filter( lambda x:x == prtobject.key, variables )
if keyfound:
prtobject.selected = True
def selectClusterObjectByKeys(self, variables):
""" Get a clusterObject based on the keys given
Parameters:
variables - key that must be part of the clusterobject
"""
for clsObject in self.clsObjects:
clsPoints = clsObject.getClusterPoints()
if len(variables) == len(clsPoints):
variablesInCluster = True
for variable in variables:
if len(filter(lambda x:x.key == variable, clsPoints)) == 0:
variablesInCluster = False
break
if variablesInCluster:
return clsObject
return None
def getObjectByKey( self, key ):
""" Get an object by its unique key.
Parameters:
key - key of an object
"""
for prtObject in self.prtObjects:
if prtObject.key == key:
return prtObject
return None
def setSelectedObject( self, selectionId, bOnlySelect=False, bDeselectSelected = True ):
""" Set a selected object, by the selection id obtained from OpenGL.
Parameters:
selectionId - the selection id, which is the object that the user has chosen.
bOnlySelect - if it must only be highlighted, but further actions are not allowed.
"""
found = False
for prtObject in self.prtObjects:
if bDeselectSelected:
prtObject.selected = False
if prtObject.selectionId == selectionId[0][0] and not prtObject.ghost:
found = True
prtObject.selected = True
if not bOnlySelect:
self.objectSelected = prtObject
elif prtObject.isMovable:
prtObject.selected = False
self.panel.updateSelection = False
self.panel.selectItemByName( prtObject.name )
self.panel.updateSelection = True
if not found:
for transPrtObject in self.transpPrtObjects:
transPrtObject.selected = False
if transPrtObject.selectionId == selectionId[0][0]:
found = True
transPrtObject.selected = True
if not bOnlySelect:
self.objectSelected = transPrtObject
elif prtObject.isMovable:
prtObject.selected = False
def changeSelection(self, selectionId):
for prtObject in self.prtObjects:
found = False
if prtObject.selectionId == selectionId[0][0]:
if prtObject.selected:
prtObject.selected = False
else:
prtObject.selected = True
found = True
break
def setSelectedObjects( self, selectionIds, deselectObjects=True, temporarySel=False ):
for prtObject in self.prtObjects:
found = False
for selectionId in selectionIds:
if prtObject.selectionId == selectionId[0]:
prtObject.selected = True
if temporarySel:
prtObject.temporarySelected = True
found = True
break
if not found and deselectObjects:
prtObject.selected = False
def convertTemporySelection(self):
for prtObject in self.prtObjects:
if prtObject.temporarySelected:
prtObject.temporarySelected = False
def setPanel( self, panel ):
""" Set the panel in the main window for access, for updating information
Parameters:
panel - panel from the main window.
"""
self.panel = panel
def isNameUnique( self, oldName, newName ):
""" Check whether the name given by the user is unique.
Parameters:
oldName - the old name for the object.
newName - the new name for the object.
Return:
boolean - whether the name is unique or not.
"""
for prtObject in self.prtObjects:
if prtObject.name == newName and newName != oldName:
return False
return True
def setObjectName( self, oldName, newName ):
""" Set a new name for an object.
Parameters:
oldName - old name of an object for comparison
newName - new name for an object
"""
for prtObject in self.prtObjects:
if prtObject.name == oldName:
prtObject.name = newName
return True
return False
def showClusters(self):
if self.visualiseClusters:
self.visualiseClusters = False
else:
self.visualiseClusters = True
def getParameterRange(self, prtObject):
if self.result != None:
if self.result.flag == GeometricDecomposition.OK and prtObject.parameterRange == []:
if prtObject.objType == ObjectType.DISTANCE_CONSTRAINT:
dConstraint = self.geoProblem.get_distance(prtObject.pointBegin.key, prtObject.pointEnd.key)
prtObject.parameterRange = geosolver.prange.sample_prange(self.geoProblem, dConstraint, 0.0, prtObject.distance+100.0,0.5)
elif prtObject.objType == ObjectType.ANGLE_CONSTRAINT:
aConstraint = self.geoProblem.get_angle(prtObject.pointBegin.key, prtObject.pointMiddle.key, prtObject.pointEnd.key)
prtObject.parameterRange = geosolver.prange.sample_prange(self.geoProblem, aConstraint, 0.0, 360.0,0.1)
return prtObject.parameterRange
elif self.result.flag == GeometricDecomposition.OK and prtObject.parameterRange != []:
return prtObject.parameterRange
return []
def resetParameterRange(self):
for prtObj in self.prtObjects:
if prtObj.objType == ObjectType.DISTANCE_CONSTRAINT or prtObj.objType == ObjectType.ANGLE_CONSTRAINT:
prtObj.parameterRange = []
def solve( self ):
""" Solve the system of GCS. If there is a solution, then this is provided in the Solution View. The decomposition
is shown in the Decomposition View. """
print self.geoProblem
self.removeAllClusters()
self.resetParameterRange()
self.setVisibilityOfObjects(True)
geoSolver = geosolver.GeometricSolver( self.geoProblem )
self.result = geoSolver.get_result()
self.__handleResult()
# 20090521 - geoSolver is deleted in this context, but it is not deleted because geoProblem refers to it via Listener interface
# 20090521 - now fixed this bug
print self.result
print "solve finished"
def save(self, domDocument ):
pointNode = QtXml.QDomElement( domDocument.createElement( "Prototypes" ) )
pointNode.setAttribute( "number", self.objectNr )
pointNode.setAttribute( "numberOfImports", self.nrOfImports )
return pointNode
def load( self, domElements ):
""" Load the objects from a XML file.
Parameters:
domElements: different saved objects.
"""
elements = domElements.firstChild()
while not elements.isNull():
element = elements.toElement()
if not element.isNull():
prtObject = None
if element.tagName() == "Point":
prtObject = Point("", Vec([0.0, 0.0, 0.0]), 5.0)
elif element.tagName() == "FixedPoint":
prtObject = FixedPoint("", Vec([0.0, 0.0, 0.0]), 5.0)
elif element.tagName() == "AngleConstraint":
prtObject = AngleConstraint("", None, None, None)
elif element.tagName() == "Distance":
prtObject = Distance("", None, None)
elif element.tagName() == "DistanceConstraint":
prtObject = DistanceConstraint("", None, None)
elif element.tagName() == "Prototypes":
self.setObjectNumber(element)
else:
raise StandardError, "Unable to load unkown object", element.tagName()
if prtObject != None:
prtObject.load(element)
self.addObject(prtObject)
elements = elements.nextSibling()
self.updateObjects()
def importScene(self, domElements):
""" Import the objects from a XML file.
Parameters:
domElements: different saved objects.
"""
elements = domElements.firstChild()
while not elements.isNull():
element = elements.toElement()
if not element.isNull():
prtObject = None
if element.tagName() == "Point":
prtObject = Point("", Vec([0.0, 0.0, 0.0]), 5.0)
elif element.tagName() == "FixedPoint":
prtObject = FixedPoint("", Vec([0.0, 0.0, 0.0]), 5.0)
elif element.tagName() == "AngleConstraint":
prtObject = AngleConstraint("", None, None, None)
elif element.tagName() == "Distance":
prtObject = Distance("", None, None)
elif element.tagName() == "DistanceConstraint":
prtObject = DistanceConstraint("", None, None)
else:
raise StandardError, "Unable to import unkown object", element.tagName()
if prtObject != None:
prtObject.importItem(element, self.nrOfImports, self.objectNr )
self.importedObjs += [prtObject]
self.addObject(prtObject)
elements = elements.nextSibling()
self.updateObjects()
self.nrOfImports += 1
self.importedObjs = []
# Rick 20090522
def setProblem(self, problem):
""" Import the objects from a GeometricProblem.
Parameters:
problem: a GeometricProblem instance
"""
# remove all objects first
# self.removeAllObjects()
# add point variabels and store a mapping
map = {}
vars = problem.cg.variables();
for var in vars:
if problem.has_point(var):
prtObject = Point(var, Vec(problem.get_point(var)), 5.0)
map[var]=prtObject
self.addObject(prtObject)
else:
raise StandardError, "Unable to import non-point variable: "+str(var)
# add constraints
constraints = problem.cg.constraints();
count = 0
for con in constraints:
if isinstance(con, geosolver.DistanceConstraint):
name = "dist_"+str(con.variables()[0])+"_"+str(con.variables()[1])
count += 1
prtObject = DistanceConstraint(name,
map[con.variables()[0]],
map[con.variables()[1]]
)
self.addObject(prtObject)
elif isinstance(con, geosolver.AngleConstraint):
name = "angle_"+str(con.variables()[0])+"_"+str(con.variables()[1])+str(con.variables()[2])
count += 1
prtObject = AngleConstraint(name,
map[con.variables()[0]],
map[con.variables()[1]],
map[con.variables()[2]]
)
self.addObject(prtObject)
else:
raise StandardError, "Unable to import constraint: "+str(con)
# compute object visulisation, etc
self.updateObjects()
def setObjectNumber(self, domElement):
self.objectNr = domElement.attribute("number", "").toInt()[0]
self.nrOfImports = domElement.attribute("numberOfImports", "").toInt()[0]
class Object:
""" The general prototype object class. All objects which must be visualised, or have a connection with the constraint
solver must be subclassed from the Object class. """
def __init__( self ):
self.settings = Settings()
self.selectionId = 0
self.selectColor = self.settings.sketcherData.selectColor
self.selected = False
self.temporarySelected = False
self.quadric = gluNewQuadric()
gluQuadricNormals(self.quadric, GLU_SMOOTH)
self.ghost = False
self.showAxis = False
self.isMovable = False
self.isVisible = True
def draw( self ):
""" A virtual draw function, for drawing the object. """
raise NotImplementedError( caller + ' must be implemented in subclass' )
def clone( self ):
""" A virtual clone function, to clone an object. """
raise NotImplementedError( caller + ' must be implemented in subclass' )
def update( self ):
""" A virtual update function, to update an object. """
raise NotImplementedError( caller + ' must be implemented in subclass' )
def setNewReference( self, oldObj, newObj ):
""" A virtual set new reference function, to dereference an old object and reference to the new one.
Parameters:
oldObj - old object which must be dereferenced
newObj - new object where must be referenced to
"""
raise NotImplementedError( caller + ' must be implemented in subclass' )
def load(self, domElement):
""" A virtual load function to load the object from a XML file and set the initial values.
Parameters:
domElement - an element which contains information about an object.
"""
raise NotImplementedError( caller + ' must be implemented in subclass' )
def save( self, domDocument ):
""" A virtual save function to save the object to a XML file.
Parameters:
domDocument - a document where must be saved to.
"""
raise NotImplementedError( caller + ' must be implemented in subclass' )
def importItem(self, domElement, nrOfImports=0, objNr=0):
""" A virtual importItem function to import the object from a XML file into the scene.
Parameters:
domElement - an element which contains information about an object.
nrOfImports - a number added to the name of the import, to make it unique
objNr - total number of objects already in the scene
"""
raise NotImplementedError( caller + ' must be implemented in subclass' )
class Point( Object ):
def __init__( self, name, position, radius ):
Object.__init__( self )
self.name = name
self.key = name
self.importKey = name
self.position = position
self.radius = self.settings.sketcherData.pointRadius
self.color = self.settings.sketcherData.pointColor
self.showAxis = True
self.objType = ObjectType.POINT
self.fixed = False
self.ghost = False
self.needUpdate = True
def draw( self ):
if self.selected:
glColor3fv( [self.selectColor.redF(),self.selectColor.greenF(), self.selectColor.blueF()])
else:
glColor3fv( [self.color.redF(),self.color.greenF(), self.color.blueF()])
glPushMatrix()
glTranslatef( self.position[0], self.position[1], self.position[2] )
gluSphere( self.quadric, self.radius, 10, 10 )
glPopMatrix()
def updatePosition( self, translation ):
self.position[0] += translation[0]
self.position[1] += translation[1]
self.position[2] += translation[2]
def setPosition( self, position ):
self.position[0] = position[0]
self.position[1] = position[1]
self.position[2] = position[2]
def update( self ):
pass
def setNewReference( self, oldObj, newObj ):
pass
def clone( self, **attr ):
obj = deepcopy( self )
obj.__dict__.update( attr )
return obj
def setTexture( self, texture ):
pass
def load (self, domElement):
self.key = str(domElement.attribute("key", ""))
self.name = str(domElement.attribute("name", ""))
self.position[0] = domElement.attribute("posX", "").toFloat()[0]
self.position[1] = domElement.attribute("posY", "").toFloat()[0]
self.position[2] = domElement.attribute("posZ", "").toFloat()[0]
def importItem(self, domElement, nrOfImports=0, objNr=0):
self.key = "p" + str(objNr)
self.importKey = str(domElement.attribute("key", ""))
self.name = str(domElement.attribute("name", ""))
self.name += "_" + str(nrOfImports)
self.position[0] = domElement.attribute("posX", "").toFloat()[0]
self.position[1] = domElement.attribute("posY", "").toFloat()[0]
self.position[2] = domElement.attribute("posZ", "").toFloat()[0]
def save( self, domDocument ):
pointNode = QtXml.QDomElement( domDocument.createElement( "Point" ) )
pointNode.setAttribute( "key", self.key )
pointNode.setAttribute( "name", self.name )
pointNode.setAttribute( "posX", str(self.position[0]))
pointNode.setAttribute( "posY", str(self.position[1]) )
pointNode.setAttribute( "posZ", str(self.position[2]) )
return pointNode
class FixedPoint( Point ):
def __init__( self, name, position, radius ):
Point.__init__( self, name, position, radius )
self.objType = ObjectType.FIXED_POINT
self.radius = self.settings.sketcherData.fPointRadius
self.color = self.settings.sketcherData.fPointColor
def draw( self ):
if self.selected:
glColor3fv( [self.selectColor.redF(),self.selectColor.greenF(), self.selectColor.blueF()])
else:
glColor3fv( [self.color.redF(),self.color.greenF(), self.color.blueF()])
glPushMatrix()
glTranslatef( self.position[0], self.position[1], self.position[2] )
gluSphere( self.quadric, self.radius, 10, 10 )
glPopMatrix()
def load (self, domElement):
Point.load(self, domElement)
def importItem(self, domElement, nrOfImports=0, objNr=0):
Point.importItem(self, domElement, imported=False, nrOfImports=0, objNr=0)
self.key = "f" + str(objNr)
def save( self, domDocument ):
pointNode = QtXml.QDomElement( domDocument.createElement( "FixedPoint" ) )
pointNode.setAttribute( "key", self.key )
pointNode.setAttribute( "name", self.name )
pointNode.setAttribute( "posX", str(self.position[0]) )
pointNode.setAttribute( "posY", str(self.position[1]) )
pointNode.setAttribute( "posZ", str(self.position[2]) )
return pointNode
class AngleConstraint( Object ):
def __init__( self, name, pBegin, pMiddle, pEnd ):
Object.__init__( self )
self.pointBegin = pBegin
self.pointMiddle = pMiddle
self.pointEnd = pEnd
self.key = name
self.name = name
self.realAngle = 0.0
self.angle = None
self.con = None
self.showAxis = False
self.objType = ObjectType.ANGLE_CONSTRAINT
self.color = self.settings.sketcherData.angleColor
self.height = 25.0
self.angleDisc = Quaternion()
self.rotAngleMatrix = Numeric.identity(4)
self.normVec = Vec([0.0, 0.0, 0.0])
self.parameterRange=[]
self.fixed = False
# rick 20090519
self.height1 = None
self.height2 = None
self.orientation1 = Quaternion()
self.orientation2 = Quaternion()
self.radius = 0.0 # self.settings.sketcherData.distanceRadius
self.update()
def draw( self ):
""" Visualisation of the angle constraint """
# first draw disk
glPushMatrix()
# Rick 20090519 glMultMatrixd doesn't work properly, see above
# glMultMatrixd( self.rotAngleMatrix )
axis = -self.angleDisc.axis()
angle = self.angleDisc.angle()
pos = self.pointMiddle.position
glTranslate(pos[0],pos[1],pos[2])
glRotate(angle*180/math.pi, axis[0], axis[1], axis[2])
#glDisable( GL_DEPTH_TEST )
glEnable ( GL_BLEND )
if self.selected:
glColor4fv( [self.selectColor.redF(),self.selectColor.greenF(), self.selectColor.blueF(),self.selectColor.alphaF()])
else:
glColor4fv( [self.color.redF(),self.color.greenF(), self.color.blueF(), self.color.alphaF()])
""" Visualisate angle constraint as transparent partial disk """
gluPartialDisk(self.quadric, self.pointMiddle.radius, self.height, 20, 10, 0.0, self.realAngle)
glDisable ( GL_BLEND )
#glEnable( GL_DEPTH_TEST )
glPopMatrix()
glPushMatrix()
self.drawAxis()
glPopMatrix()
# draw cylinder1
glPushMatrix()
if self.selected:
glColor3fv( [self.selectColor.redF(),self.selectColor.greenF(), self.selectColor.blueF()])
else:
glColor3fv( [self.color.redF(),self.color.greenF(), self.color.blueF()])
if self.height1 == 0.0:
self.height1 = 0.001
if self.radius == 0:
glBegin(GL_LINES)
glVertex3f(self.pointBegin.position[0], self.pointBegin.position[1], self.pointBegin.position[2])
glVertex3f(self.pointMiddle.position[0], self.pointMiddle.position[1], self.pointMiddle.position[2])
glEnd()
else:
#glMultMatrixd( self.rotMatrix )
# there is either a bug in glMultMatrixd or in Quaternion.getRotationMatrix
# or maybe it has to do with Numpy -> Numeric transition?
# now doing it with glTranslate/Rotate
axis = -self.orientation1.axis()
angle = self.orientation1.angle()
pos = self.pointBegin.position
glTranslate(pos[0],pos[1],pos[2])
glRotate(angle*180/math.pi, axis[0], axis[1], axis[2])
#print "gluCylinder ", self.radius, self.radius, self.height, 10, 10
gluCylinder( self.quadric, float(self.radius), float(self.radius), float(self.height1), 10, 10 )
glPopMatrix()
# draw cylinder2
glPushMatrix()
if self.selected:
glColor3fv( [self.selectColor.redF(),self.selectColor.greenF(), self.selectColor.blueF()])
else:
glColor3fv( [self.color.redF(),self.color.greenF(), self.color.blueF()])
if self.height2 == 0.0:
self.height2 = 0.001
if self.radius == 0:
glBegin(GL_LINES)
glVertex3f(self.pointMiddle.position[0], self.pointMiddle.position[1], self.pointMiddle.position[2])
glVertex3f(self.pointEnd.position[0], self.pointEnd.position[1], self.pointEnd.position[2])
glEnd()
else:
#glMultMatrixd( self.rotMatrix )
# there is either a bug in glMultMatrixd or in Quaternion.getRotationMatrix
# or maybe it has to do with Numpy -> Numeric transition?
# now doing it with glTranslate/Rotate
axis = -self.orientation2.axis()
angle = self.orientation2.angle()
pos = self.pointMiddle.position
glTranslate(pos[0],pos[1],pos[2])
glRotate(angle*180/math.pi, axis[0], axis[1], axis[2])
#print "gluCylinder ", self.radius, self.radius, self.height, 10, 10
gluCylinder( self.quadric, float(self.radius), float(self.radius), float(self.height2), 10, 10 )
glPopMatrix()
def drawAxis( self ):
pass
def update( self ):
""" The vector is calculated where to rotate to. This is the up-vector relative
to the plane where the angle constraint must be visualised """
# compute transform for cylinder1: height1 and orientation1
self.height1 = (self.pointBegin.position - self.pointMiddle.position ).norm()
if self.height1 == 0.0:
self.height1 = 0.001
diff = self.pointMiddle.position - self.pointBegin.position
self.orientation1.fromDirection( Vec( [0.0, 0.0, self.height1] ), diff )
# compute transform for cylinder2: height2 and orientation2
self.height2 = (self.pointEnd.position - self.pointMiddle.position ).norm()
if self.height2 == 0.0:
self.height2 = 0.001
diff = self.pointEnd.position - self.pointMiddle.position
self.orientation2.fromDirection( Vec( [0.0, 0.0, self.height2] ), diff )
# compute transform for disk
diffToBegin = self.pointBegin.position - self.pointMiddle.position
diffToEnd = self.pointEnd.position - self.pointMiddle.position
diffBeginEnd = diffToEnd - diffToBegin
vMiddlePoint = self.pointMiddle.position - self.pointBegin.position
vMiddleMiddle = (diffBeginEnd*0.5) - vMiddlePoint
diffBeginEnd.normalize()
vAngleStart = copy(vMiddleMiddle)
vMiddleMiddle.normalize()
if diffToBegin.norm() > 1e10:
diffToBegin.normalize()
#else:
# diffToBegin = Vec([1.0,0,0])
if diffToEnd.norm() > 1e10:
diffToEnd.normalize()
#else:
# diffToEnd = Vec([0,1,0])
""" Retrieve the up-vector, and rotate based upon this vector and the starting direction """
rotateTo = vMiddleMiddle.cross(diffBeginEnd)
self.angleDisc.fromDirection(Vec( [0.0, 0.0, 1.0] ), rotateTo )
""" Retrieve the part of the disk that needs to be visualised """
angleFromTo = Quaternion()
angleFromTo.fromDirection( diffToBegin, diffToEnd )
self.realAngle = math.degrees( angleFromTo.angle() )
if not self.ghost and not self.fixed:
self.angle = self.realAngle
""" Rotate to the location from where to start the visualisation of the partial disk """
angleStartPartialDisk = Quaternion()
self.inverseRot = self.angleDisc.inverseRotate(Vec([0.0, 1.0, 0.0]))
if self.angle > 180.0:
self.realAngle = 360.0-self.realAngle
angleStartPartialDisk.fromDirection(self.inverseRot, diffToBegin)
else:
angleStartPartialDisk.fromDirection(self.inverseRot, diffToEnd)
self.angleDisc = self.angleDisc * angleStartPartialDisk
""" Translate the partial disk to the middle point and store the matrix """
self.angleDisc.getRotationMatrix( self.rotAngleMatrix )
self.rotAngleMatrix[3][0] = self.pointMiddle.position[0]
self.rotAngleMatrix[3][1] = self.pointMiddle.position[1]
self.rotAngleMatrix[3][2] = self.pointMiddle.position[2]
self.rotAngleMatrix[3][3] = 1.0
def setNewReference( self, oldObj, newObj ):
""" When objects change properties new references must be set """
if self.pointBegin == oldObj:
self.pointBegin = newObj
elif self.pointMiddle == oldObj:
self.pointMiddle = newObj
elif self.pointEnd == oldObj:
self.pointEnd = newObj
def clone( self, **attr ):
""" Create a copy of this object """
obj = deepcopy( self )
obj.__dict__.update( attr )
return obj
def load (self, domElement):
""" Load the angle constraint from the xml-file """
self.key = str(domElement.attribute("key", ""))
self.name = str(domElement.attribute("name", ""))
pBeginKey = str(domElement.attribute("pBeginKey", ""))
pMiddleKey = str(domElement.attribute("pMiddleKey", ""))
pEndKey = str(domElement.attribute("pEndKey", ""))
self.pointBegin = PrototypeManager().getObjectByKey(pBeginKey)
self.pointMiddle = PrototypeManager().getObjectByKey(pMiddleKey)
self.pointEnd = PrototypeManager().getObjectByKey(pEndKey)
self.angle = domElement.attribute("angle", "").toDouble()[0]
if domElement.attribute("fixed", "") == "True":
self.fixed = True
else:
self.fixed = False
def importItem(self, domElement, nrOfImports=0, objNr=0):
self.key = "a" + str(objNr)
self.importKey = str(domElement.attribute("key", ""))
self.name = str(domElement.attribute("name", ""))
self.name += "_" + str(nrOfImports)
pBeginKey = str(domElement.attribute("pBeginKey", ""))
pMiddleKey = str(domElement.attribute("pMiddleKey", ""))
pEndKey = str(domElement.attribute("pEndKey", ""))
self.pointBegin = PrototypeManager().getImportedObjsByKey(pBeginKey)
self.pointMiddle = PrototypeManager().getImportedObjsByKey(pMiddleKey)
self.pointEnd = PrototypeManager().getImportedObjsByKey(pEndKey)
self.angle = domElement.attribute("angle", "").toDouble()[0]
if domElement.attribute("fixed", "") == "True":
self.fixed = True
else:
self.fixed = False
def save( self, domDocument ):
""" Save the angle constraint to the xml-file """
angleNode = QtXml.QDomElement( domDocument.createElement( "AngleConstraint" ) )
angleNode.setAttribute( "pBeginKey", self.pointBegin.key )
angleNode.setAttribute( "pMiddleKey", self.pointMiddle.key )
angleNode.setAttribute( "pEndKey", self.pointEnd.key )
angleNode.setAttribute( "key", self.key )
angleNode.setAttribute( "name", self.name )
angleNode.setAttribute( "angle", str(self.angle) )
angleNode.setAttribute( "fixed", str(self.fixed) )
return angleNode
class Distance( Object ):
def __init__( self, name, pBegin, pEnd ):
Object.__init__( self )
self.pointBegin = pBegin
self.pointEnd = pEnd
self.radius = self.settings.sketcherData.lineRadius
self.name = name
self.key = name
self.orientation = Quaternion()
self.rotMatrix = Numeric.identity(4)
self.height = 0.1
self.fixed = False
self.showAxis = False
self.objType = ObjectType.DISTANCE_HELPER
self.color = self.settings.sketcherData.lineColor
if self.pointBegin != None and self.pointEnd != None:
self.distance = (self.pointBegin.position - self.pointEnd.position ).norm()
else:
self.distance = 0.0
def update( self ):
self.height = (self.pointBegin.position - self.pointEnd.position ).norm()
if self.height == 0.0:
self.height = 0.001
diff = self.pointEnd.position - self.pointBegin.position
self.orientation.fromDirection( Vec( [0.0, 0.0, self.height] ), diff )
#print "cylinder orientation:",self.orientation
#print "axis:",self.orientation.axis(), "angle:", self.orientation.angle()
self.orientation.getRotationMatrix( self.rotMatrix )
self.rotMatrix[3][0] = self.pointBegin.position[0]
self.rotMatrix[3][1] = self.pointBegin.position[1]
self.rotMatrix[3][2] = self.pointBegin.position[2]
self.rotMatrix[3][3] = 1.0
#print "cylinder rotMatix:",self.rotMatrix
def draw( self ):
glPushMatrix()
if self.selected:
glColor3fv( [self.selectColor.redF(),self.selectColor.greenF(), self.selectColor.blueF()])
else:
glColor3fv( [self.color.redF(),self.color.greenF(), self.color.blueF()])
if self.height == 0.0:
self.height = 0.001
if self.radius == 0:
glBegin(GL_LINES)
glVertex3f(self.pointBegin.position[0], self.pointBegin.position[1], self.pointBegin.position[2])
glVertex3f(self.pointEnd.position[0], self.pointEnd.position[1], self.pointEnd.position[2])
glEnd()
else:
#glMultMatrixd( self.rotMatrix )
# there is either a bug in glMultMatrixd or in Quaternion.getRotationMatrix
# or maybe it has to do with Numpy -> Numeric transition?
# now doing it with glTranslate/Rotate
axis = -self.orientation.axis()
angle = self.orientation.angle()
pos = self.pointBegin.position
glTranslate(pos[0],pos[1],pos[2])
glRotate(angle*180/math.pi, axis[0], axis[1], axis[2])
#print "gluCylinder ", self.radius, self.radius, self.height, 10, 10
gluCylinder( self.quadric, float(self.radius), float(self.radius), float(self.height), 10, 10 )
glPopMatrix()
def setNewReference( self, oldObj, newObj ):
if self.pointBegin == oldObj:
self.pointBegin = newObj
elif self.pointEnd == oldObj:
self.pointEnd = newObj
def clone( self, **attr ):
obj = deepcopy( self )
obj.__dict__.update( attr )
return obj
def load (self, domElement):
self.key = str(domElement.attribute("key", ""))
self.name = str(domElement.attribute("name", ""))
pBeginKey = str(domElement.attribute("pBeginKey", ""))
pEndKey = str(domElement.attribute("pEndKey", ""))
self.pointBegin = PrototypeManager().getObjectByKey(pBeginKey)
self.pointEnd = PrototypeManager().getObjectByKey(pEndKey)
self.distance = domElement.attribute("distance", "").toDouble()[0]
def importItem(self, domElement, nrOfImports=0, objNr=0):
self.key = "l" + str(objNr)
self.importKey = str(domElement.attribute("key", ""))
self.name = str(domElement.attribute("name", ""))
self.name += "_" + str(nrOfImports)
pBeginKey = str(domElement.attribute("pBeginKey", ""))
pEndKey = str(domElement.attribute("pEndKey", ""))
self.pointBegin = PrototypeManager().getImportedObjsByKey(pBeginKey)
self.pointEnd = PrototypeManager().getImportedObjsByKey(pEndKey)
self.distance = domElement.attribute("distance", "").toDouble()[0]
def save( self, domDocument ):
distanceNode = QtXml.QDomElement( domDocument.createElement( "Distance" ) )
distanceNode.setAttribute( "pBeginKey", self.pointBegin.key )
distanceNode.setAttribute( "pEndKey", self.pointEnd.key )
distanceNode.setAttribute( "key", self.key )
distanceNode.setAttribute( "name", self.name )
distanceNode.setAttribute( "distance", str(self.distance) )
return distanceNode
class DistanceConstraint( Distance ):
def __init__( self, name, pBegin, pEnd ):
Distance.__init__( self, name, pBegin, pEnd )
self.radius = self.settings.sketcherData.distanceRadius
self.objType = ObjectType.DISTANCE_CONSTRAINT
self.con = None
self.color = self.settings.sketcherData.distanceColor
self.texture = None
self.fixed = False
self.parameterRange=[]
def clone( self, **attr ):
obj = deepcopy( self )
obj.__dict__.update( attr )
return obj
def update(self):
Distance.update(self)
if not self.fixed and not self.ghost:
self.distance = self.height
def load (self, domElement):
Distance.load(self, domElement)
if domElement.attribute("fixed", "") == "True":
self.fixed = True
else:
self.fixed = False
def importItem(self, domElement, nrOfImports=0, objNr=0):
Distance.importItem(self, domElement, nrOfImports, objNr)
self.key = "d" + str(objNr)
print "Distance: ", self.key, self.name, self.pointBegin.key, self.pointEnd.key
if domElement.attribute("fixed", "") == "True":
self.fixed = True
else:
self.fixed = False
def save( self, domDocument ):
distanceNode = QtXml.QDomElement( domDocument.createElement( "DistanceConstraint" ) )
distanceNode.setAttribute( "pBeginKey", self.pointBegin.key )
distanceNode.setAttribute( "pEndKey", self.pointEnd.key )
distanceNode.setAttribute( "key", self.key )
distanceNode.setAttribute( "name", self.name )
distanceNode.setAttribute( "distance", str(self.distance) )
distanceNode.setAttribute( "fixed", str(self.fixed) )
return distanceNode
class Cluster( Object ):
def __init__(self, pBegin, pMiddle, pEnd):
Object.__init__( self )
self.name = ""
self.pointBegin = pBegin
self.pointMiddle = pMiddle
self.pointEnd = pEnd
self.objType = None
self.color = [1.0, 0.0, 0.0, 0.15]
self.height = 40.0
def draw( self ):
glPushMatrix()
glDisable( GL_DEPTH_TEST )
glEnable ( GL_BLEND )
glColor4fv( self.color )
glBegin(GL_TRIANGLES)
glVertex3f(self.pointBegin.position[0], self.pointBegin.position[1], self.pointBegin.position[2])
glVertex3f(self.pointMiddle.position[0], self.pointMiddle.position[1], self.pointMiddle.position[2])
glVertex3f(self.pointEnd.position[0], self.pointEnd.position[1], self.pointEnd.position[2])
glEnd()
glDisable ( GL_BLEND )
glEnable( GL_DEPTH_TEST )
glPopMatrix()
def update( self ):
pass
class Axis( Object ):
def __init__( self, position, width, height ):
Object.__init__( self )
self.position = position
self.width = width
self.height = height
self.selected = False
self.selectionID = 0
self.isMovable = True
def draw( self ):
glPushMatrix()
glTranslate( self.position[0], self.position[1], self.position[2] )
self.drawXAxis()
self.drawYAxis()
self.drawZAxis()
glPopMatrix()
def drawWithPicking( self ):
glPushMatrix()
glTranslate( self.position[0], self.position[1], self.position[2] )
glPushName( 1 )
self.drawXAxis()
glPopName()
glPushName( 2 )
self.drawYAxis()
glPopName()
glPushName( 3 )
self.drawZAxis()
glPopName()
glPopMatrix()
def clone( self, **attr ):
obj = deepcopy( self )
obj.__dict__.update( attr )
return obj
def updatePosition( self, position ):
self.position = position
def drawXAxis( self ):
# x axis
glPushMatrix()
if self.selected == True and self.selectionId == 1:
glColor3fv( [1.0, 1.0, 0.0] )
else:
glColor3fv( [1.0, 0.0, 0.0] )
glTranslate( -1.0, 0.0, 0.0 )
glRotate( 90, 0.0, 1.0 , 0.0 )
#glRotate(180, 1.0, 0.0, 0.0)
gluCylinder( self.quadric, self.width, self.width, self.height, 10, 10 )
glPushMatrix()
glTranslatef( 0.0, 0.0, self.height )
gluCylinder( self.quadric, self.width*2.5, 0.0, self.height/5, 10, 10 )
glPopMatrix()
glPopMatrix()
def drawYAxis( self ):
# y axis
glPushMatrix()
if self.selected == True and self.selectionId == 2:
glColor3fv( [1.0, 1.0, 0.0] )
else:
glColor3fv( [0.0, 1.0, 0.0] )
glRotate( -90, 1.0, 0.0 , 0.0 )
gluCylinder( self.quadric, self.width, self.width, self.height, 10, 10 )
glPushMatrix()
glTranslatef( 0.0, 0.0, self.height )
gluCylinder( self.quadric, self.width*2.5, 0.0, self.height/5, 10, 10 )
newFont = QtGui.QFont()
newFont.setStyleStrategy( QtGui.QFont.OpenGLCompatible )
#self.activeViewport.renderText(14.0, 10.0, 1.0, 'XY', newFont)
#glEnable(GL_LIGHTING)
glPopMatrix()
glPopMatrix()
def drawZAxis( self ):
# z axis
glPushMatrix()
if self.selected == True and self.selectionId == 3:
glColor3fv( [1.0, 1.0, 0.0] )
else:
glColor3fv( [0.0, 0.0, 1.0] )
glRotate( 180, 0.0, 1.0 , 0.0 )
gluCylinder( self.quadric, self.width, self.width, self.height, 10, 10 )
glPushMatrix()
glTranslatef( 0.0, 0.0, self.height )
gluCylinder( self.quadric, self.width*2.5, 0.0, self.height/5, 10, 10 )
glPopMatrix()
glPopMatrix()
def setNewReference( self, oldObj, newObj ):
pass
class PointCluster ( Point ):
def __init__( self, position, radius, relatedPoint ):
Point.__init__(self,"", position, radius)
self.color = [1.0, 0.0, 0.0, 0.4]
self.selectColor = [1.0, 1.0, 0.0, 0.4]
self.temporary = False
self.fixed = False
self.relPoint = relatedPoint
def draw( self ):
glPushMatrix()
glEnable ( GL_BLEND )
if self.selected:
glColor4fv( self.selectColor )
else:
glColor4fv( self.color )
glTranslatef( self.position[0], self.position[1], self.position[2] )
gluSphere( self.quadric, self.radius, 10, 10 )
glDisable ( GL_BLEND )
glPopMatrix()
def getClusterPoints(self):
clusterPoints = []
clusterPoints += [self]
return clusterPoints
class DistanceCluster( Distance ):
def __init__( self, pBegin, pEnd ):
Distance.__init__(self,"", pBegin, pEnd)
# Rick 20090519 - set radius from preferences
#self.radius = 3.0
self.radius = self.settings.sketcherData.distanceRadius * 1.5
self.color = [1.0, 0.0, 0.0, 0.4]
self.selectColor = [1.0, 1.0, 0.0, 0.4]
self.temporary = False
self.fixed = False
def draw( self ):
glPushMatrix()
if self.selected:
glColor4fv( self.selectColor )
else:
glColor4fv( self.color )
glEnable ( GL_BLEND )
# Rick 20090519 glMultMatrixd doesn't work properly, see above
# glMultMatrixd( self.rotMatrix )
axis = -self.orientation.axis()
angle = self.orientation.angle()
pos = self.pointBegin.position
glTranslate(pos[0],pos[1],pos[2])
glRotate(angle*180/math.pi, axis[0], axis[1], axis[2])
if self.height == 0.0:
self.height = 0.1
gluCylinder( self.quadric, float(self.radius), float(self.radius), float(self.height), 10, 10 )
glDisable ( GL_BLEND )
glPopMatrix()
def getClusterPoints(self):
clusterPoints = []
clusterPoints += [self.pointBegin]
clusterPoints += [self.pointEnd]
return clusterPoints
class ClusterI( Object ):
def __init__(self, constrainedness):
Object.__init__( self )
self.name = ""
self.points = ""
self.dimension = 3
self.zeroIndex = None
self.objType = ObjectType.CLUSTER
self.constrainedness = constrainedness
self.color = [1.0, 0.0, 0.0, 0.2]
self.underconstrainedClr = [1.0, 0.0, 0.0, 0.2]
self.overconstrainedClr = [0.0, 0.0, 1.0, 0.2]
self.wellconstrainedClr = [0.0, 1.0, 0.0, 0.2]
self.selectColor = [1.0, 1.0, 0.0, 0.15]
self.clusterPoints = []
self.pickColor()
self.temporary = False
self.fixed = False
self.hull = None
def pickColor(self):
if self.constrainedness == GeometricDecomposition.I_UNDER or self.constrainedness == GeometricDecomposition.S_UNDER:
self.color = self.underconstrainedClr
elif self.constrainedness == GeometricDecomposition.I_OVER or self.constrainedness == GeometricDecomposition.S_OVER:
self.color = self.overconstrainedClr
elif self.constrainedness == GeometricDecomposition.OK:
self.color = self.wellconstrainedClr
def draw( self ):
glPushMatrix()
if self.selected:
glColor4fv( self.selectColor )
else:
glColor4fv( self.color )
if self.hull != None:
for triangle in self.hull:
#glDisable( GL_DEPTH_TEST)
glEnable ( GL_BLEND )
glBegin(GL_TRIANGLES)
for vertex in triangle:
glVertex3f(vertex[0], vertex[1], vertex[2])
glEnd()
glDisable ( GL_BLEND )
#glEnable( GL_DEPTH_TEST)
glBegin(GL_LINES)
glVertex3f(triangle[0][0], triangle[0][1], triangle[0][2])
glVertex3f(triangle[1][0], triangle[1][1], triangle[1][2])
glVertex3f(triangle[1][0], triangle[1][1], triangle[1][2])
glVertex3f(triangle[2][0], triangle[2][1], triangle[2][2])
glVertex3f(triangle[2][0], triangle[2][1], triangle[2][2])
glVertex3f(triangle[0][0], triangle[0][1], triangle[0][2])
glEnd()
else:
glDisable( GL_DEPTH_TEST)
glEnable ( GL_BLEND )
glBegin(GL_POLYGON)
for clsPoint in self.clusterPoints:
glVertex3f(clsPoint.position[0], clsPoint.position[1], clsPoint.position[2])
glEnd()
glDisable ( GL_BLEND )
glEnable( GL_DEPTH_TEST)
glPopMatrix()
def update( self ):
points = []
for clsPoint in self.clusterPoints:
points += [clsPoint.position]
self.determineDimension(points)
if self.dimension == 2:
if len(self.clusterPoints) < 4:
self.hull = [points]
return
elif self.dimension == 3:
if len(self.clusterPoints) == 4:
self.hull = self.createTetrahedron(points)
return
elif len(self.clusterPoints) == 3:
self.hull = [points]
return
""" handle the creation of a hull for more than 3 points in 2D and more than 4 point in 3D. """
if self.dimension == 2:
points = self.convert3DTo2D(points)
triangulation = dcore.Triangulation(points, self.dimension)
if self.dimension == 2:
indexHull = self.createFaces(triangulation.get_elements_indices())
if self.dimension == 3:
indexHull = self.createHull(triangulation.get_elements_indices())
self.hull = []
for iHull in indexHull:
face = map(lambda x:points[x], iHull)
self.hull += [face]
if self.dimension == 2:
self.hull = self.convert2DTo3D(self.hull)
def getClusterPoints(self):
return self.clusterPoints
def createHull(self, tetraIndex):
faces = self.createFaces(tetraIndex)
faces.sort()
uniqueFaces = []
for face in faces:
if faces.count(face) == 1:
uniqueFaces += [face]
return uniqueFaces
def createFaces(self, tetrahedra):
faces = []
if self.dimension==2:
for face in tetrahedra:
if self.zeroIndex == 0:
faces += [[face[0], face[1], face[2]]]
elif self.zeroIndex == 1:
faces += [[face[0], face[1], face[2]]]
elif self.zeroIndex == 2:
faces += [[face[0], face[1], face[2]]]
elif self.dimension==3:
for tetrahedron in tetrahedra:
faces += [[tetrahedron[0], tetrahedron[1],tetrahedron[2]]]
faces += [[tetrahedron[1], tetrahedron[2],tetrahedron[3]]]
faces += [[tetrahedron[2], tetrahedron[3],tetrahedron[0]]]
faces += [[tetrahedron[3], tetrahedron[0],tetrahedron[1]]]
for face in faces:
face.sort()
return faces
def determineDimension(self, points):
pointsOfTwoDimensions = filter(lambda x:x[0] == 0.0, points)
if len(pointsOfTwoDimensions) == len(points):
self.dimension = 2
self.zeroIndex = 0
return
pointsOfTwoDimensions = filter(lambda x:x[1] == 0.0, points)
if len(pointsOfTwoDimensions) == len(points):
self.dimension = 2
self.zeroIndex = 1
return
pointsOfTwoDimensions = filter(lambda x:x[2] == 0.0, points)
if len(pointsOfTwoDimensions) == len(points):
self.dimension = 2
self.zeroIndex = 2
return
self.dimension = 3
def convert3DTo2D(self, points):
newDimension = []
if self.dimension == 2:
for point in points:
if self.zeroIndex == 0:
newDimension += [[point[1], point[2]]]
elif self.zeroIndex == 1:
newDimension += [[point[0], point[2]]]
elif self.zeroIndex == 2:
newDimension += [[point[0], point[1]]]
return newDimension
def convert2DTo3D(self, triangles):
newDimension = []
if self.dimension == 2:
index = 0
for triangle in triangles:
newDimension += [[]]
for point in triangle:
if self.zeroIndex == 0:
newDimension[index] += [[0.0, point[0], point[1]]]
elif self.zeroIndex == 1:
newDimension[index] += [[point[0], 0.0, point[1]]]
elif self.zeroIndex == 2:
newDimension[index] += [[point[0], point[1], 0.0]]
index += 1
return newDimension
def createTetrahedron(self, points):
hull = []
if len(points) == 4:
hull += [[points[0], points[1], points[2]]]
hull += [[points[0], points[1], points[3]]]
hull += [[points[0], points[2], points[3]]]
hull += [[points[1], points[2], points[3]]]
return hull