Major reorganization to only include the communication stack from Cura.

master
Gina Häußge 2012-12-31 13:18:54 +01:00
parent f12cc26fbb
commit a0cac835b5
404 changed files with 98 additions and 59145 deletions

View File

@ -1,89 +0,0 @@
#!/usr/bin/python
"""
This page is in the table of contents.
==Overview==
===Introduction===
Cura is a GPL tool chain to forge a gcode skein for a model. Based on Skeinforge.
The slicing code is the same as Skeinforge. But the UI has been revamped to be... sane.
"""
from __future__ import absolute_import
from optparse import OptionParser
from Cura.util import profile
__author__ = 'Daid'
__credits__ = """
David Braam (daid303@gmail.com)
Enrique Perez (perez_enrique@yahoo.com)
Adrian Bowyer <http://forums.reprap.org/profile.php?12,13>
Brendan Erwin <http://forums.reprap.org/profile.php?12,217>
Greenarrow <http://forums.reprap.org/profile.php?12,81>
Ian England <http://forums.reprap.org/profile.php?12,192>
John Gilmore <http://forums.reprap.org/profile.php?12,364>
Jonwise <http://forums.reprap.org/profile.php?12,716>
Kyle Corbitt <http://forums.reprap.org/profile.php?12,90>
Michael Duffin <http://forums.reprap.org/profile.php?12,930>
Marius Kintel <http://reprap.soup.io/>
Nophead <http://www.blogger.com/profile/12801535866788103677>
PJR <http://forums.reprap.org/profile.php?12,757>
Reece.Arnott <http://forums.reprap.org/profile.php?12,152>
Wade <http://forums.reprap.org/profile.php?12,489>
Xsainnz <http://forums.reprap.org/profile.php?12,563>
Zach Hoeken <http://blog.zachhoeken.com/>
Ilya Kulakov (kulakov.ilya@gmail.com)
Organizations:
Ultimaker <http://www.ultimaker.com>
Art of Illusion <http://www.artofillusion.org/>"""
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def main():
parser = OptionParser(usage="usage: %prog [options] <filename>.stl")
parser.add_option("-i", "--ini", action="store", type="string", dest="profileini",
help="Load settings from a profile ini file")
parser.add_option("-r", "--print", action="store", type="string", dest="printfile",
help="Open the printing interface, instead of the normal cura interface.")
parser.add_option("-p", "--profile", action="store", type="string", dest="profile",
help="Internal option, do not use!")
parser.add_option("-s", "--slice", action="store_true", dest="slice",
help="Slice the given files instead of opening them in Cura")
parser.add_option("-w", "--web", action="store_true", dest="webui",
help="Start the webui instead of the normal Cura UI")
parser.add_option("-d", "--debug", action="store_true", dest="debug",
help="Enable debug mode, currently only used by the webui")
parser.add_option("--web-host", action="store", type="string", default="0.0.0.0", dest="webHost",
help="Specify the host on which to bind the webui, defaults to 0.0.0.0 (all interfaces) if not set")
parser.add_option("--web-port", action="store", type="int", default=5000, dest="webPort",
help="Specify the port on which to bind the webui, defaults to 5000 if not set")
(options, args) = parser.parse_args()
if options.profile is not None:
profile.loadGlobalProfileFromString(options.profile)
if options.profileini is not None:
profile.loadGlobalProfile(options.profileini)
if options.printfile is not None:
from Cura.gui import printWindow
printWindow.startPrintInterface(options.printfile)
elif options.slice is not None:
from Cura.util import sliceRun
sliceRun.runSlice(args)
elif options.webui:
import Cura.webui as webapp
webapp.run(host=options.webHost, port=options.webPort, debug=options.debug)
else:
#Place any unused arguments as last file, so Cura starts with opening those files.
if len(args) > 0:
profile.putPreference('lastFile', ';'.join(args))
#Do not import anything from Cura.gui before this spot, as the above code also needs to run in pypy.
from Cura.gui import app
app.CuraApp().MainLoop()
if __name__ == '__main__':
main()

View File

@ -1,2 +0,0 @@
This SkeinPyPy version is based in Skeinforge: 50

View File

@ -1,405 +0,0 @@
"""
Boolean geometry utilities.
"""
from __future__ import absolute_import
import os
import sys
import traceback
import zipfile
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalTemporarySettingsPath = os.path.join(os.path.expanduser('~'), '.skeinforge_pypy')
def addToNamePathDictionary(directoryPath, namePathDictionary):
'Add to the name path dictionary.'
pluginFileNames = getPluginFileNamesFromDirectoryPath(directoryPath)
for pluginFileName in pluginFileNames:
namePathDictionary[pluginFileName.replace('_', '')] = os.path.join(directoryPath, pluginFileName)
def getAbsoluteFolderPath(filePath, folderName=''):
'Get the absolute folder path.'
absoluteFolderPath = os.path.dirname(os.path.abspath(filePath))
if folderName == '':
return absoluteFolderPath
return os.path.join(absoluteFolderPath, folderName)
def getAbsoluteFrozenFolderPath(filePath, folderName=''):
'Get the absolute frozen folder path.'
if hasattr(sys, 'frozen'):
if '.py' in filePath:
filePath = ''.join(filePath.rpartition('\\')[: 2])
filePath = os.path.join(filePath, 'skeinforge_application')
return getAbsoluteFolderPath(filePath, folderName)
def getAnalyzePluginsDirectoryPath(subName=''):
'Get the analyze plugins directory path.'
return getJoinedPath(getSkeinforgePluginsPath('analyze_plugins'), subName)
def getCraftPluginsDirectoryPath(subName=''):
'Get the craft plugins directory path.'
return getJoinedPath(getSkeinforgePluginsPath('craft_plugins'), subName)
def getDocumentationPath(subName=''):
'Get the documentation file path.'
return getJoinedPath(getFabmetheusPath('documentation'), subName)
def getElementsPath(subName=''):
'Get the evaluate_elements directory path.'
return getJoinedPath(getGeometryUtilitiesPath('evaluate_elements'), subName)
def getEndsWithList(word, wordEndings):
'Determine if the word ends with a list.'
for wordEnding in wordEndings:
if word.endswith(wordEnding):
return True
return False
def getFabmetheusPath(subName=''):
'Get the fabmetheus directory path.'
fabmetheusFile = None
if hasattr(sys, 'frozen'):
fabmetheusFile = unicode(sys.executable, sys.getfilesystemencoding())
else:
fabmetheusFile = os.path.dirname(os.path.abspath(__file__))
return getJoinedPath(os.path.dirname(fabmetheusFile), subName)
def getFabmetheusToolsPath(subName=''):
'Get the fabmetheus tools directory path.'
return getJoinedPath(getFabmetheusUtilitiesPath('fabmetheus_tools'), subName)
def getFabmetheusUtilitiesPath(subName=''):
'Get the fabmetheus utilities directory path.'
return getJoinedPath(getFabmetheusPath('fabmetheus_utilities'), subName)
def getFileNamesByFilePaths(pluginFilePaths):
'Get the file names of the plugins by the file paths.'
fileNames = []
for pluginFilePath in pluginFilePaths:
pluginBasename = os.path.basename(pluginFilePath)
pluginBasename = getUntilDot(pluginBasename)
fileNames.append(pluginBasename)
return fileNames
def getFilePaths(fileInDirectory=''):
'Get the file paths in the directory of the file in directory.'
directoryName = os.getcwd()
if fileInDirectory != '':
directoryName = os.path.dirname(fileInDirectory)
return getFilePathsByDirectory(directoryName)
def getFilePathsByDirectory(directoryName):
'Get the file paths in the directory of the file in directory.'
absoluteDirectoryPath = os.path.abspath(directoryName)
filePaths = []
if os.path.isdir(directoryName):
for fileName in os.listdir(directoryName):
filePaths.append(os.path.join(absoluteDirectoryPath, fileName))
elif '.zip/' in directoryName:
zipfilename = directoryName[:directoryName.rfind('.zip/')+4]
subpath = directoryName[directoryName.rfind('.zip/')+5:]
z = zipfile.ZipFile(zipfilename, 'r')
for name in z.namelist():
if os.path.dirname(name) == subpath:
filePaths.append(os.path.join(zipfilename, name))
z.close()
print(directoryName, filePaths)
return filePaths
def getFilePathsRecursively(fileInDirectory=''):
'Get the file paths in the directory of the file in directory.'
filePaths = getFilePaths(fileInDirectory)
filePathsRecursively = filePaths[:]
for filePath in filePaths:
if os.path.isdir(filePath):
directory = os.listdir(filePath)
if len(directory) > 0:
filePathsRecursively += getFilePathsRecursively(os.path.join(filePath, directory[0]))
return filePathsRecursively
def getFilePathWithUnderscoredBasename(fileName, suffix):
'Get the file path with all spaces in the basename replaced with underscores.'
suffixFileName = getUntilDot(fileName) + suffix
suffixDirectoryName = os.path.dirname(suffixFileName)
suffixReplacedBaseName = os.path.basename(suffixFileName).replace(' ', '_')
return os.path.join(suffixDirectoryName, suffixReplacedBaseName)
def getFilesWithFileTypesWithoutWords(fileTypes, words = [], fileInDirectory=''):
'Get files which have a given file type, but with do not contain a word in a list.'
filesWithFileTypes = []
for filePath in getFilePaths(fileInDirectory):
for fileType in fileTypes:
if isFileWithFileTypeWithoutWords(fileType, filePath, words):
filesWithFileTypes.append(filePath)
filesWithFileTypes.sort()
return filesWithFileTypes
def getFilesWithFileTypesWithoutWordsRecursively(fileTypes, words = [], fileInDirectory=''):
'Get files recursively which have a given file type, but with do not contain a word in a list.'
filesWithFileTypesRecursively = []
for filePath in getFilePathsRecursively(fileInDirectory):
for fileType in fileTypes:
if isFileWithFileTypeWithoutWords(fileType, filePath, words):
filesWithFileTypesRecursively.append(filePath)
filesWithFileTypesRecursively.sort()
return filesWithFileTypesRecursively
def getFilesWithFileTypeWithoutWords(fileType, words = [], fileInDirectory=''):
'Get files which have a given file type, but with do not contain a word in a list.'
filesWithFileType = []
for filePath in getFilePaths(fileInDirectory):
if isFileWithFileTypeWithoutWords(fileType, filePath, words):
filesWithFileType.append(filePath)
filesWithFileType.sort()
return filesWithFileType
def getFileText(fileName, printWarning=True, readMode='r'):
'Get the entire text of a file.'
if '.zip/' in fileName:
zipfilename = fileName[:fileName.rfind('.zip/')+4]
subpath = fileName[fileName.rfind('.zip/')+5:]
try:
z = zipfile.ZipFile(zipfilename, 'r')
f = z.open(subpath, 'r')
fileText = f.read()
f.close()
z.close()
return fileText
except KeyError:
if printWarning:
print('The file ' + fileName + ' does not exist.')
return ''
try:
f = open(fileName, readMode)
fileText = f.read()
f.close()
return fileText
except IOError:
if printWarning:
print('The file ' + fileName + ' does not exist.')
return ''
def getFileTextInFileDirectory(fileInDirectory, fileName, readMode='r'):
'Get the entire text of a file in the directory of the file in directory.'
absoluteFilePathInFileDirectory = os.path.join(os.path.dirname(fileInDirectory), fileName)
return getFileText(absoluteFilePathInFileDirectory, True, readMode)
def getFundamentalsPath(subName=''):
'Get the evaluate_fundamentals directory path.'
return getJoinedPath(getGeometryUtilitiesPath('evaluate_fundamentals'), subName)
def getGeometryDictionary(folderName):
'Get to the geometry name path dictionary.'
geometryDictionary={}
geometryDirectory = getGeometryPath()
addToNamePathDictionary(os.path.join(geometryDirectory, folderName), geometryDictionary)
geometryPluginsDirectory = getFabmetheusUtilitiesPath('geometry_plugins')
addToNamePathDictionary(os.path.join(geometryPluginsDirectory, folderName), geometryDictionary)
return geometryDictionary
def getGeometryPath(subName=''):
'Get the geometry directory path.'
return getJoinedPath(getFabmetheusUtilitiesPath('geometry'), subName)
def getGeometryToolsPath(subName=''):
'Get the geometry tools directory path.'
return getJoinedPath(getGeometryPath('geometry_tools'), subName)
def getGeometryUtilitiesPath(subName=''):
'Get the geometry_utilities directory path.'
return getJoinedPath(getGeometryPath('geometry_utilities'), subName)
def getInterpretPluginsPath(subName=''):
'Get the interpret plugins directory path.'
return getJoinedPath(getFabmetheusToolsPath('interpret_plugins'), subName)
def getJoinedPath(path, subName=''):
'Get the joined file path.'
if subName == '':
return path
return os.path.join(path, subName)
def getModuleWithDirectoryPath(directoryPath, fileName):
'Get the module from the fileName and folder name.'
if fileName == '':
print('The file name in getModule in archive was empty.')
return None
originalSystemPath = sys.path[:]
try:
sys.path.insert(0, directoryPath)
folderPluginsModule = __import__(fileName)
sys.path = originalSystemPath
return folderPluginsModule
except:
sys.path = originalSystemPath
print('')
print('Exception traceback in getModuleWithDirectoryPath in archive:')
traceback.print_exc(file=sys.stdout)
print('')
print('That error means; could not import a module with the fileName ' + fileName)
print('and an absolute directory name of ' + directoryPath)
print('')
return None
def getModuleWithPath(path):
'Get the module from the path.'
return getModuleWithDirectoryPath(os.path.dirname(path), os.path.basename(path))
def getPluginFileNamesFromDirectoryPath(directoryPath):
'Get the file names of the python plugins in the directory path.'
fileInDirectory = os.path.join(directoryPath, '__init__.py')
return getFileNamesByFilePaths(getPythonFileNamesExceptInit(fileInDirectory))
def getProfilesPath(subName=''):
'Get the profiles directory path, which is the settings directory joined with profiles.'
return getJoinedPath(getSettingsPath('profiles'), subName)
def getPythonDirectoryNames(directoryName):
'Get the python directories.'
pythonDirectoryNames = []
directory = os.listdir(directoryName)
for fileName in directory:
subdirectoryName = os.path.join(directoryName, fileName)
if os.path.isdir(subdirectoryName):
if os.path.isfile(os.path.join(subdirectoryName, '__init__.py')):
pythonDirectoryNames.append(subdirectoryName)
return pythonDirectoryNames
def getPythonDirectoryNamesRecursively(directoryName=''):
'Get the python directories recursively.'
recursivePythonDirectoryNames = []
if directoryName == '':
directoryName = os.getcwd()
if os.path.isfile(os.path.join(directoryName, '__init__.py')):
recursivePythonDirectoryNames.append(directoryName)
pythonDirectoryNames = getPythonDirectoryNames(directoryName)
for pythonDirectoryName in pythonDirectoryNames:
recursivePythonDirectoryNames += getPythonDirectoryNamesRecursively(pythonDirectoryName)
else:
return []
return recursivePythonDirectoryNames
def getPythonFileNamesExceptInit(fileInDirectory=''):
'Get the python fileNames of the directory which the fileInDirectory is in, except for the __init__.py file.'
pythonFileNamesExceptInit = getFilesWithFileTypeWithoutWords('py', ['__init__.py'], fileInDirectory)
pythonFileNamesExceptInit.sort()
return pythonFileNamesExceptInit
def getPythonFileNamesExceptInitRecursively(directoryName=''):
'Get the python fileNames of the directory recursively, except for the __init__.py files.'
pythonDirectoryNames = getPythonDirectoryNamesRecursively(directoryName)
pythonFileNamesExceptInitRecursively = []
for pythonDirectoryName in pythonDirectoryNames:
pythonFileNamesExceptInitRecursively += getPythonFileNamesExceptInit(os.path.join(pythonDirectoryName, '__init__.py'))
pythonFileNamesExceptInitRecursively.sort()
return pythonFileNamesExceptInitRecursively
def getSettingsPath(subName=''):
'Get the settings directory path, which is the home directory joined with .skeinforge.'
global globalTemporarySettingsPath
return getJoinedPath(globalTemporarySettingsPath, subName)
def getSkeinforgePath(subName=''):
'Get the skeinforge directory path.'
return getJoinedPath(getFabmetheusPath('skeinforge_application'), subName)
def getSkeinforgePluginsPath(subName=''):
'Get the skeinforge plugins directory path.'
return getJoinedPath(getSkeinforgePath('skeinforge_plugins'), subName)
def getSummarizedFileName(fileName):
'Get the fileName basename if the file is in the current working directory, otherwise return the original full name.'
if os.getcwd() == os.path.dirname(fileName):
return os.path.basename(fileName)
return fileName
def getTemplatesPath(subName=''):
'Get the templates directory path.'
return getJoinedPath(getFabmetheusUtilitiesPath('templates'), subName)
def getTextIfEmpty(fileName, text):
'Get the text from a file if it the text is empty.'
if text != '':
return text
return getFileText(fileName)
def getTextLines(text):
'Get the all the lines of text of a text.'
if '\r' in text:
text = text.replace('\r', '\n').replace('\n\n', '\n')
textLines = text.split('\n')
if len(textLines) == 1:
if textLines[0] == '':
return []
return textLines
def getUntilDot(text):
'Get the text until the last dot, if any.'
dotIndex = text.rfind('.')
if dotIndex < 0:
return text
return text[: dotIndex]
def getVersionFileName():
'Get the file name of the version date.getFabmetheusUtilitiesPath(subName='')'
return getFabmetheusUtilitiesPath('version.txt')
def isFileWithFileTypeWithoutWords(fileType, fileName, words):
'Determine if file has a given file type, but with does not contain a word in a list.'
fileName = os.path.basename(fileName)
fileTypeDot = '.' + fileType
if not fileName.endswith(fileTypeDot):
return False
for word in words:
if fileName.find(word) >= 0:
return False
return True
def makeDirectory(directoryPath):
'Make a directory if it does not already exist.'
if os.path.isdir(directoryPath):
return
try:
print('The following directory was made:')
print(os.path.abspath(directoryPath))
os.makedirs(directoryPath)
except OSError:
print('Skeinforge can not make the directory %s so give it read/write permission for that directory and the containing directory.' % directoryPath)
def removeBackupFilesByType(fileType):
'Remove backup files by type.'
backupFilePaths = getFilesWithFileTypesWithoutWordsRecursively([fileType + '~'])
for backupFilePath in backupFilePaths:
os.remove(backupFilePath)
def removeBackupFilesByTypes(fileTypes):
'Remove backup files by types.'
for fileType in fileTypes:
removeBackupFilesByType(fileType)
def writeFileMessageEnd(end, fileName, fileText, message):
'Write to a fileName with a suffix and print a message.'
suffixFileName = getUntilDot(fileName) + end
writeFileText(suffixFileName, fileText)
print(message + getSummarizedFileName(suffixFileName))
def writeFileText(fileName, fileText, writeMode='w+'):
'Write a text to a file.'
try:
file = open(fileName, writeMode)
file.write(fileText)
file.close()
except IOError:
print('The file ' + fileName + ' can not be written to.')

File diff suppressed because it is too large Load Diff

View File

@ -1,129 +0,0 @@
"""
Fabmetheus interpret is a fabmetheus utility to interpret a file, turning it into fabmetheus constructive solid geometry xml.
"""
from __future__ import absolute_import
from fabmetheus_utilities import archive
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import settings
from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
from skeinforge_application.skeinforge_utilities import skeinforge_profile
import os
import time
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getCarving(fileName):
"Get carving."
pluginModule = getInterpretPlugin(fileName)
if pluginModule == None:
return None
return pluginModule.getCarving(fileName)
def getGNUTranslatorFilesUnmodified():
"Get the file types from the translators in the import plugins folder."
return archive.getFilesWithFileTypesWithoutWords(getImportPluginFileNames())
def getGNUTranslatorGcodeFileTypeTuples():
"Get the file type tuples from the translators in the import plugins folder plus gcode."
fileTypeTuples = [] #getTranslatorFileTypeTuples()
fileTypeTuples.append( ('Gcode text files', '*.gcode') )
fileTypeTuples.sort()
return fileTypeTuples
def getImportPluginFileNames():
"Get interpret plugin fileNames."
return archive.getPluginFileNamesFromDirectoryPath( getPluginsDirectoryPath() )
def getInterpretPlugin(fileName):
"Get the interpret plugin for the file."
importPluginFileNames = getImportPluginFileNames()
for importPluginFileName in importPluginFileNames:
fileTypeDot = '.' + importPluginFileName
if fileName[ - len(fileTypeDot) : ].lower() == fileTypeDot:
importPluginsDirectoryPath = getPluginsDirectoryPath()
pluginModule = archive.getModuleWithDirectoryPath( importPluginsDirectoryPath, importPluginFileName )
if pluginModule != None:
return pluginModule
print('Could not find plugin to handle ' + fileName )
return None
def getNewRepository():
'Get new repository.'
return InterpretRepository()
def getPluginsDirectoryPath():
"Get the plugins directory path."
return archive.getInterpretPluginsPath()
def getTranslatorFileTypeTuples():
"Get the file types from the translators in the import plugins folder."
importPluginFileNames = getImportPluginFileNames()
fileTypeTuples = []
for importPluginFileName in importPluginFileNames:
fileTypeTitle = importPluginFileName.upper() + ' files'
fileType = ( fileTypeTitle, '*.' + importPluginFileName )
fileTypeTuples.append( fileType )
fileTypeTuples.sort()
return fileTypeTuples
def getWindowAnalyzeFile(fileName):
"Get file interpretion."
startTime = time.time()
carving = getCarving(fileName)
if carving == None:
return None
interpretGcode = str( carving )
if interpretGcode == '':
return None
repository = settings.getReadRepository( InterpretRepository() )
if repository.printInterpretion.value:
print(interpretGcode)
suffixFileName = fileName[ : fileName.rfind('.') ] + '_interpret.' + carving.getInterpretationSuffix()
suffixDirectoryName = os.path.dirname(suffixFileName)
suffixReplacedBaseName = os.path.basename(suffixFileName).replace(' ', '_')
suffixFileName = os.path.join( suffixDirectoryName, suffixReplacedBaseName )
archive.writeFileText( suffixFileName, interpretGcode )
print('The interpret file is saved as ' + archive.getSummarizedFileName(suffixFileName) )
print('It took %s to interpret the file.' % euclidean.getDurationString( time.time() - startTime ) )
textProgram = repository.textProgram.value
if textProgram == '':
return None
if textProgram == 'webbrowser':
settings.openWebPage(suffixFileName)
return None
textFilePath = '"' + os.path.normpath(suffixFileName) + '"' # " to send in file name with spaces
shellCommand = textProgram + ' ' + textFilePath
print('Sending the shell command:')
print(shellCommand)
commandResult = os.system(shellCommand)
if commandResult != 0:
print('It may be that the system could not find the %s program.' % textProgram )
print('If so, try installing the %s program or look for another one, like Open Office which can be found at:' % textProgram )
print('http://www.openoffice.org/')
print('Open office writer can then be started from the command line with the command "soffice -writer".')
class InterpretRepository(object):
"A class to handle the interpret settings."
def __init__(self):
"Set the default settings, execute title & settings fileName."
skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.analyze_plugins.interpret.html', self)
self.fileNameInput = settings.FileNameInput().getFromFileName( getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Interpret', self, '')
self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Interpret')
self.activateInterpret = settings.BooleanSetting().getFromValue('Activate Interpret', self, False )
self.printInterpretion = settings.BooleanSetting().getFromValue('Print Interpretion', self, False )
self.textProgram = settings.StringSetting().getFromValue('Text Program:', self, 'webbrowser')
self.executeTitle = 'Interpret'
def execute(self):
"Write button has been clicked."
fileNames = skeinforge_polyfile.getFileOrGcodeDirectory( self.fileNameInput.value, self.fileNameInput.wasCancelled )
for fileName in fileNames:
getWindowAnalyzeFile(fileName)

View File

@ -1,156 +0,0 @@
"""
This page is in the table of contents.
The csv.py script is an import translator plugin to get a carving from an csv file.
An import plugin is a script in the interpret_plugins folder which has the function getCarving. It is meant to be run from the interpret tool. To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
The getCarving function takes the file name of an csv file and returns the carving.
"""
from __future__ import absolute_import
from fabmetheus_utilities import archive
from fabmetheus_utilities import xml_simple_reader
import sys
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getCarving(fileName=''):
"Get the carving for the csv file."
csvText = archive.getFileText(fileName)
if csvText == '':
return None
csvParser = CSVSimpleParser( fileName, None, csvText )
lowerLocalName = csvParser.getDocumentElement().getNodeName().lower()
pluginModule = archive.getModuleWithDirectoryPath( getPluginsDirectoryPath(), lowerLocalName )
if pluginModule == None:
return None
return pluginModule.getCarvingFromParser( csvParser )
def getLineDictionary(line):
"Get the line dictionary."
lineDictionary = {}
splitLine = line.split('\t')
for splitLineIndex in xrange( len(splitLine) ):
word = splitLine[ splitLineIndex ]
if word != '':
lineDictionary[ splitLineIndex ] = word
return lineDictionary
def getPluginsDirectoryPath():
"Get the plugins directory path."
return archive.getInterpretPluginsPath('xml_plugins')
class CSVElement( xml_simple_reader.XMLElement ):
"A csv element."
def continueParsingObject( self, line, lineStripped ):
"Parse replaced line."
splitLineStripped = lineStripped.split('\t')
key = splitLineStripped[0]
value = splitLineStripped[1]
self.attributes[key] = value
self.addToIdentifierDictionaries()
def continueParsingTable( self, line, lineStripped ):
"Parse replaced line."
if self.headingDictionary == None:
self.headingDictionary = getLineDictionary(line)
return
csvElement = self
oldAttributesLength = len( self.attributes )
if oldAttributesLength > 0:
csvElement = CSVElement()
csvElement.parentNode = self.parentNode
csvElement.localName = self.localName
lineDictionary = getLineDictionary(line)
for columnIndex in lineDictionary.keys():
if columnIndex in self.headingDictionary:
key = self.headingDictionary[ columnIndex ]
value = lineDictionary[ columnIndex ]
csvElement.attributes[key] = value
csvElement.addToIdentifierDictionaries()
if len( csvElement.attributes ) == 0 or oldAttributesLength == 0 or self.parentNode == None:
return
self.parentNode.childNodes.append( csvElement )
def getElementFromObject( self, leadingTabCount, lineStripped, oldElement ):
"Parse replaced line."
splitLine = lineStripped.split('\t')
self.localName = splitLine[1]
if leadingTabCount == 0:
return self
self.parentNode = oldElement
while leadingTabCount <= self.parentNode.getNumberOfParents():
self.parentNode = self.parentNode.parentNode
self.parentNode.childNodes.append(self)
return self
def getElementFromTable( self, leadingTabCount, lineStripped, oldElement ):
"Parse replaced line."
self.headingDictionary = None
return self.getElementFromObject( leadingTabCount, lineStripped, oldElement )
def getNumberOfParents(self):
"Get the number of parent nodes."
if self.parentNode == None:
return 0
return self.parentNode.getNumberOfParents() + 1
class CSVSimpleParser( xml_simple_reader.DocumentNode ):
"A simple csv parser."
def __init__( self, parentNode, csvText ):
"Add empty lists."
self.continueFunction = None
self.extraLeadingTabCount = None
self.lines = archive.getTextLines( csvText )
self.oldCSVElement = None
self.documentElement = None
for line in self.lines:
self.parseLine(line)
def getNewCSVElement( self, leadingTabCount, lineStripped ):
"Get a new csv element."
if self.documentElement != None and self.extraLeadingTabCount == None:
self.extraLeadingTabCount = 1 - leadingTabCount
if self.extraLeadingTabCount != None:
leadingTabCount += self.extraLeadingTabCount
if lineStripped[ : len('_table') ] == '_table' or lineStripped[ : len('_t') ] == '_t':
self.oldCSVElement = CSVElement().getElementFromTable( leadingTabCount, lineStripped, self.oldCSVElement )
self.continueFunction = self.oldCSVElement.continueParsingTable
return
self.oldCSVElement = CSVElement().getElementFromObject( leadingTabCount, lineStripped, self.oldCSVElement )
self.continueFunction = self.oldCSVElement.continueParsingObject
def parseLine(self, line):
"Parse a gcode line and add it to the inset skein."
lineStripped = line.lstrip()
if len( lineStripped ) < 1:
return
leadingPart = line[ : line.find( lineStripped ) ]
leadingTabCount = leadingPart.count('\t')
if lineStripped[ : len('_') ] == '_':
self.getNewCSVElement( leadingTabCount, lineStripped )
if self.documentElement == None:
self.documentElement = self.oldCSVElement
self.documentElement.document = self
return
if self.continueFunction != None:
self.continueFunction( line, lineStripped )
def main():
"Display the inset dialog."
if len(sys.argv) > 1:
getCarving(' '.join(sys.argv[1 :]))
if __name__ == "__main__":
main()

View File

@ -1,134 +0,0 @@
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_tools import face
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
from xml.parsers.expat import ParserCreate
def getCarving(fileName=''):
"Get the triangle mesh for the dae file."
return daeModel().load(fileName)
class daeModel(triangle_mesh.TriangleMesh):
def __init__(self):
triangle_mesh.TriangleMesh.__init__(self)
def load(self, filename):
r = ParserCreate()
r.StartElementHandler = self._StartElementHandler
r.EndElementHandler = self._EndElementHandler
r.CharacterDataHandler = self._CharacterDataHandler
self._base = {}
self._cur = self._base
self._idMap = {}
self._geometryList = []
r.ParseFile(open(filename, "r"))
self._scale = float(self._base['collada'][0]['asset'][0]['unit'][0]['_meter']) * 1000
for instance_visual_scene in self._base['collada'][0]['scene'][0]['instance_visual_scene']:
for node in self._idMap[instance_visual_scene['_url']]['node']:
self._ProcessNode2(node)
self._base = None
self._cur = None
self._idMap = None
return self
def _ProcessNode2(self, node, matrix = None):
if 'matrix' in node:
oldMatrix = matrix
matrix = map(float, node['matrix'][0]['__data'].split())
if oldMatrix != None:
newMatrix = [0]*16
newMatrix[0] = oldMatrix[0] * matrix[0] + oldMatrix[1] * matrix[4] + oldMatrix[2] * matrix[8] + oldMatrix[3] * matrix[12]
newMatrix[1] = oldMatrix[0] * matrix[1] + oldMatrix[1] * matrix[5] + oldMatrix[2] * matrix[9] + oldMatrix[3] * matrix[13]
newMatrix[2] = oldMatrix[0] * matrix[2] + oldMatrix[1] * matrix[6] + oldMatrix[2] * matrix[10] + oldMatrix[3] * matrix[14]
newMatrix[3] = oldMatrix[0] * matrix[3] + oldMatrix[1] * matrix[7] + oldMatrix[2] * matrix[11] + oldMatrix[3] * matrix[15]
newMatrix[4] = oldMatrix[4] * matrix[0] + oldMatrix[5] * matrix[4] + oldMatrix[6] * matrix[8] + oldMatrix[7] * matrix[12]
newMatrix[5] = oldMatrix[4] * matrix[1] + oldMatrix[5] * matrix[5] + oldMatrix[6] * matrix[9] + oldMatrix[7] * matrix[13]
newMatrix[6] = oldMatrix[4] * matrix[2] + oldMatrix[5] * matrix[6] + oldMatrix[6] * matrix[10] + oldMatrix[7] * matrix[14]
newMatrix[7] = oldMatrix[4] * matrix[3] + oldMatrix[5] * matrix[7] + oldMatrix[6] * matrix[11] + oldMatrix[7] * matrix[15]
newMatrix[8] = oldMatrix[8] * matrix[0] + oldMatrix[9] * matrix[4] + oldMatrix[10] * matrix[8] + oldMatrix[11] * matrix[12]
newMatrix[9] = oldMatrix[8] * matrix[1] + oldMatrix[9] * matrix[5] + oldMatrix[10] * matrix[9] + oldMatrix[11] * matrix[13]
newMatrix[10] = oldMatrix[8] * matrix[2] + oldMatrix[9] * matrix[6] + oldMatrix[10] * matrix[10] + oldMatrix[11] * matrix[14]
newMatrix[11] = oldMatrix[8] * matrix[3] + oldMatrix[9] * matrix[7] + oldMatrix[10] * matrix[11] + oldMatrix[11] * matrix[15]
newMatrix[12] = oldMatrix[12] * matrix[0] + oldMatrix[13] * matrix[4] + oldMatrix[14] * matrix[8] + oldMatrix[15] * matrix[12]
newMatrix[13] = oldMatrix[12] * matrix[1] + oldMatrix[13] * matrix[5] + oldMatrix[14] * matrix[9] + oldMatrix[15] * matrix[13]
newMatrix[14] = oldMatrix[12] * matrix[2] + oldMatrix[13] * matrix[6] + oldMatrix[14] * matrix[10] + oldMatrix[15] * matrix[14]
newMatrix[15] = oldMatrix[12] * matrix[3] + oldMatrix[13] * matrix[7] + oldMatrix[14] * matrix[11] + oldMatrix[15] * matrix[15]
matrix = newMatrix
if 'node' in node:
for n in node['node']:
self._ProcessNode2(n, matrix)
if 'instance_geometry' in node:
for instance_geometry in node['instance_geometry']:
mesh = self._idMap[instance_geometry['_url']]['mesh'][0]
if 'triangles' in mesh:
for triangles in mesh['triangles']:
for input in triangles['input']:
if input['_semantic'] == 'VERTEX':
vertices = self._idMap[input['_source']]
for input in vertices['input']:
if input['_semantic'] == 'POSITION':
vertices = self._idMap[input['_source']]
indexList = map(int, triangles['p'][0]['__data'].split())
positionList = map(float, vertices['float_array'][0]['__data'].split())
startIndex = len(self.vertexes)
for idx in xrange(0, len(positionList)/3):
x = positionList[idx*3] * self._scale
y = positionList[idx*3+1] * self._scale
z = positionList[idx*3+2] * self._scale
if matrix != None:
self.vertexes.append(Vector3(x * matrix[0] + y * matrix[1] + z * matrix[2] + matrix[3], x * matrix[4] + y * matrix[5] + z * matrix[6] + matrix[7], x * matrix[8] + y * matrix[9] + z * matrix[10] + matrix[11]))
else:
self.vertexes.append(Vector3(x, y, z))
stepSize = len(indexList) / (int(triangles['_count']) * 3)
for i in xrange(0, int(triangles['_count'])):
idx = i * stepSize * 3
f = face.Face()
f.index = len(self.faces)
f.vertexIndexes.append(startIndex + indexList[idx])
f.vertexIndexes.append(startIndex + indexList[idx+stepSize])
f.vertexIndexes.append(startIndex + indexList[idx+stepSize*2])
self.faces.append(f)
if 'instance_node' in node:
for instance_node in node['instance_node']:
self._ProcessNode2(self._idMap[instance_node['_url']], matrix)
def _StartElementHandler(self, name, attributes):
name = name.lower()
if not name in self._cur:
self._cur[name] = []
new = {'__name': name, '__parent': self._cur}
self._cur[name].append(new)
self._cur = new
for k in attributes.keys():
self._cur['_' + k] = attributes[k]
if 'id' in attributes:
self._idMap['#' + attributes['id']] = self._cur
def _EndElementHandler(self, name):
self._cur = self._cur['__parent']
def _CharacterDataHandler(self, data):
if len(data.strip()) < 1:
return
if '__data' in self._cur:
self._cur['__data'] += data
else:
self._cur['__data'] = data
def _GetWithKey(self, item, basename, key, value):
input = basename
while input in item:
if item[basename]['_'+key] == value:
return self._idMap[item[input]['_source']]
basename += "!"

View File

@ -1,77 +0,0 @@
"""
This page is in the table of contents.
The gts.py script is an import translator plugin to get a carving from an gts file.
An import plugin is a script in the interpret_plugins folder which has the function getCarving. It is meant to be run from the interpret tool. To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
The getCarving function takes the file name of an gts file and returns the carving.
The GNU Triangulated Surface (.gts) format is described at:
http://gts.sourceforge.net/reference/gts-surfaces.html#GTS-SURFACE-WRITE
Quoted from http://gts.sourceforge.net/reference/gts-surfaces.html#GTS-SURFACE-WRITE
"All the lines beginning with GTS_COMMENTS (#!) are ignored. The first line contains three unsigned integers separated by spaces. The first integer is the number of vertexes, nv, the second is the number of edges, ne and the third is the number of faces, nf.
Follows nv lines containing the x, y and z coordinates of the vertexes. Follows ne lines containing the two indices (starting from one) of the vertexes of each edge. Follows nf lines containing the three ordered indices (also starting from one) of the edges of each face.
The format described above is the least common denominator to all GTS files. Consistent with an object-oriented approach, the GTS file format is extensible. Each of the lines of the file can be extended with user-specific attributes accessible through the read() and write() virtual methods of each of the objects written (surface, vertexes, edges or faces). When read with different object classes, these extra attributes are just ignored."
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_tools import face
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import archive
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getCarving(fileName):
"Get the carving for the gts file."
return getFromGNUTriangulatedSurfaceText( archive.getFileText(fileName), triangle_mesh.TriangleMesh() )
def getFromGNUTriangulatedSurfaceText( gnuTriangulatedSurfaceText, triangleMesh ):
"Initialize from a GNU Triangulated Surface Text."
if gnuTriangulatedSurfaceText == '':
return None
lines = archive.getTextLines( gnuTriangulatedSurfaceText )
linesWithoutComments = []
for line in lines:
if len(line) > 0:
firstCharacter = line[0]
if firstCharacter != '#' and firstCharacter != '!':
linesWithoutComments.append(line)
splitLine = linesWithoutComments[0].split()
numberOfVertexes = int( splitLine[0] )
numberOfEdges = int(splitLine[1])
numberOfFaces = int( splitLine[2] )
faceTriples = []
for vertexIndex in xrange( numberOfVertexes ):
line = linesWithoutComments[ vertexIndex + 1 ]
splitLine = line.split()
vertex = Vector3( float( splitLine[0] ), float(splitLine[1]), float( splitLine[2] ) )
triangleMesh.vertexes.append(vertex)
edgeStart = numberOfVertexes + 1
for edgeIndex in xrange( numberOfEdges ):
line = linesWithoutComments[ edgeIndex + edgeStart ]
splitLine = line.split()
vertexIndexes = []
for word in splitLine[ : 2 ]:
vertexIndexes.append( int(word) - 1 )
edge = face.Edge().getFromVertexIndexes( edgeIndex, vertexIndexes )
triangleMesh.edges.append( edge )
faceStart = edgeStart + numberOfEdges
for faceIndex in xrange( numberOfFaces ):
line = linesWithoutComments[ faceIndex + faceStart ]
splitLine = line.split()
edgeIndexes = []
for word in splitLine[ : 3 ]:
edgeIndexes.append( int(word) - 1 )
triangleMesh.faces.append( face.Face().getFromEdgeIndexes( edgeIndexes, triangleMesh.edges, faceIndex ) )
return triangleMesh

View File

@ -1,75 +0,0 @@
"""
This page is in the table of contents.
The obj.py script is an import translator plugin to get a carving from an obj file.
An example obj file is box.obj in the models folder.
An import plugin is a script in the interpret_plugins folder which has the function getCarving. It is meant to be run from the interpret tool. To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
The getCarving function takes the file name of an obj file and returns the carving.
From wikipedia, OBJ (or .OBJ) is a geometry definition file format first developed by Wavefront Technologies for its Advanced Visualizer animation package:
http://en.wikipedia.org/wiki/Obj
The Object File specification is at:
http://local.wasp.uwa.edu.au/~pbourke/dataformats/obj/
An excellent link page about obj files is at:
http://people.sc.fsu.edu/~burkardt/data/obj/obj.html
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_tools import face
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import archive
from fabmetheus_utilities import gcodec
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addFacesGivenText( objText, triangleMesh ):
"Add faces given obj text."
lines = archive.getTextLines( objText )
for line in lines:
splitLine = line.split()
firstWord = gcodec.getFirstWord(splitLine)
if firstWord == 'v':
triangleMesh.vertexes.append( getVertexGivenLine(line) )
elif firstWord == 'f':
triangleMesh.faces.append( getFaceGivenLine( line, triangleMesh ) )
def getCarving(fileName=''):
"Get the triangle mesh for the obj file."
if fileName == '':
return None
objText = archive.getFileText(fileName, True, 'rb')
if objText == '':
return None
triangleMesh = triangle_mesh.TriangleMesh()
addFacesGivenText(objText, triangleMesh)
return triangleMesh
def getFaceGivenLine( line, triangleMesh ):
"Add face given line index and lines."
faceGivenLine = face.Face()
faceGivenLine.index = len( triangleMesh.faces )
splitLine = line.split()
for vertexStringIndex in xrange( 1, 4 ):
vertexString = splitLine[ vertexStringIndex ]
vertexStringWithSpaces = vertexString.replace('/', ' ')
vertexStringSplit = vertexStringWithSpaces.split()
vertexIndex = int( vertexStringSplit[0] ) - 1
faceGivenLine.vertexIndexes.append(vertexIndex)
return faceGivenLine
def getVertexGivenLine(line):
"Get vertex given obj vertex line."
splitLine = line.split()
return Vector3( float(splitLine[1]), float( splitLine[2] ), float( splitLine[3] ) )

View File

@ -1,185 +0,0 @@
"""
This page is in the table of contents.
The slc.py script is an import translator plugin to get a carving from an [http://rapid.lpt.fi/archives/rp-ml-1999/0713.html slc file].
An import plugin is a script in the interpret_plugins folder which has the function getCarving. It is meant to be run from the interpret tool. To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
The getCarving function takes the file name of an slc file and returns the carving.
"""
from __future__ import absolute_import
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import svg_writer
from struct import unpack
import math
import sys
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getCarving(fileName=''):
"Get the triangle mesh for the slc file."
carving = SLCCarving()
carving.readFile(fileName)
return carving
def getLittleEndianFloatGivenFile( file ):
"Get little endian float given a file."
return unpack('<f', file.read(4) )[0]
def getLittleEndianUnsignedLongGivenFile( file ):
"Get little endian float given a file."
return unpack('<L', file.read(4) )[0]
def getPointsFromFile( numPoints, file ):
"Process the vertice points for a given boundary."
points = []
for pointIndex in xrange( numPoints ):
x = getLittleEndianFloatGivenFile( file )
y = getLittleEndianFloatGivenFile( file )
points.append( complex(x, y) )
return points
def readHeader( file ):
"Read the slc header."
while ord( file.read( 1 ) ) != 0x1A:
pass
class SampleTableEntry(object):
"Sample table entry."
def __init__( self, file ):
"Read in the sampling table section. It contains a table length (byte) and the table entries."
self.min_z_level = getLittleEndianFloatGivenFile( file )
self.layer_thickness = getLittleEndianFloatGivenFile( file )
self.beam_comp = getLittleEndianFloatGivenFile( file )
getLittleEndianFloatGivenFile( file )
def __repr__(self):
"Get the string representation of this sample table entry."
return '%s, %s, %s' % ( self.min_z_level, self.layer_thickness, self.beam_comp )
class SLCCarving(object):
"An slc carving."
def __init__(self):
"Add empty lists."
self.layerHeight = None
self.loopLayers = []
self.maximumZ = - 987654321.0
self.minimumZ = 987654321.0
def __repr__(self):
"Get the string representation of this carving."
return self.getCarvedSVG()
def addXML(self, depth, output):
"Add xml for this object."
xml_simple_writer.addXMLFromObjects(depth, self.loopLayers, output)
def getCarveBoundaryLayers(self):
"Get the boundary layers."
return self.loopLayers
def getCarveCornerMaximum(self):
"Get the corner maximum of the vertexes."
return self.cornerMaximum
def getCarveCornerMinimum(self):
"Get the corner minimum of the vertexes."
return self.cornerMinimum
def getCarvedSVG(self):
"Get the carved svg text."
if len(self.loopLayers) < 1:
return ''
decimalPlaces = max(0, 2 - int(math.floor(math.log10(self.layerHeight))))
self.svgWriter = svg_writer.SVGWriter(True, self.cornerMaximum, self.cornerMinimum, decimalPlaces, self.layerHeight)
return self.svgWriter.getReplacedSVGTemplate(self.fileName, self.loopLayers, 'basic')
def getCarveLayerHeight(self):
"Get the layer height."
return self.layerHeight
def getFabmetheusXML(self):
"Return the fabmetheus XML."
return None
def getInterpretationSuffix(self):
"Return the suffix for a carving."
return 'svg'
def processContourLayers( self, file ):
"Process a contour layer at a time until the top of the part."
while True:
minLayer = getLittleEndianFloatGivenFile( file )
numContours = getLittleEndianUnsignedLongGivenFile( file )
if numContours == 0xFFFFFFFF:
return
loopLayer = euclidean.LoopLayer( minLayer )
self.loopLayers.append( loopLayer )
for contourIndex in xrange( numContours ):
numPoints = getLittleEndianUnsignedLongGivenFile( file )
numGaps = getLittleEndianUnsignedLongGivenFile( file )
if numPoints > 2:
loopLayer.loops.append( getPointsFromFile( numPoints, file ) )
def readFile( self, fileName ):
"Read SLC and store the layers."
self.fileName = fileName
pslcfile = open( fileName, 'rb')
readHeader( pslcfile )
pslcfile.read( 256 ) #Go past the 256 byte 3D Reserved Section.
self.readTableEntry( pslcfile )
self.processContourLayers( pslcfile )
pslcfile.close()
self.cornerMaximum = Vector3(-987654321.0, -987654321.0, self.maximumZ)
self.cornerMinimum = Vector3(987654321.0, 987654321.0, self.minimumZ)
for loopLayer in self.loopLayers:
for loop in loopLayer.loops:
for point in loop:
pointVector3 = Vector3(point.real, point.imag, loopLayer.z)
self.cornerMaximum.maximize(pointVector3)
self.cornerMinimum.minimize(pointVector3)
halfLayerThickness = 0.5 * self.layerHeight
self.cornerMaximum.z += halfLayerThickness
self.cornerMinimum.z -= halfLayerThickness
def readTableEntry( self, file ):
"Read in the sampling table section. It contains a table length (byte) and the table entries."
tableEntrySize = ord( file.read( 1 ) )
if tableEntrySize == 0:
print("Sampling table size is zero!")
exit()
for index in xrange( tableEntrySize ):
sampleTableEntry = SampleTableEntry( file )
self.layerHeight = sampleTableEntry.layerHeight
def setCarveImportRadius( self, importRadius ):
"Set the import radius."
pass
def setCarveIsCorrectMesh( self, isCorrectMesh ):
"Set the is correct mesh flag."
pass
def setCarveLayerHeight( self, layerHeight ):
"Set the layer height."
pass
def main():
"Display the inset dialog."
if len(sys.argv) > 1:
getCarving(' '.join(sys.argv[1 :]))
if __name__ == "__main__":
main()

View File

@ -1,108 +0,0 @@
"""
This page is in the table of contents.
The stl.py script is an import translator plugin to get a carving from an stl file.
An import plugin is a script in the interpret_plugins folder which has the function getCarving. It is meant to be run from the interpret tool. To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
The getCarving function takes the file name of an stl file and returns the carving.
STL is an inferior triangle surface format, described at:
http://en.wikipedia.org/wiki/STL_(file_format)
A good triangle surface format is the GNU Triangulated Surface format which is described at:
http://gts.sourceforge.net/reference/gts-surfaces.html#GTS-SURFACE-WRITE
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_tools import face
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import archive
from struct import unpack
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addFacesGivenBinary( stlData, triangleMesh, vertexIndexTable ):
"Add faces given stl binary."
numberOfVertexes = ( len( stlData ) - 84 ) / 50
vertexes = []
for vertexIndex in xrange( numberOfVertexes ):
byteIndex = 84 + vertexIndex * 50
vertexes.append( getVertexGivenBinary( byteIndex + 12, stlData ) )
vertexes.append( getVertexGivenBinary( byteIndex + 24, stlData ) )
vertexes.append( getVertexGivenBinary( byteIndex + 36, stlData ) )
addFacesGivenVertexes( triangleMesh, vertexIndexTable, vertexes )
def addFacesGivenText( stlText, triangleMesh, vertexIndexTable ):
"Add faces given stl text."
lines = archive.getTextLines( stlText )
vertexes = []
for line in lines:
if line.find('vertex') != - 1:
vertexes.append( getVertexGivenLine(line) )
addFacesGivenVertexes( triangleMesh, vertexIndexTable, vertexes )
def addFacesGivenVertexes( triangleMesh, vertexIndexTable, vertexes ):
"Add faces given stl text."
for vertexIndex in xrange( 0, len(vertexes), 3 ):
triangleMesh.faces.append( getFaceGivenLines( triangleMesh, vertexIndex, vertexIndexTable, vertexes ) )
def getCarving(fileName=''):
"Get the triangle mesh for the stl file."
if fileName == '':
return None
stlData = archive.getFileText(fileName, True, 'rb')
if stlData == '':
return None
triangleMesh = triangle_mesh.TriangleMesh()
vertexIndexTable = {}
numberOfVertexStrings = stlData.count('vertex')
requiredVertexStringsForText = max( 2, len( stlData ) / 8000 )
if numberOfVertexStrings > requiredVertexStringsForText:
addFacesGivenText( stlData, triangleMesh, vertexIndexTable )
else:
# A binary stl should never start with the word "solid". Because this error is common the file is been parsed as binary regardless.
addFacesGivenBinary( stlData, triangleMesh, vertexIndexTable )
return triangleMesh
def getFaceGivenLines( triangleMesh, vertexStartIndex, vertexIndexTable, vertexes ):
"Add face given line index and lines."
faceGivenLines = face.Face()
faceGivenLines.index = len( triangleMesh.faces )
for vertexIndex in xrange( vertexStartIndex, vertexStartIndex + 3 ):
vertex = vertexes[vertexIndex]
vertexUniqueIndex = len( vertexIndexTable )
if str(vertex) in vertexIndexTable:
vertexUniqueIndex = vertexIndexTable[ str(vertex) ]
else:
vertexIndexTable[ str(vertex) ] = vertexUniqueIndex
triangleMesh.vertexes.append(vertex)
faceGivenLines.vertexIndexes.append( vertexUniqueIndex )
return faceGivenLines
def getFloat(floatString):
"Get the float, replacing commas if necessary because an inferior program is using a comma instead of a point for the decimal point."
try:
return float(floatString)
except:
return float( floatString.replace(',', '.') )
def getFloatGivenBinary( byteIndex, stlData ):
"Get vertex given stl vertex line."
return unpack('f', stlData[ byteIndex : byteIndex + 4 ] )[0]
def getVertexGivenBinary( byteIndex, stlData ):
"Get vertex given stl vertex line."
return Vector3( getFloatGivenBinary( byteIndex, stlData ), getFloatGivenBinary( byteIndex + 4, stlData ), getFloatGivenBinary( byteIndex + 8, stlData ) )
def getVertexGivenLine(line):
"Get vertex given stl vertex line."
splitLine = line.split()
return Vector3( getFloat(splitLine[1]), getFloat( splitLine[2] ), getFloat( splitLine[3] ) )

View File

@ -1,104 +0,0 @@
"""
This page is in the table of contents.
The svg.py script is an import translator plugin to get a carving from an svg file. This script will read an svg file made by skeinforge or by inkscape.
An example inkscape svg file is inkscape_star.svg in the models folder.
An import plugin is a script in the interpret_plugins folder which has the function getCarving. It is meant to be run from the interpret tool. To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
The getCarving function takes the file name of an svg file and returns the carving.
"""
from __future__ import absolute_import
from fabmetheus_utilities.svg_reader import SVGReader
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import archive
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import svg_writer
from fabmetheus_utilities import xml_simple_writer
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getCarving(fileName=''):
'Get the triangle mesh for the gts file.'
carving = SVGCarving()
carving.parseSVG(fileName, archive.getFileText(fileName))
return carving
class SVGCarving(object):
'An svg carving.'
def __init__(self):
'Add empty lists.'
self.layerHeight = 1.0
self.maximumZ = - 987654321.0
self.minimumZ = 987654321.0
self.svgReader = SVGReader()
def __repr__(self):
'Get the string representation of this carving.'
return self.getCarvedSVG()
def addXML(self, depth, output):
'Add xml for this object.'
xml_simple_writer.addXMLFromObjects(depth, self.svgReader.loopLayers, output)
def getCarveBoundaryLayers(self):
'Get the boundary layers.'
return self.svgReader.loopLayers
def getCarveCornerMaximum(self):
'Get the corner maximum of the vertexes.'
return self.cornerMaximum
def getCarveCornerMinimum(self):
'Get the corner minimum of the vertexes.'
return self.cornerMinimum
def getCarvedSVG(self):
'Get the carved svg text.'
return svg_writer.getSVGByLoopLayers(True, self, self.svgReader.loopLayers)
def getCarveLayerHeight(self):
'Get the layer height.'
return self.layerHeight
def getFabmetheusXML(self):
'Return the fabmetheus XML.'
return None
def getInterpretationSuffix(self):
'Return the suffix for a carving.'
return 'svg'
def parseSVG(self, fileName, svgText):
'Parse SVG text and store the layers.'
if svgText == '':
return
self.fileName = fileName
self.svgReader.parseSVG(fileName, svgText)
self.layerHeight = euclidean.getFloatDefaultByDictionary(
self.layerHeight, self.svgReader.sliceDictionary, 'layerHeight')
self.cornerMaximum = Vector3(-987654321.0, -987654321.0, self.maximumZ)
self.cornerMinimum = Vector3(987654321.0, 987654321.0, self.minimumZ)
svg_writer.setSVGCarvingCorners(
self.cornerMaximum, self.cornerMinimum, self.layerHeight, self.svgReader.loopLayers)
def setCarveImportRadius(self, importRadius):
'Set the import radius.'
pass
def setCarveIsCorrectMesh(self, isCorrectMesh):
'Set the is correct mesh flag.'
pass
def setCarveLayerHeight(self, layerHeight):
'Set the layer height.'
self.layerHeight = layerHeight

View File

@ -1,441 +0,0 @@
"""
Gcodec is a collection of utilities to decode and encode gcode.
To run gcodec, install python 2.x on your machine, which is avaliable from http://www.python.org/download/
Then in the folder which gcodec is in, type 'python' in a shell to run the python interpreter. Finally type 'from gcodec import *' to import this program.
Below is an example of gcodec use. This example is run in a terminal in the folder which contains gcodec and Screw Holder Bottom_export.gcode.
>>> from gcodec import *
>>> getFileText('Screw Holder Bottom_export.gcode')
'G90\nG21\nM103\nM105\nM106\nM110 S60.0\nM111 S30.0\nM108 S210.0\nM104 S235.0\nG1 X0.37 Y-4.07 Z1.9 F60.0\nM101\n
..
many lines of text
..
"""
from __future__ import absolute_import
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import archive
from fabmetheus_utilities import euclidean
import math
import sys
if sys.version_info[0] < 3:
import cStringIO
else:
import io as cStringIO
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addLineAndNewlineIfNecessary(line, output):
'Add the line and if the line does not end with a newline add a newline.'
output.write(line)
if len(line) < 1:
return
if not line.endswith('\n'):
output.write('\n')
def addLinesToCString(cString, lines):
'Add lines which have something to cStringIO.'
for line in lines:
if line != '':
cString.write(line + '\n')
def getArcDistance(relativeLocation, splitLine):
'Get arc distance.'
halfPlaneLineDistance = 0.5 * abs(relativeLocation.dropAxis())
radius = getDoubleFromCharacterSplitLine('R', splitLine)
if radius == None:
iFloat = getDoubleFromCharacterSplitLine('I', splitLine)
jFloat = getDoubleFromCharacterSplitLine('J', splitLine)
radius = abs(complex(iFloat, jFloat))
angle = 0.0
if radius > 0.0:
halfPlaneLineDistanceOverRadius = halfPlaneLineDistance / radius
if halfPlaneLineDistance < radius:
angle = 2.0 * math.asin(halfPlaneLineDistanceOverRadius)
else:
angle = math.pi * halfPlaneLineDistanceOverRadius
return abs(complex(angle * radius, relativeLocation.z))
def getDoubleAfterFirstLetter(word):
'Get the double value of the word after the first letter.'
return float(word[1 :])
def getDoubleForLetter(letter, splitLine):
'Get the double value of the word after the first occurence of the letter in the split line.'
return getDoubleAfterFirstLetter(splitLine[getIndexOfStartingWithSecond(letter, splitLine)])
def getDoubleFromCharacterSplitLine(character, splitLine):
'Get the double value of the string after the first occurence of the character in the split line.'
indexOfCharacter = getIndexOfStartingWithSecond(character, splitLine)
if indexOfCharacter < 0:
return None
floatString = splitLine[indexOfCharacter][1 :]
try:
return float(floatString)
except ValueError:
return None
def getDoubleFromCharacterSplitLineValue(character, splitLine, value):
'Get the double value of the string after the first occurence of the character in the split line, if it does not exist return the value.'
splitLineFloat = getDoubleFromCharacterSplitLine(character, splitLine)
if splitLineFloat == None:
return value
return splitLineFloat
def getFeedRateMinute(feedRateMinute, splitLine):
'Get the feed rate per minute if the split line has a feed rate.'
indexOfF = getIndexOfStartingWithSecond('F', splitLine)
if indexOfF > 0:
return getDoubleAfterFirstLetter( splitLine[indexOfF] )
return feedRateMinute
def getFirstWord(splitLine):
'Get the first word of a split line.'
if len(splitLine) > 0:
return splitLine[0]
return ''
def getFirstWordFromLine(line):
'Get the first word of a line.'
return getFirstWord(line.split())
def getFirstWordIndexReverse(firstWord, lines, startIndex):
'Parse gcode in reverse order until the first word if there is one, otherwise return -1.'
for lineIndex in xrange(len(lines) - 1, startIndex - 1, -1):
if firstWord == getFirstWord(getSplitLineBeforeBracketSemicolon(lines[lineIndex])):
return lineIndex
return -1
def getGcodeFileText(fileName, gcodeText):
'Get the gcode text from a file if it the gcode text is empty and if the file is a gcode file.'
if gcodeText != '':
return gcodeText
if fileName.endswith('.gcode'):
return archive.getFileText(fileName)
return ''
def getGcodeWithoutDuplication(duplicateWord, gcodeText):
'Get gcode text without duplicate first words.'
lines = archive.getTextLines(gcodeText)
oldWrittenLine = None
output = cStringIO.StringIO()
for line in lines:
firstWord = getFirstWordFromLine(line)
if firstWord == duplicateWord:
if line != oldWrittenLine:
output.write(line + '\n')
oldWrittenLine = line
else:
if len(line) > 0:
output.write(line + '\n')
return output.getvalue()
def getIndexOfStartingWithSecond(letter, splitLine):
'Get index of the first occurence of the given letter in the split line, starting with the second word. Return - 1 if letter is not found'
for wordIndex in xrange( 1, len(splitLine) ):
word = splitLine[ wordIndex ]
firstLetter = word[0]
if firstLetter == letter:
return wordIndex
return - 1
def getLineWithValueString(character, line, splitLine, valueString):
'Get the line with a valueString.'
roundedValueString = character + valueString
indexOfValue = getIndexOfStartingWithSecond(character, splitLine)
if indexOfValue == -1:
return line + ' ' + roundedValueString
word = splitLine[indexOfValue]
return line.replace(word, roundedValueString)
def getLocationFromSplitLine(oldLocation, splitLine):
'Get the location from the split line.'
if oldLocation == None:
oldLocation = Vector3()
return Vector3(
getDoubleFromCharacterSplitLineValue('X', splitLine, oldLocation.x),
getDoubleFromCharacterSplitLineValue('Y', splitLine, oldLocation.y),
getDoubleFromCharacterSplitLineValue('Z', splitLine, oldLocation.z))
def getRotationBySplitLine(splitLine):
'Get the complex rotation from the split gcode line.'
return complex(splitLine[1].replace('(', '').replace(')', ''))
def getSplitLineBeforeBracketSemicolon(line):
'Get the split line before a bracket or semicolon.'
if ';' in line:
line = line[: line.find(';')]
bracketIndex = line.find('(')
if bracketIndex > 0:
return line[: bracketIndex].split()
return line.split()
def getStringFromCharacterSplitLine(character, splitLine):
'Get the string after the first occurence of the character in the split line.'
indexOfCharacter = getIndexOfStartingWithSecond(character, splitLine)
if indexOfCharacter < 0:
return None
return splitLine[indexOfCharacter][1 :]
def getTagBracketedLine(tagName, value):
'Get line with a begin tag, value and end tag.'
return '(<%s> %s </%s>)' % (tagName, value, tagName)
def getTagBracketedProcedure(procedure):
'Get line with a begin procedure tag, procedure and end procedure tag.'
return getTagBracketedLine('procedureName', procedure)
def isProcedureDone(gcodeText, procedure):
'Determine if the procedure has been done on the gcode text.'
if gcodeText == '':
return False
extruderInitializationIndex = gcodeText.find('(</extruderInitialization>)')
if extruderInitializationIndex == -1:
metadataBeginIndex = gcodeText.find('<metadata>')
metadataEndIndex = gcodeText.find('</metadata>')
if metadataBeginIndex != -1 and metadataEndIndex != -1:
attributeString = "procedureName='%s'" % procedure
return gcodeText.find(attributeString, metadataBeginIndex, metadataEndIndex) != -1
return False
return gcodeText.find(getTagBracketedProcedure(procedure), 0, extruderInitializationIndex) != -1
def isProcedureDoneOrFileIsEmpty(gcodeText, procedure):
'Determine if the procedure has been done on the gcode text or the file is empty.'
if gcodeText == '':
return True
return isProcedureDone(gcodeText, procedure)
def isThereAFirstWord(firstWord, lines, startIndex):
'Parse gcode until the first word if there is one.'
for lineIndex in xrange(startIndex, len(lines)):
line = lines[lineIndex]
splitLine = getSplitLineBeforeBracketSemicolon(line)
if firstWord == getFirstWord(splitLine):
return True
return False
class BoundingRectangle(object):
'A class to get the corners of a gcode text.'
def getFromGcodeLines(self, lines, radius):
'Parse gcode text and get the minimum and maximum corners.'
self.cornerMaximum = complex(-987654321.0, -987654321.0)
self.cornerMinimum = complex(987654321.0, 987654321.0)
self.oldLocation = None
self.cornerRadius = complex(radius, radius)
for line in lines:
self.parseCorner(line)
return self
def isPointInside(self, point):
'Determine if the point is inside the bounding rectangle.'
return point.imag >= self.cornerMinimum.imag and point.imag <= self.cornerMaximum.imag and point.real >= self.cornerMinimum.real and point.real <= self.cornerMaximum.real
def parseCorner(self, line):
'Parse a gcode line and use the location to update the bounding corners.'
splitLine = getSplitLineBeforeBracketSemicolon(line)
firstWord = getFirstWord(splitLine)
if firstWord == '(<boundaryPoint>':
locationComplex = getLocationFromSplitLine(None, splitLine).dropAxis()
self.cornerMaximum = euclidean.getMaximum(self.cornerMaximum, locationComplex)
self.cornerMinimum = euclidean.getMinimum(self.cornerMinimum, locationComplex)
elif firstWord == 'G1':
location = getLocationFromSplitLine(self.oldLocation, splitLine)
locationComplex = location.dropAxis()
self.cornerMaximum = euclidean.getMaximum(self.cornerMaximum, locationComplex + self.cornerRadius)
self.cornerMinimum = euclidean.getMinimum(self.cornerMinimum, locationComplex - self.cornerRadius)
self.oldLocation = location
class DistanceFeedRate(object):
'A class to limit the z feed rate and round values.'
def __init__(self):
'Initialize.'
self.isAlteration = False
self.decimalPlacesCarried = 3
self.output = cStringIO.StringIO()
def addFlowRateLine(self, flowRate):
'Add a flow rate line.'
self.output.write('M108 S%s\n' % euclidean.getFourSignificantFigures(flowRate))
def addGcodeFromFeedRateThreadZ(self, feedRateMinute, thread, travelFeedRateMinute, z):
'Add a thread to the output.'
if len(thread) > 0:
self.addGcodeMovementZWithFeedRate(travelFeedRateMinute, thread[0], z)
else:
print('zero length vertex positions array which was skipped over, this should never happen.')
if len(thread) < 2:
print('thread of only one point in addGcodeFromFeedRateThreadZ in gcodec, this should never happen.')
print(thread)
return
self.output.write('M101\n') # Turn extruder on.
for point in thread[1 :]:
self.addGcodeMovementZWithFeedRate(feedRateMinute, point, z)
self.output.write('M103\n') # Turn extruder off.
def addGcodeFromLoop(self, loop, z):
'Add the gcode loop.'
euclidean.addNestedRingBeginning(self, loop, z)
self.addPerimeterBlock(loop, z)
self.addLine('(</boundaryPerimeter>)')
self.addLine('(</nestedRing>)')
def addGcodeFromThreadZ(self, thread, z):
'Add a thread to the output.'
if len(thread) > 0:
self.addGcodeMovementZ(thread[0], z)
else:
print('zero length vertex positions array which was skipped over, this should never happen.')
if len(thread) < 2:
print('thread of only one point in addGcodeFromThreadZ in gcodec, this should never happen.')
print(thread)
return
self.output.write('M101\n') # Turn extruder on.
for point in thread[1 :]:
self.addGcodeMovementZ(point, z)
self.output.write('M103\n') # Turn extruder off.
def addGcodeMovementZ(self, point, z):
'Add a movement to the output.'
self.output.write(self.getLinearGcodeMovement(point, z) + '\n')
def addGcodeMovementZWithFeedRate(self, feedRateMinute, point, z):
'Add a movement to the output.'
self.output.write(self.getLinearGcodeMovementWithFeedRate(feedRateMinute, point, z) + '\n')
def addGcodeMovementZWithFeedRateVector3(self, feedRateMinute, vector3):
'Add a movement to the output by Vector3.'
xRounded = self.getRounded(vector3.x)
yRounded = self.getRounded(vector3.y)
self.output.write('G1 X%s Y%s Z%s F%s\n' % (xRounded, yRounded, self.getRounded(vector3.z), self.getRounded(feedRateMinute)))
def addLine(self, line):
'Add a line of text and a newline to the output.'
if len(line) > 0:
self.output.write(line + '\n')
def addLineCheckAlteration(self, line):
'Add a line of text and a newline to the output and check to see if it is an alteration line.'
firstWord = getFirstWord(getSplitLineBeforeBracketSemicolon(line))
if firstWord == '(<alteration>)':
self.isAlteration = True
elif firstWord == '(</alteration>)':
self.isAlteration = False
if len(line) > 0:
self.output.write(line + '\n')
def addLines(self, lines):
'Add lines of text to the output.'
addLinesToCString(self.output, lines)
def addLinesSetAbsoluteDistanceMode(self, lines):
'Add lines of text to the output and ensure the absolute mode is set.'
if len(lines) < 1:
return
if len(lines[0]) < 1:
return
absoluteDistanceMode = True
self.addLine('(<alteration>)')
for line in lines:
splitLine = getSplitLineBeforeBracketSemicolon(line)
firstWord = getFirstWord(splitLine)
if firstWord == 'G90':
absoluteDistanceMode = True
elif firstWord == 'G91':
absoluteDistanceMode = False
self.addLine('(<alterationDeleteThisPrefix/>)' + line)
if not absoluteDistanceMode:
self.addLine('G90')
self.addLine('(</alteration>)')
def addParameter(self, firstWord, parameter):
'Add the parameter.'
self.addLine(firstWord + ' S' + euclidean.getRoundedToThreePlaces(parameter))
def addPerimeterBlock(self, loop, z):
'Add the edge gcode block for the loop.'
if len(loop) < 2:
return
if euclidean.isWiddershins(loop): # Indicate that an edge is beginning.
self.addLine('(<edge> outer )')
else:
self.addLine('(<edge> inner )')
self.addGcodeFromThreadZ(loop + [loop[0]], z)
self.addLine('(</edge>)') # Indicate that an edge is beginning.
def addTagBracketedLine(self, tagName, value):
'Add a begin tag, value and end tag.'
self.addLine(getTagBracketedLine(tagName, value))
def addTagRoundedLine(self, tagName, value):
'Add a begin tag, rounded value and end tag.'
self.addLine('(<%s> %s </%s>)' % (tagName, self.getRounded(value), tagName))
def addTagBracketedProcedure(self, procedure):
'Add a begin procedure tag, procedure and end procedure tag.'
self.addLine(getTagBracketedProcedure(procedure))
def getBoundaryLine(self, location):
'Get boundary gcode line.'
return '(<boundaryPoint> X%s Y%s Z%s </boundaryPoint>)' % (self.getRounded(location.x), self.getRounded(location.y), self.getRounded(location.z))
def getFirstWordMovement(self, firstWord, location):
'Get the start of the arc line.'
return '%s X%s Y%s Z%s' % (firstWord, self.getRounded(location.x), self.getRounded(location.y), self.getRounded(location.z))
def getInfillBoundaryLine(self, location):
'Get infill boundary gcode line.'
return '(<infillPoint> X%s Y%s Z%s </infillPoint>)' % (self.getRounded(location.x), self.getRounded(location.y), self.getRounded(location.z))
def getIsAlteration(self, line):
'Determine if it is an alteration.'
if self.isAlteration:
self.addLineCheckAlteration(line)
return True
return False
def getLinearGcodeMovement(self, point, z):
'Get a linear gcode movement.'
return 'G1 X%s Y%s Z%s' % (self.getRounded(point.real), self.getRounded(point.imag), self.getRounded(z))
def getLinearGcodeMovementWithFeedRate(self, feedRateMinute, point, z):
'Get a z limited gcode movement.'
linearGcodeMovement = self.getLinearGcodeMovement(point, z)
if feedRateMinute == None:
return linearGcodeMovement
return linearGcodeMovement + ' F' + self.getRounded(feedRateMinute)
def getLineWithFeedRate(self, feedRateMinute, line, splitLine):
'Get the line with a feed rate.'
return getLineWithValueString('F', line, splitLine, self.getRounded(feedRateMinute))
def getLineWithX(self, line, splitLine, x):
'Get the line with an x.'
return getLineWithValueString('X', line, splitLine, self.getRounded(x))
def getLineWithY(self, line, splitLine, y):
'Get the line with a y.'
return getLineWithValueString('Y', line, splitLine, self.getRounded(y))
def getLineWithZ(self, line, splitLine, z):
'Get the line with a z.'
return getLineWithValueString('Z', line, splitLine, self.getRounded(z))
def getRounded(self, number):
'Get number rounded to the number of carried decimal places as a string.'
return euclidean.getRoundedToPlacesString(self.decimalPlacesCarried, number)
def parseSplitLine(self, firstWord, splitLine):
'Parse gcode split line and store the parameters.'
if firstWord == '(<decimalPlacesCarried>':
self.decimalPlacesCarried = int(splitLine[1])

View File

@ -1,53 +0,0 @@
"""
Drill negative solid.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.creation import teardrop
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutput(derivation, elementNode):
"Get vector3 vertexes from attribute dictionary."
if derivation == None:
derivation = DrillDerivation(elementNode)
negatives = []
teardrop.addNegativesByRadius(elementNode, derivation.end, negatives, derivation.radius, derivation.start)
return solid.getGeometryOutputByManipulation(elementNode, negatives[0])
def getGeometryOutputByArguments(arguments, elementNode):
"Get vector3 vertexes from attribute dictionary by arguments."
evaluate.setAttributesByArguments(['radius', 'start', 'end'], arguments, elementNode)
return getGeometryOutput(None, elementNode)
def getNewDerivation(elementNode):
'Get new derivation.'
return DrillDerivation(elementNode)
def processElementNode(elementNode):
"Process the xml element."
solid.processElementNodeByGeometry(elementNode, getGeometryOutput(None, elementNode))
class DrillDerivation(object):
"Class to hold drill variables."
def __init__(self, elementNode):
'Set defaults.'
self.elementNode = elementNode
self.end = evaluate.getVector3ByPrefix(Vector3(0.0, 0.0, 1.0), elementNode, 'end')
self.start = evaluate.getVector3ByPrefix(Vector3(), elementNode, 'start')
self.radius = lineation.getFloatByPrefixBeginEnd(elementNode, 'radius', 'diameter', 1.0)
size = evaluate.getEvaluatedFloat(None, elementNode, 'size')
if size != None:
self.radius = 0.5 * size

View File

@ -1,58 +0,0 @@
"""
Svg reader.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import svg_reader
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutput(derivation, elementNode):
"Get vector3 vertexes from attribute dictionary."
if derivation == None:
derivation = SVGDerivation(elementNode)
return getGeometryOutputBySVGReader(elementNode, derivation.svgReader)
def getGeometryOutputByArguments(arguments, elementNode):
"Get vector3 vertexes from attribute dictionary by arguments."
derivation = SVGDerivation()
derivation.svgReader.parseSVG('', arguments[0])
return getGeometryOutput(derivation, elementNode)
def getGeometryOutputBySVGReader(elementNode, svgReader):
"Get vector3 vertexes from svgReader."
geometryOutput = []
for loopLayer in svgReader.loopLayers:
for loop in loopLayer.loops:
vector3Path = euclidean.getVector3Path(loop, loopLayer.z)
sideLoop = lineation.SideLoop(vector3Path)
sideLoop.rotate(elementNode)
geometryOutput += lineation.getGeometryOutputByManipulation(elementNode, sideLoop)
return geometryOutput
def getNewDerivation(elementNode):
'Get new derivation.'
return SVGDerivation(elementNode)
def processElementNode(elementNode):
"Process the xml element."
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
class SVGDerivation(object):
"Class to hold svg variables."
def __init__(self, elementNode):
'Set defaults.'
self.svgReader = svg_reader.SVGReader()
self.svgReader.parseSVGByElementNode(elementNode)

View File

@ -1,74 +0,0 @@
"""
Polygon path.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutput(derivation, elementNode):
"Get vector3 vertexes from attribute dictionary."
if derivation == None:
derivation = CircleDerivation(elementNode)
angleTotal = math.radians(derivation.start)
loop = []
sidesCeiling = int(math.ceil(abs(derivation.sides) * derivation.extent / 360.0))
sideAngle = math.radians(derivation.extent) / sidesCeiling
if derivation.sides < 0.0:
sideAngle = -sideAngle
spiral = lineation.Spiral(derivation.spiral, 0.5 * sideAngle / math.pi)
for side in xrange(sidesCeiling + 1):
unitPolar = euclidean.getWiddershinsUnitPolar(angleTotal)
x = unitPolar.real * derivation.radiusArealized.real
y = unitPolar.imag * derivation.radiusArealized.imag
vertex = spiral.getSpiralPoint(unitPolar, Vector3(x, y))
angleTotal += sideAngle
loop.append(vertex)
radiusMaximum = 0.000001 * max(derivation.radiusArealized.real, derivation.radiusArealized.imag)
loop = euclidean.getLoopWithoutCloseEnds(radiusMaximum, loop)
lineation.setClosedAttribute(elementNode, derivation.revolutions)
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop(loop, sideAngle))
def getGeometryOutputByArguments(arguments, elementNode):
"Get vector3 vertexes from attribute dictionary by arguments."
evaluate.setAttributesByArguments(['radius', 'start', 'end', 'revolutions'], arguments, elementNode)
return getGeometryOutput(None, elementNode)
def getNewDerivation(elementNode):
'Get new derivation.'
return CircleDerivation(elementNode)
def processElementNode(elementNode):
"Process the xml element."
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
class CircleDerivation(object):
"Class to hold circle variables."
def __init__(self, elementNode):
'Set defaults.'
self.radius = lineation.getRadiusComplex(elementNode, complex(1.0, 1.0))
self.sides = evaluate.getEvaluatedFloat(None, elementNode, 'sides')
if self.sides == None:
radiusMaximum = max(self.radius.real, self.radius.imag)
self.sides = evaluate.getSidesMinimumThreeBasedOnPrecisionSides(elementNode, radiusMaximum)
self.radiusArealized = evaluate.getRadiusArealizedBasedOnAreaRadius(elementNode, self.radius, self.sides)
self.start = evaluate.getEvaluatedFloat(0.0, elementNode, 'start')
end = evaluate.getEvaluatedFloat(360.0, elementNode, 'end')
self.revolutions = evaluate.getEvaluatedFloat(1.0, elementNode, 'revolutions')
self.extent = evaluate.getEvaluatedFloat(end - self.start, elementNode, 'extent')
self.extent += 360.0 * (self.revolutions - 1.0)
self.spiral = evaluate.getVector3ByPrefix(None, elementNode, 'spiral')

View File

@ -1,50 +0,0 @@
"""
Boolean geometry concatenation.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutput(derivation, elementNode):
'Get triangle mesh from attribute dictionary.'
if derivation == None:
derivation = ConcatenateDerivation(elementNode)
concatenatedList = euclidean.getConcatenatedList(derivation.target)[:]
if len(concatenatedList) == 0:
print('Warning, in concatenate there are no paths.')
print(elementNode.attributes)
return None
if 'closed' not in elementNode.attributes:
elementNode.attributes['closed'] = 'true'
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop(concatenatedList))
def getGeometryOutputByArguments(arguments, elementNode):
'Get triangle mesh from attribute dictionary by arguments.'
return getGeometryOutput(None, elementNode)
def getNewDerivation(elementNode):
'Get new derivation.'
return ConcatenateDerivation(elementNode)
def processElementNode(elementNode):
'Process the xml element.'
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
class ConcatenateDerivation(object):
'Class to hold concatenate variables.'
def __init__(self, elementNode):
'Initialize.'
self.target = evaluate.getTransformedPathsByKey([], elementNode, 'target')

View File

@ -1,438 +0,0 @@
"""
Boolean geometry extrusion.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities.vector3index import Vector3Index
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addLoop(derivation, endMultiplier, loopLists, path, portionDirectionIndex, portionDirections, vertexes):
'Add an indexed loop to the vertexes.'
portionDirection = portionDirections[ portionDirectionIndex ]
if portionDirection.directionReversed == True:
loopLists.append([])
loops = loopLists[-1]
interpolationOffset = derivation.interpolationDictionary['offset']
offset = interpolationOffset.getVector3ByPortion( portionDirection )
if endMultiplier != None:
if portionDirectionIndex == 0:
setOffsetByMultiplier( interpolationOffset.path[1], interpolationOffset.path[0], endMultiplier, offset )
elif portionDirectionIndex == len( portionDirections ) - 1:
setOffsetByMultiplier( interpolationOffset.path[-2], interpolationOffset.path[-1], endMultiplier, offset )
scale = derivation.interpolationDictionary['scale'].getComplexByPortion( portionDirection )
twist = derivation.interpolationDictionary['twist'].getYByPortion( portionDirection )
projectiveSpace = euclidean.ProjectiveSpace()
if derivation.tiltTop == None:
tilt = derivation.interpolationDictionary['tilt'].getComplexByPortion( portionDirection )
projectiveSpace = projectiveSpace.getByTilt( tilt )
else:
normals = getNormals( interpolationOffset, offset, portionDirection )
normalFirst = normals[0]
normalAverage = getNormalAverage(normals)
if derivation.tiltFollow and derivation.oldProjectiveSpace != None:
projectiveSpace = derivation.oldProjectiveSpace.getNextSpace( normalAverage )
else:
projectiveSpace = projectiveSpace.getByBasisZTop( normalAverage, derivation.tiltTop )
derivation.oldProjectiveSpace = projectiveSpace
projectiveSpace.unbuckle( derivation.maximumUnbuckling, normalFirst )
projectiveSpace = projectiveSpace.getSpaceByXYScaleAngle( twist, scale )
loop = []
if ( abs( projectiveSpace.basisX ) + abs( projectiveSpace.basisY ) ) < 0.0001:
vector3Index = Vector3Index(len(vertexes))
addOffsetAddToLists( loop, offset, vector3Index, vertexes )
loops.append(loop)
return
for point in path:
vector3Index = Vector3Index(len(vertexes))
projectedVertex = projectiveSpace.getVector3ByPoint(point)
vector3Index.setToVector3( projectedVertex )
addOffsetAddToLists( loop, offset, vector3Index, vertexes )
loops.append(loop)
def addNegatives(derivation, negatives, paths):
'Add pillars output to negatives.'
portionDirections = getSpacedPortionDirections(derivation.interpolationDictionary)
for path in paths:
loopLists = getLoopListsByPath(derivation, 1.000001, path, portionDirections)
geometryOutput = triangle_mesh.getPillarsOutput(loopLists)
negatives.append(geometryOutput)
def addNegativesPositives(derivation, negatives, paths, positives):
'Add pillars output to negatives and positives.'
portionDirections = getSpacedPortionDirections(derivation.interpolationDictionary)
for path in paths:
endMultiplier = None
if not euclidean.getIsWiddershinsByVector3(path):
endMultiplier = 1.000001
loopLists = getLoopListsByPath(derivation, endMultiplier, path, portionDirections)
geometryOutput = triangle_mesh.getPillarsOutput(loopLists)
if endMultiplier == None:
positives.append(geometryOutput)
else:
negatives.append(geometryOutput)
def addOffsetAddToLists(loop, offset, vector3Index, vertexes):
'Add an indexed loop to the vertexes.'
vector3Index += offset
loop.append(vector3Index)
vertexes.append(vector3Index)
def addPositives(derivation, paths, positives):
'Add pillars output to positives.'
portionDirections = getSpacedPortionDirections(derivation.interpolationDictionary)
for path in paths:
loopLists = getLoopListsByPath(derivation, None, path, portionDirections)
geometryOutput = triangle_mesh.getPillarsOutput(loopLists)
positives.append(geometryOutput)
def addSpacedPortionDirection( portionDirection, spacedPortionDirections ):
'Add spaced portion directions.'
lastSpacedPortionDirection = spacedPortionDirections[-1]
if portionDirection.portion - lastSpacedPortionDirection.portion > 0.003:
spacedPortionDirections.append( portionDirection )
return
if portionDirection.directionReversed > lastSpacedPortionDirection.directionReversed:
spacedPortionDirections.append( portionDirection )
def addTwistPortions( interpolationTwist, remainderPortionDirection, twistPrecision ):
'Add twist portions.'
lastPortionDirection = interpolationTwist.portionDirections[-1]
if remainderPortionDirection.portion == lastPortionDirection.portion:
return
lastTwist = interpolationTwist.getYByPortion( lastPortionDirection )
remainderTwist = interpolationTwist.getYByPortion( remainderPortionDirection )
twistSegments = int( math.floor( abs( remainderTwist - lastTwist ) / twistPrecision ) )
if twistSegments < 1:
return
portionDifference = remainderPortionDirection.portion - lastPortionDirection.portion
twistSegmentsPlusOne = float( twistSegments + 1 )
for twistSegment in xrange( twistSegments ):
additionalPortion = portionDifference * float( twistSegment + 1 ) / twistSegmentsPlusOne
portionDirection = PortionDirection( lastPortionDirection.portion + additionalPortion )
interpolationTwist.portionDirections.append( portionDirection )
def comparePortionDirection( portionDirection, otherPortionDirection ):
'Comparison in order to sort portion directions in ascending order of portion then direction.'
if portionDirection.portion > otherPortionDirection.portion:
return 1
if portionDirection.portion < otherPortionDirection.portion:
return - 1
if portionDirection.directionReversed < otherPortionDirection.directionReversed:
return - 1
return portionDirection.directionReversed > otherPortionDirection.directionReversed
def getGeometryOutput(derivation, elementNode):
'Get triangle mesh from attribute dictionary.'
if derivation == None:
derivation = ExtrudeDerivation(elementNode)
if len(euclidean.getConcatenatedList(derivation.target)) == 0:
print('Warning, in extrude there are no paths.')
print(elementNode.attributes)
return None
return getGeometryOutputByLoops(derivation, derivation.target)
def getGeometryOutputByArguments(arguments, elementNode):
'Get triangle mesh from attribute dictionary by arguments.'
return getGeometryOutput(None, elementNode)
def getGeometryOutputByLoops(derivation, loops):
'Get geometry output by sorted, nested loops.'
loops.sort(key=euclidean.getAreaVector3LoopAbsolute, reverse=True)
complexLoops = euclidean.getComplexPaths(loops)
nestedRings = []
for loopIndex, loop in enumerate(loops):
complexLoop = complexLoops[loopIndex]
leftPoint = euclidean.getLeftPoint(complexLoop)
isInFilledRegion = euclidean.getIsInFilledRegion(complexLoops[: loopIndex] + complexLoops[loopIndex + 1 :], leftPoint)
if isInFilledRegion == euclidean.isWiddershins(complexLoop):
loop.reverse()
nestedRing = euclidean.NestedRing()
nestedRing.boundary = complexLoop
nestedRing.vector3Loop = loop
nestedRings.append(nestedRing)
nestedRings = euclidean.getOrderedNestedRings(nestedRings)
nestedRings = euclidean.getFlattenedNestedRings(nestedRings)
portionDirections = getSpacedPortionDirections(derivation.interpolationDictionary)
if len(nestedRings) < 1:
return {}
if len(nestedRings) == 1:
geometryOutput = getGeometryOutputByNestedRing(derivation, nestedRings[0], portionDirections)
return solid.getGeometryOutputByManipulation(derivation.elementNode, geometryOutput)
shapes = []
for nestedRing in nestedRings:
shapes.append(getGeometryOutputByNestedRing(derivation, nestedRing, portionDirections))
return solid.getGeometryOutputByManipulation(derivation.elementNode, {'union' : {'shapes' : shapes}})
def getGeometryOutputByNegativesPositives(elementNode, negatives, positives):
'Get triangle mesh from elementNode, negatives and positives.'
positiveOutput = triangle_mesh.getUnifiedOutput(positives)
if len(negatives) < 1:
return solid.getGeometryOutputByManipulation(elementNode, positiveOutput)
if len(positives) < 1:
negativeOutput = triangle_mesh.getUnifiedOutput(negatives)
return solid.getGeometryOutputByManipulation(elementNode, negativeOutput)
return solid.getGeometryOutputByManipulation(elementNode, {'difference' : {'shapes' : [positiveOutput] + negatives}})
def getGeometryOutputByNestedRing(derivation, nestedRing, portionDirections):
'Get geometry output by sorted, nested loops.'
loopLists = getLoopListsByPath(derivation, None, nestedRing.vector3Loop, portionDirections)
outsideOutput = triangle_mesh.getPillarsOutput(loopLists)
if len(nestedRing.innerNestedRings) < 1:
return outsideOutput
shapes = [outsideOutput]
for nestedRing.innerNestedRing in nestedRing.innerNestedRings:
loopLists = getLoopListsByPath(derivation, 1.000001, nestedRing.innerNestedRing.vector3Loop, portionDirections)
shapes.append(triangle_mesh.getPillarsOutput(loopLists))
return {'difference' : {'shapes' : shapes}}
def getLoopListsByPath(derivation, endMultiplier, path, portionDirections):
'Get loop lists from path.'
vertexes = []
loopLists = [[]]
derivation.oldProjectiveSpace = None
for portionDirectionIndex in xrange(len(portionDirections)):
addLoop(derivation, endMultiplier, loopLists, path, portionDirectionIndex, portionDirections, vertexes)
return loopLists
def getNewDerivation(elementNode):
'Get new derivation.'
return ExtrudeDerivation(elementNode)
def getNormalAverage(normals):
'Get normal.'
if len(normals) < 2:
return normals[0]
return (normals[0] + normals[1]).getNormalized()
def getNormals( interpolationOffset, offset, portionDirection ):
'Get normals.'
normals = []
portionFrom = portionDirection.portion - 0.0001
portionTo = portionDirection.portion + 0.0001
if portionFrom >= 0.0:
normals.append( ( offset - interpolationOffset.getVector3ByPortion( PortionDirection( portionFrom ) ) ).getNormalized() )
if portionTo <= 1.0:
normals.append( ( interpolationOffset.getVector3ByPortion( PortionDirection( portionTo ) ) - offset ).getNormalized() )
return normals
def getSpacedPortionDirections( interpolationDictionary ):
'Get sorted portion directions.'
portionDirections = []
for interpolationDictionaryValue in interpolationDictionary.values():
portionDirections += interpolationDictionaryValue.portionDirections
portionDirections.sort( comparePortionDirection )
if len( portionDirections ) < 1:
return []
spacedPortionDirections = [ portionDirections[0] ]
for portionDirection in portionDirections[1 :]:
addSpacedPortionDirection( portionDirection, spacedPortionDirections )
return spacedPortionDirections
def insertTwistPortions(derivation, elementNode):
'Insert twist portions and radian the twist.'
interpolationDictionary = derivation.interpolationDictionary
interpolationTwist = Interpolation().getByPrefixX(elementNode, derivation.twistPathDefault, 'twist')
interpolationDictionary['twist'] = interpolationTwist
for point in interpolationTwist.path:
point.y = math.radians(point.y)
remainderPortionDirections = interpolationTwist.portionDirections[1 :]
interpolationTwist.portionDirections = [interpolationTwist.portionDirections[0]]
if elementNode != None:
twistPrecision = setting.getTwistPrecisionRadians(elementNode)
for remainderPortionDirection in remainderPortionDirections:
addTwistPortions(interpolationTwist, remainderPortionDirection, twistPrecision)
interpolationTwist.portionDirections.append(remainderPortionDirection)
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByGeometry(elementNode, getGeometryOutput(None, elementNode))
def setElementNodeToEndStart(elementNode, end, start):
'Set elementNode attribute dictionary to a tilt following path from the start to end.'
elementNode.attributes['path'] = [start, end]
elementNode.attributes['tiltFollow'] = 'true'
elementNode.attributes['tiltTop'] = Vector3(0.0, 0.0, 1.0)
def setOffsetByMultiplier(begin, end, multiplier, offset):
'Set the offset by the multiplier.'
segment = end - begin
delta = segment * multiplier - segment
offset.setToVector3(offset + delta)
class ExtrudeDerivation(object):
'Class to hold extrude variables.'
def __init__(self, elementNode):
'Initialize.'
self.elementNode = elementNode
self.interpolationDictionary = {}
self.tiltFollow = evaluate.getEvaluatedBoolean(True, elementNode, 'tiltFollow')
self.tiltTop = evaluate.getVector3ByPrefix(None, elementNode, 'tiltTop')
self.maximumUnbuckling = evaluate.getEvaluatedFloat(5.0, elementNode, 'maximumUnbuckling')
scalePathDefault = [Vector3(1.0, 1.0, 0.0), Vector3(1.0, 1.0, 1.0)]
self.interpolationDictionary['scale'] = Interpolation().getByPrefixZ(elementNode, scalePathDefault, 'scale')
self.target = evaluate.getTransformedPathsByKey([], elementNode, 'target')
if self.tiltTop == None:
offsetPathDefault = [Vector3(), Vector3(0.0, 0.0, 1.0)]
self.interpolationDictionary['offset'] = Interpolation().getByPrefixZ(elementNode, offsetPathDefault, '')
tiltPathDefault = [Vector3(), Vector3(0.0, 0.0, 1.0)]
self.interpolationDictionary['tilt'] = Interpolation().getByPrefixZ(elementNode, tiltPathDefault, 'tilt')
for point in self.interpolationDictionary['tilt'].path:
point.x = math.radians(point.x)
point.y = math.radians(point.y)
else:
offsetAlongDefault = [Vector3(), Vector3(1.0, 0.0, 0.0)]
self.interpolationDictionary['offset'] = Interpolation().getByPrefixAlong(elementNode, offsetAlongDefault, '')
self.twist = evaluate.getEvaluatedFloat(0.0, elementNode, 'twist')
self.twistPathDefault = [Vector3(), Vector3(1.0, self.twist) ]
insertTwistPortions(self, elementNode)
class Interpolation(object):
'Class to interpolate a path.'
def __init__(self):
'Set index.'
self.interpolationIndex = 0
def __repr__(self):
'Get the string representation of this Interpolation.'
return str(self.__dict__)
def getByDistances(self):
'Get by distances.'
beginDistance = self.distances[0]
self.interpolationLength = self.distances[-1] - beginDistance
self.close = abs(0.000001 * self.interpolationLength)
self.portionDirections = []
oldDistance = -self.interpolationLength # so the difference should not be close
for distance in self.distances:
deltaDistance = distance - beginDistance
portionDirection = PortionDirection(deltaDistance / self.interpolationLength)
if abs(deltaDistance - oldDistance) < self.close:
portionDirection.directionReversed = True
self.portionDirections.append(portionDirection)
oldDistance = deltaDistance
return self
def getByPrefixAlong(self, elementNode, path, prefix):
'Get interpolation from prefix and xml element along the path.'
if len(path) < 2:
print('Warning, path is too small in evaluate in Interpolation.')
return
if elementNode == None:
self.path = path
else:
self.path = evaluate.getTransformedPathByPrefix(elementNode, path, prefix)
self.distances = [0.0]
previousPoint = self.path[0]
for point in self.path[1 :]:
distanceDifference = abs(point - previousPoint)
self.distances.append(self.distances[-1] + distanceDifference)
previousPoint = point
return self.getByDistances()
def getByPrefixX(self, elementNode, path, prefix):
'Get interpolation from prefix and xml element in the z direction.'
if len(path) < 2:
print('Warning, path is too small in evaluate in Interpolation.')
return
if elementNode == None:
self.path = path
else:
self.path = evaluate.getTransformedPathByPrefix(elementNode, path, prefix)
self.distances = []
for point in self.path:
self.distances.append(point.x)
return self.getByDistances()
def getByPrefixZ(self, elementNode, path, prefix):
'Get interpolation from prefix and xml element in the z direction.'
if len(path) < 2:
print('Warning, path is too small in evaluate in Interpolation.')
return
if elementNode == None:
self.path = path
else:
self.path = evaluate.getTransformedPathByPrefix(elementNode, path, prefix)
self.distances = []
for point in self.path:
self.distances.append(point.z)
return self.getByDistances()
def getComparison( self, first, second ):
'Compare the first with the second.'
if abs( second - first ) < self.close:
return 0
if second > first:
return 1
return - 1
def getComplexByPortion( self, portionDirection ):
'Get complex from z portion.'
self.setInterpolationIndexFromTo( portionDirection )
return self.oneMinusInnerPortion * self.startVertex.dropAxis() + self.innerPortion * self.endVertex.dropAxis()
def getInnerPortion(self):
'Get inner x portion.'
fromDistance = self.distances[ self.interpolationIndex ]
innerLength = self.distances[ self.interpolationIndex + 1 ] - fromDistance
if abs( innerLength ) == 0.0:
return 0.0
return ( self.absolutePortion - fromDistance ) / innerLength
def getVector3ByPortion( self, portionDirection ):
'Get vector3 from z portion.'
self.setInterpolationIndexFromTo( portionDirection )
return self.oneMinusInnerPortion * self.startVertex + self.innerPortion * self.endVertex
def getYByPortion( self, portionDirection ):
'Get y from x portion.'
self.setInterpolationIndexFromTo( portionDirection )
return self.oneMinusInnerPortion * self.startVertex.y + self.innerPortion * self.endVertex.y
def setInterpolationIndex( self, portionDirection ):
'Set the interpolation index.'
self.absolutePortion = self.distances[0] + self.interpolationLength * portionDirection.portion
interpolationIndexes = range( 0, len( self.distances ) - 1 )
if portionDirection.directionReversed:
interpolationIndexes.reverse()
for self.interpolationIndex in interpolationIndexes:
begin = self.distances[ self.interpolationIndex ]
end = self.distances[ self.interpolationIndex + 1 ]
if self.getComparison( begin, self.absolutePortion ) != self.getComparison( end, self.absolutePortion ):
return
def setInterpolationIndexFromTo( self, portionDirection ):
'Set the interpolation index, the start vertex and the end vertex.'
self.setInterpolationIndex( portionDirection )
self.innerPortion = self.getInnerPortion()
self.oneMinusInnerPortion = 1.0 - self.innerPortion
self.startVertex = self.path[ self.interpolationIndex ]
self.endVertex = self.path[ self.interpolationIndex + 1 ]
class PortionDirection(object):
'Class to hold a portion and direction.'
def __init__( self, portion ):
'Initialize.'
self.directionReversed = False
self.portion = portion
def __repr__(self):
'Get the string representation of this PortionDirection.'
return '%s: %s' % ( self.portion, self.directionReversed )

File diff suppressed because it is too large Load Diff

View File

@ -1,163 +0,0 @@
"""
Grid path points.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities import euclidean
import math
import random
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addGridRow(diameter, gridPath, loopsComplex, maximumComplex, rowIndex, x, y, zigzag):
'Add grid row.'
row = []
while x < maximumComplex.real:
point = complex(x, y)
if euclidean.getIsInFilledRegion(loopsComplex, point):
row.append(point)
x += diameter.real
if zigzag and rowIndex % 2 == 1:
row.reverse()
gridPath += row
def getGeometryOutput(elementNode):
'Get vector3 vertexes from attribute dictionary.'
derivation = GridDerivation(elementNode)
diameter = derivation.radius + derivation.radius
typeStringTwoCharacters = derivation.typeString.lower()[: 2]
typeStringFirstCharacter = typeStringTwoCharacters[: 1]
topRight = complex(derivation.demiwidth, derivation.demiheight)
loopsComplex = [euclidean.getSquareLoopWiddershins(-topRight, topRight)]
if len(derivation.target) > 0:
loopsComplex = euclidean.getComplexPaths(derivation.target)
maximumComplex = euclidean.getMaximumByComplexPaths(loopsComplex)
minimumComplex = euclidean.getMinimumByComplexPaths(loopsComplex)
gridPath = None
if typeStringTwoCharacters == 'he':
gridPath = getHexagonalGrid(diameter, loopsComplex, maximumComplex, minimumComplex, derivation.zigzag)
elif typeStringTwoCharacters == 'ra' or typeStringFirstCharacter == 'a':
gridPath = getRandomGrid(derivation, diameter, elementNode, loopsComplex, maximumComplex, minimumComplex)
elif typeStringTwoCharacters == 're' or typeStringFirstCharacter == 'e':
gridPath = getRectangularGrid(diameter, loopsComplex, maximumComplex, minimumComplex, derivation.zigzag)
if gridPath == None:
print('Warning, the step type was not one of (hexagonal, random or rectangular) in getGeometryOutput in grid for:')
print(derivation.typeString)
print(elementNode)
return []
loop = euclidean.getVector3Path(gridPath)
elementNode.attributes['closed'] = 'false'
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop(loop, 0.5 * math.pi))
def getGeometryOutputByArguments(arguments, elementNode):
'Get vector3 vertexes from attribute dictionary by arguments.'
if len(arguments) < 1:
return getGeometryOutput(elementNode)
inradius = 0.5 * euclidean.getFloatFromValue(arguments[0])
elementNode.attributes['inradius.x'] = str(inradius)
if len(arguments) > 1:
inradius = 0.5 * euclidean.getFloatFromValue(arguments[1])
elementNode.attributes['inradius.y'] = str(inradius)
return getGeometryOutput(elementNode)
def getHexagonalGrid(diameter, loopsComplex, maximumComplex, minimumComplex, zigzag):
'Get hexagonal grid.'
diameter = complex(diameter.real, math.sqrt(0.75) * diameter.imag)
demiradius = 0.25 * diameter
xRadius = 0.5 * diameter.real
xStart = minimumComplex.real - demiradius.real
y = minimumComplex.imag - demiradius.imag
gridPath = []
rowIndex = 0
while y < maximumComplex.imag:
x = xStart
if rowIndex % 2 == 1:
x -= xRadius
addGridRow(diameter, gridPath, loopsComplex, maximumComplex, rowIndex, x, y, zigzag)
y += diameter.imag
rowIndex += 1
return gridPath
def getIsPointInsideZoneAwayOthers(diameterReciprocal, loopsComplex, point, pixelDictionary):
'Determine if the point is inside the loops zone and and away from the other points.'
if not euclidean.getIsInFilledRegion(loopsComplex, point):
return False
pointOverDiameter = complex(point.real * diameterReciprocal.real, point.imag * diameterReciprocal.imag)
squareValues = euclidean.getSquareValuesFromPoint(pixelDictionary, pointOverDiameter)
for squareValue in squareValues:
if abs(squareValue - pointOverDiameter) < 1.0:
return False
euclidean.addElementToPixelListFromPoint(pointOverDiameter, pixelDictionary, pointOverDiameter)
return True
def getNewDerivation(elementNode):
'Get new derivation.'
return GridDerivation(elementNode)
def getRandomGrid(derivation, diameter, elementNode, loopsComplex, maximumComplex, minimumComplex):
'Get rectangular grid.'
gridPath = []
diameterReciprocal = complex(1.0 / diameter.real, 1.0 / diameter.imag)
diameterSquared = diameter.real * diameter.real + diameter.imag * diameter.imag
elements = int(math.ceil(derivation.density * euclidean.getAreaLoops(loopsComplex) / diameterSquared / math.sqrt(0.75)))
elements = evaluate.getEvaluatedInt(elements, elementNode, 'elements')
failedPlacementAttempts = 0
pixelDictionary = {}
if derivation.seed != None:
random.seed(derivation.seed)
successfulPlacementAttempts = 0
while failedPlacementAttempts < 100:
point = euclidean.getRandomComplex(minimumComplex, maximumComplex)
if getIsPointInsideZoneAwayOthers(diameterReciprocal, loopsComplex, point, pixelDictionary):
gridPath.append(point)
euclidean.addElementToPixelListFromPoint(point, pixelDictionary, point)
successfulPlacementAttempts += 1
else:
failedPlacementAttempts += 1
if successfulPlacementAttempts >= elements:
return gridPath
return gridPath
def getRectangularGrid(diameter, loopsComplex, maximumComplex, minimumComplex, zigzag):
'Get rectangular grid.'
demiradius = 0.25 * diameter
xStart = minimumComplex.real - demiradius.real
y = minimumComplex.imag - demiradius.imag
gridPath = []
rowIndex = 0
while y < maximumComplex.imag:
addGridRow(diameter, gridPath, loopsComplex, maximumComplex, rowIndex, xStart, y, zigzag)
y += diameter.imag
rowIndex += 1
return gridPath
def processElementNode(elementNode):
'Process the xml element.'
path.convertElementNode(elementNode, getGeometryOutput(elementNode))
class GridDerivation(object):
'Class to hold grid variables.'
def __init__(self, elementNode):
'Set defaults.'
self.inradius = lineation.getInradius(complex(10.0, 10.0), elementNode)
self.demiwidth = lineation.getFloatByPrefixBeginEnd(elementNode, 'demiwidth', 'width', self.inradius.real)
self.demiheight = lineation.getFloatByPrefixBeginEnd(elementNode, 'demiheight', 'height', self.inradius.imag)
self.density = evaluate.getEvaluatedFloat(0.2, elementNode, 'density')
self.radius = lineation.getComplexByPrefixBeginEnd(elementNode, 'elementRadius', 'elementDiameter', complex(1.0, 1.0))
self.radius = lineation.getComplexByPrefixBeginEnd(elementNode, 'radius', 'diameter', self.radius)
self.seed = evaluate.getEvaluatedInt(None, elementNode, 'seed')
self.target = evaluate.getTransformedPathsByKey([], elementNode, 'target')
self.typeMenuRadioStrings = 'hexagonal random rectangular'.split()
self.typeString = evaluate.getEvaluatedString('rectangular', elementNode, 'type')
self.zigzag = evaluate.getEvaluatedBoolean(True, elementNode, 'zigzag')

View File

@ -1,202 +0,0 @@
"""
Heightmap.
http://www.cs.otago.ac.nz/graphics/Mirage/node59.html
http://en.wikipedia.org/wiki/Heightmap
http://en.wikipedia.org/wiki/Netpbm_format
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities.vector3index import Vector3Index
from fabmetheus_utilities import archive
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addHeightsByBitmap(heights, textLines):
'Add heights by bitmap.'
for line in textLines[3:]:
for integerWord in line.split():
heights.append(float(integerWord))
def addHeightsByGraymap(heights, textLines):
'Add heights by graymap.'
divisor = float(textLines[3])
for line in textLines[4:]:
for integerWord in line.split():
heights.append(float(integerWord) / divisor)
def getAddIndexedHeightGrid(heightGrid, minimumXY, step, top, vertexes):
'Get and add an indexed heightGrid.'
indexedHeightGrid = []
for rowIndex, row in enumerate(heightGrid):
indexedRow = []
indexedHeightGrid.append(indexedRow)
rowOffset = step.imag * float(rowIndex) + minimumXY.imag
for columnIndex, element in enumerate(row):
columnOffset = step.real * float(columnIndex) + minimumXY.real
vector3index = Vector3Index(len(vertexes), columnOffset, rowOffset, top * element)
indexedRow.append(vector3index)
vertexes.append(vector3index)
return indexedHeightGrid
def getAddIndexedSegmentedPerimeter(heightGrid, maximumXY, minimumXY, step, vertexes, z=0.0):
'Get and add an indexed segmented perimeter.'
indexedSegmentedPerimeter = []
firstRow = heightGrid[0]
columnOffset = minimumXY.real
numberOfRowsMinusTwo = len(heightGrid) - 2
for column in firstRow:
vector3index = Vector3Index(len(vertexes), columnOffset, minimumXY.imag, z)
vertexes.append(vector3index)
indexedSegmentedPerimeter.append(vector3index)
columnOffset += step.real
rowOffset = minimumXY.imag
for rowIndex in xrange(numberOfRowsMinusTwo):
rowOffset += step.imag
vector3index = Vector3Index(len(vertexes), maximumXY.real, rowOffset, z)
vertexes.append(vector3index)
indexedSegmentedPerimeter.append(vector3index)
columnOffset = maximumXY.real
for column in firstRow:
vector3index = Vector3Index(len(vertexes), columnOffset, maximumXY.imag, z)
vertexes.append(vector3index)
indexedSegmentedPerimeter.append(vector3index)
columnOffset -= step.real
rowOffset = maximumXY.imag
for rowIndex in xrange(numberOfRowsMinusTwo):
rowOffset -= step.imag
vector3index = Vector3Index(len(vertexes), minimumXY.real, rowOffset, z)
vertexes.append(vector3index)
indexedSegmentedPerimeter.append(vector3index)
return indexedSegmentedPerimeter
def getGeometryOutput(elementNode):
'Get vector3 vertexes from attribute dictionary.'
derivation = HeightmapDerivation(elementNode)
heightGrid = derivation.heightGrid
if derivation.fileName != '':
heightGrid = getHeightGrid(archive.getAbsoluteFolderPath(elementNode.getOwnerDocument().fileName, derivation.fileName))
return getGeometryOutputByHeightGrid(derivation, elementNode, heightGrid)
def getGeometryOutputByArguments(arguments, elementNode):
'Get vector3 vertexes from attribute dictionary by arguments.'
evaluate.setAttributesByArguments(['file', 'start'], arguments, elementNode)
return getGeometryOutput(elementNode)
def getGeometryOutputByHeightGrid(derivation, elementNode, heightGrid):
'Get vector3 vertexes from attribute dictionary.'
numberOfColumns = len(heightGrid)
if numberOfColumns < 2:
print('Warning, in getGeometryOutputByHeightGrid in heightmap there are fewer than two rows for:')
print(heightGrid)
print(elementNode)
return None
numberOfRows = len(heightGrid[0])
if numberOfRows < 2:
print('Warning, in getGeometryOutputByHeightGrid in heightmap there are fewer than two columns for:')
print(heightGrid)
print(elementNode)
return None
for row in heightGrid:
if len(row) != numberOfRows:
print('Warning, in getGeometryOutputByHeightGrid in heightmap the heightgrid is not rectangular for:')
print(heightGrid)
print(elementNode)
return None
inradiusComplex = derivation.inradius.dropAxis()
minimumXY = -inradiusComplex
step = complex(derivation.inradius.x / float(numberOfRows - 1), derivation.inradius.y / float(numberOfColumns - 1))
step += step
faces = []
heightGrid = getRaisedHeightGrid(heightGrid, derivation.start)
top = derivation.inradius.z + derivation.inradius.z
vertexes = []
indexedBottomLoop = getAddIndexedSegmentedPerimeter(heightGrid, inradiusComplex, minimumXY, step, vertexes)
indexedLoops = [indexedBottomLoop]
indexedGridTop = getAddIndexedHeightGrid(heightGrid, minimumXY, step, top, vertexes)
indexedLoops.append(triangle_mesh.getIndexedLoopFromIndexedGrid(indexedGridTop))
vertexes = triangle_mesh.getUniqueVertexes(indexedLoops + indexedGridTop)
triangle_mesh.addPillarFromConvexLoopsGridTop(faces, indexedGridTop, indexedLoops)
return triangle_mesh.getGeometryOutputByFacesVertexes(faces, vertexes)
def getHeightGrid(fileName):
'Get heightGrid by fileName.'
if 'models/' not in fileName:
print('Warning, models/ was not in the absolute file path, so for security nothing will be done for:')
print(fileName)
print('The heightmap tool can only read a file which has models/ in the file path.')
print('To import the file, move the file into a folder called model/ or a subfolder which is inside the model folder tree.')
return
pgmText = archive.getFileText(fileName)
textLines = archive.getTextLines(pgmText)
format = textLines[0].lower()
sizeWords = textLines[2].split()
numberOfColumns = int(sizeWords[0])
numberOfRows = int(sizeWords[1])
heights = []
if format == 'p1':
addHeightsByBitmap(heights, textLines)
elif format == 'p2':
addHeightsByGraymap(heights, textLines)
else:
print('Warning, the file format was not recognized for:')
print(fileName)
print('Heightmap can only read the Netpbm Portable bitmap format and the Netpbm Portable graymap format.')
print('The Netpbm formats are described at:')
print('http://en.wikipedia.org/wiki/Netpbm_format')
return []
heightGrid = []
heightIndex = 0
for rowIndex in xrange(numberOfRows):
row = []
heightGrid.append(row)
for columnIndex in xrange(numberOfColumns):
row.append(heights[heightIndex])
heightIndex += 1
return heightGrid
def getNewDerivation(elementNode):
'Get new derivation.'
return HeightmapDerivation(elementNode)
def getRaisedHeightGrid(heightGrid, start):
'Get heightGrid raised above start.'
raisedHeightGrid = []
remainingHeight = 1.0 - start
for row in heightGrid:
raisedRow = []
raisedHeightGrid.append(raisedRow)
for element in row:
raisedElement = remainingHeight * element + start
raisedRow.append(raisedElement)
return raisedHeightGrid
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByGeometry(elementNode, getGeometryOutput(elementNode))
class HeightmapDerivation(object):
'Class to hold heightmap variables.'
def __init__(self, elementNode):
'Set defaults.'
self.fileName = evaluate.getEvaluatedString('', elementNode, 'file')
self.heightGrid = evaluate.getEvaluatedValue([], elementNode, 'heightGrid')
self.inradius = evaluate.getVector3ByPrefixes(elementNode, ['demisize', 'inradius'], Vector3(10.0, 10.0, 5.0))
self.inradius = evaluate.getVector3ByMultiplierPrefix(elementNode, 2.0, 'size', self.inradius)
self.start = evaluate.getEvaluatedFloat(0.0, elementNode, 'start')
def __repr__(self):
'Get the string representation of this HeightmapDerivation.'
return euclidean.getDictionaryString(self.__dict__)

View File

@ -1,173 +0,0 @@
"""
Boolean geometry extrusion.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addLoopByComplex(derivation, endMultiplier, loopLists, path, pointComplex, vertexes):
"Add an indexed loop to the vertexes."
loops = loopLists[-1]
loop = []
loops.append(loop)
for point in path:
pointMinusBegin = point - derivation.axisStart
dotVector3 = derivation.axisProjectiveSpace.getDotVector3(pointMinusBegin)
dotVector3Complex = dotVector3.dropAxis()
dotPointComplex = pointComplex * dotVector3Complex
dotPoint = Vector3(dotPointComplex.real, dotPointComplex.imag, dotVector3.z)
projectedVector3 = derivation.axisProjectiveSpace.getVector3ByPoint(dotPoint) + derivation.axisStart
loop.append(projectedVector3)
def addNegatives(derivation, negatives, paths):
"Add pillars output to negatives."
for path in paths:
loopListsByPath = getLoopListsByPath(derivation, 1.000001, path)
geometryOutput = triangle_mesh.getPillarsOutput(loopListsByPath)
negatives.append(geometryOutput)
def addNegativesPositives(derivation, negatives, paths, positives):
"Add pillars output to negatives and positives."
for path in paths:
endMultiplier = None
normal = euclidean.getNormalByPath(path)
if normal.dot(derivation.normal) < 0.0:
endMultiplier = 1.000001
loopListsByPath = getLoopListsByPath(derivation, endMultiplier, path)
geometryOutput = triangle_mesh.getPillarsOutput(loopListsByPath)
if endMultiplier == None:
positives.append(geometryOutput)
else:
negatives.append(geometryOutput)
def addOffsetAddToLists( loop, offset, vector3Index, vertexes ):
"Add an indexed loop to the vertexes."
vector3Index += offset
loop.append( vector3Index )
vertexes.append( vector3Index )
def addPositives(derivation, paths, positives):
"Add pillars output to positives."
for path in paths:
loopListsByPath = getLoopListsByPath(derivation, None, path)
geometryOutput = triangle_mesh.getPillarsOutput(loopListsByPath)
positives.append(geometryOutput)
def getGeometryOutput(derivation, elementNode):
"Get triangle mesh from attribute dictionary."
if derivation == None:
derivation = LatheDerivation(elementNode)
if len(euclidean.getConcatenatedList(derivation.target)) == 0:
print('Warning, in lathe there are no paths.')
print(elementNode.attributes)
return None
negatives = []
positives = []
addNegativesPositives(derivation, negatives, derivation.target, positives)
return getGeometryOutputByNegativesPositives(derivation, elementNode, negatives, positives)
def getGeometryOutputByArguments(arguments, elementNode):
"Get triangle mesh from attribute dictionary by arguments."
return getGeometryOutput(None, elementNode)
def getGeometryOutputByNegativesPositives(derivation, elementNode, negatives, positives):
"Get triangle mesh from derivation, elementNode, negatives and positives."
positiveOutput = triangle_mesh.getUnifiedOutput(positives)
if len(negatives) < 1:
return solid.getGeometryOutputByManipulation(elementNode, positiveOutput)
return solid.getGeometryOutputByManipulation(elementNode, {'difference' : {'shapes' : [positiveOutput] + negatives}})
def getLoopListsByPath(derivation, endMultiplier, path):
"Get loop lists from path."
vertexes = []
loopLists = [[]]
if len(derivation.loop) < 2:
return loopLists
for pointIndex, pointComplex in enumerate(derivation.loop):
if endMultiplier != None and not derivation.isEndCloseToStart:
if pointIndex == 0:
nextPoint = derivation.loop[1]
pointComplex = endMultiplier * (pointComplex - nextPoint) + nextPoint
elif pointIndex == len(derivation.loop) - 1:
previousPoint = derivation.loop[pointIndex - 1]
pointComplex = endMultiplier * (pointComplex - previousPoint) + previousPoint
addLoopByComplex(derivation, endMultiplier, loopLists, path, pointComplex, vertexes)
if derivation.isEndCloseToStart:
loopLists[-1].append([])
return loopLists
def getNewDerivation(elementNode):
'Get new derivation.'
return LatheDerivation(elementNode)
def processElementNode(elementNode):
"Process the xml element."
solid.processElementNodeByGeometry(elementNode, getGeometryOutput(None, elementNode))
class LatheDerivation(object):
"Class to hold lathe variables."
def __init__(self, elementNode):
'Set defaults.'
self.axisEnd = evaluate.getVector3ByPrefix(None, elementNode, 'axisEnd')
self.axisStart = evaluate.getVector3ByPrefix(None, elementNode, 'axisStart')
self.end = evaluate.getEvaluatedFloat(360.0, elementNode, 'end')
self.loop = evaluate.getTransformedPathByKey([], elementNode, 'loop')
self.sides = evaluate.getEvaluatedInt(None, elementNode, 'sides')
self.start = evaluate.getEvaluatedFloat(0.0, elementNode, 'start')
self.target = evaluate.getTransformedPathsByKey([], elementNode, 'target')
if len(self.target) < 1:
print('Warning, no target in derive in lathe for:')
print(elementNode)
return
firstPath = self.target[0]
if len(firstPath) < 3:
print('Warning, firstPath length is less than three in derive in lathe for:')
print(elementNode)
self.target = []
return
if self.axisStart == None:
if self.axisEnd == None:
self.axisStart = firstPath[0]
self.axisEnd = firstPath[-1]
else:
self.axisStart = Vector3()
self.axis = self.axisEnd - self.axisStart
axisLength = abs(self.axis)
if axisLength <= 0.0:
print('Warning, axisLength is zero in derive in lathe for:')
print(elementNode)
self.target = []
return
self.axis /= axisLength
firstVector3 = firstPath[1] - self.axisStart
firstVector3Length = abs(firstVector3)
if firstVector3Length <= 0.0:
print('Warning, firstVector3Length is zero in derive in lathe for:')
print(elementNode)
self.target = []
return
firstVector3 /= firstVector3Length
self.axisProjectiveSpace = euclidean.ProjectiveSpace().getByBasisZFirst(self.axis, firstVector3)
if self.sides == None:
distanceToLine = euclidean.getDistanceToLineByPaths(self.axisStart, self.axisEnd, self.target)
self.sides = evaluate.getSidesMinimumThreeBasedOnPrecisionSides(elementNode, distanceToLine)
endRadian = math.radians(self.end)
startRadian = math.radians(self.start)
self.isEndCloseToStart = euclidean.getIsRadianClose(endRadian, startRadian)
if len(self.loop) < 1:
self.loop = euclidean.getComplexPolygonByStartEnd(endRadian, 1.0, self.sides, startRadian)
self.normal = euclidean.getNormalByPath(firstPath)

View File

@ -1,101 +0,0 @@
"""
Square path.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutput(derivation, elementNode):
"Get vector3 vertexes from attribute dictionary."
if derivation == None:
derivation = LineDerivation(elementNode)
endMinusStart = derivation.end - derivation.start
endMinusStartLength = abs(endMinusStart)
if endMinusStartLength <= 0.0:
print('Warning, end is the same as start in getGeometryOutput in line for:')
print(derivation.start)
print(derivation.end)
print(elementNode)
return None
typeStringTwoCharacters = derivation.typeString.lower()[: 2]
elementNode.attributes['closed'] = str(derivation.closed)
if derivation.step == None and derivation.steps == None:
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop([derivation.start, derivation.end]))
loop = [derivation.start]
if derivation.step != None and derivation.steps != None:
stepVector = derivation.step / endMinusStartLength * endMinusStart
derivation.end = derivation.start + stepVector * derivation.steps
return getGeometryOutputByStep(elementNode, derivation.end, loop, derivation.steps, stepVector)
if derivation.step == None:
stepVector = endMinusStart / derivation.steps
return getGeometryOutputByStep(elementNode, derivation.end, loop, derivation.steps, stepVector)
endMinusStartLengthOverStep = endMinusStartLength / derivation.step
if typeStringTwoCharacters == 'av':
derivation.steps = max(1.0, round(endMinusStartLengthOverStep))
stepVector = derivation.step / endMinusStartLength * endMinusStart
derivation.end = derivation.start + stepVector * derivation.steps
return getGeometryOutputByStep(elementNode, derivation.end, loop, derivation.steps, stepVector)
if typeStringTwoCharacters == 'ma':
derivation.steps = math.ceil(endMinusStartLengthOverStep)
if derivation.steps < 1.0:
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop([derivation.start, derivation.end]))
stepVector = endMinusStart / derivation.steps
return getGeometryOutputByStep(elementNode, derivation.end, loop, derivation.steps, stepVector)
if typeStringTwoCharacters == 'mi':
derivation.steps = math.floor(endMinusStartLengthOverStep)
if derivation.steps < 1.0:
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop(loop))
stepVector = endMinusStart / derivation.steps
return getGeometryOutputByStep(elementNode, derivation.end, loop, derivation.steps, stepVector)
print('Warning, the step type was not one of (average, maximum or minimum) in getGeometryOutput in line for:')
print(derivation.typeString)
print(elementNode)
loop.append(derivation.end)
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop(loop))
def getGeometryOutputByArguments(arguments, elementNode):
"Get vector3 vertexes from attribute dictionary by arguments."
evaluate.setAttributesByArguments(['start', 'end', 'step'], arguments, elementNode)
return getGeometryOutput(None, elementNode)
def getGeometryOutputByStep(elementNode, end, loop, steps, stepVector):
"Get line geometry output by the end, loop, steps and stepVector."
stepsFloor = int(math.floor(abs(steps)))
for stepIndex in xrange(1, stepsFloor):
loop.append(loop[stepIndex - 1] + stepVector)
loop.append(end)
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop(loop))
def getNewDerivation(elementNode):
'Get new derivation.'
return LineDerivation(elementNode)
def processElementNode(elementNode):
"Process the xml element."
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
class LineDerivation(object):
"Class to hold line variables."
def __init__(self, elementNode):
'Set defaults.'
self.closed = evaluate.getEvaluatedBoolean(False, elementNode, 'closed')
self.end = evaluate.getVector3ByPrefix(Vector3(), elementNode, 'end')
self.start = evaluate.getVector3ByPrefix(Vector3(), elementNode, 'start')
self.step = evaluate.getEvaluatedFloat(None, elementNode, 'step')
self.steps = evaluate.getEvaluatedFloat(None, elementNode, 'steps')
self.typeMenuRadioStrings = 'average maximum minimum'.split()
self.typeString = evaluate.getEvaluatedString('minimum', elementNode, 'type')

View File

@ -1,245 +0,0 @@
"""
Linear bearing cage.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import extrude
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.creation import peg
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities.geometry.manipulation_matrix import translate
from fabmetheus_utilities.geometry.solids import cylinder
from fabmetheus_utilities.geometry.solids import sphere
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addAssemblyCage(derivation, negatives, positives):
'Add assembly linear bearing cage.'
addCageGroove(derivation, negatives, positives)
for pegCenterX in derivation.pegCenterXs:
addPositivePeg(derivation, positives, pegCenterX, -derivation.pegY)
addPositivePeg(derivation, positives, pegCenterX, derivation.pegY)
translate.translateNegativesPositives(negatives, positives, Vector3(0.0, -derivation.halfSeparationWidth))
femaleNegatives = []
femalePositives = []
addCageGroove(derivation, femaleNegatives, femalePositives)
for pegCenterX in derivation.pegCenterXs:
addNegativePeg(derivation, femaleNegatives, pegCenterX, -derivation.pegY)
addNegativePeg(derivation, femaleNegatives, pegCenterX, derivation.pegY)
translate.translateNegativesPositives(femaleNegatives, femalePositives, Vector3(0.0, derivation.halfSeparationWidth))
negatives += femaleNegatives
positives += femalePositives
def addCage(derivation, height, negatives, positives):
'Add linear bearing cage.'
copyShallow = derivation.elementNode.getCopyShallow()
copyShallow.attributes['path'] = [Vector3(), Vector3(0.0, 0.0, height)]
extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
roundedExtendedRectangle = getRoundedExtendedRectangle(derivation.demiwidth, derivation.rectangleCenterX, 14)
outsidePath = euclidean.getVector3Path(roundedExtendedRectangle)
extrude.addPositives(extrudeDerivation, [outsidePath], positives)
for bearingCenterX in derivation.bearingCenterXs:
addNegativeSphere(derivation, negatives, bearingCenterX)
def addCageGroove(derivation, negatives, positives):
'Add cage and groove.'
addCage(derivation, derivation.demiheight, negatives, positives)
addGroove(derivation, negatives)
def addGroove(derivation, negatives):
'Add groove on each side of cage.'
copyShallow = derivation.elementNode.getCopyShallow()
extrude.setElementNodeToEndStart(copyShallow, Vector3(-derivation.demilength), Vector3(derivation.demilength))
extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
bottom = derivation.demiheight - 0.5 * derivation.grooveWidth
outside = derivation.demiwidth
top = derivation.demiheight
leftGroove = [
complex(-outside, bottom),
complex(-derivation.innerDemiwidth, derivation.demiheight),
complex(-outside, top)]
rightGroove = [
complex(outside, top),
complex(derivation.innerDemiwidth, derivation.demiheight),
complex(outside, bottom)]
extrude.addNegatives(extrudeDerivation, negatives, euclidean.getVector3Paths([leftGroove, rightGroove]))
def addNegativePeg(derivation, negatives, x, y):
'Add negative cylinder at x and y.'
negativePegRadius = derivation.pegRadiusArealized + derivation.halfPegClearance
inradius = complex(negativePegRadius, negativePegRadius)
copyShallow = derivation.elementNode.getCopyShallow()
start = Vector3(x, y, derivation.height)
sides = evaluate.getSidesMinimumThreeBasedOnPrecision(copyShallow, negativePegRadius)
cylinder.addCylinderOutputByEndStart(0.0, inradius, negatives, sides, start, derivation.topOverBottom)
def addNegativeSphere(derivation, negatives, x):
'Add negative sphere at x.'
radius = Vector3(derivation.radiusPlusClearance, derivation.radiusPlusClearance, derivation.radiusPlusClearance)
sphereOutput = sphere.getGeometryOutput(derivation.elementNode.getCopyShallow(), radius)
euclidean.translateVector3Path(matrix.getVertexes(sphereOutput), Vector3(x, 0.0, derivation.demiheight))
negatives.append(sphereOutput)
def addPositivePeg(derivation, positives, x, y):
'Add positive cylinder at x and y.'
positivePegRadius = derivation.pegRadiusArealized - derivation.halfPegClearance
radiusArealized = complex(positivePegRadius, positivePegRadius)
copyShallow = derivation.elementNode.getCopyShallow()
start = Vector3(x, y, derivation.demiheight)
endZ = derivation.height
peg.addPegOutput(derivation.pegBevel, endZ, positives, radiusArealized, derivation.sides, start, derivation.topOverBottom)
def getBearingCenterXs(bearingCenterX, numberOfSteps, stepX):
'Get the bearing center x list.'
bearingCenterXs = []
for stepIndex in xrange(numberOfSteps + 1):
bearingCenterXs.append(bearingCenterX)
bearingCenterX += stepX
return bearingCenterXs
def getGeometryOutput(elementNode):
'Get vector3 vertexes from attribute dictionary.'
derivation = LinearBearingCageDerivation(elementNode)
negatives = []
positives = []
if derivation.typeStringFirstCharacter == 'a':
addAssemblyCage(derivation, negatives, positives)
else:
addCage(derivation, derivation.height, negatives, positives)
return extrude.getGeometryOutputByNegativesPositives(elementNode, negatives, positives)
def getGeometryOutputByArguments(arguments, elementNode):
'Get vector3 vertexes from attribute dictionary by arguments.'
evaluate.setAttributesByArguments(['length', 'radius'], arguments, elementNode)
return getGeometryOutput(elementNode)
def getNewDerivation(elementNode):
'Get new derivation.'
return LinearBearingCageDerivation(elementNode)
def getPegCenterXs(numberOfSteps, pegCenterX, stepX):
'Get the peg center x list.'
pegCenterXs = []
for stepIndex in xrange(numberOfSteps):
pegCenterXs.append(pegCenterX)
pegCenterX += stepX
return pegCenterXs
def getRoundedExtendedRectangle(radius, rectangleCenterX, sides):
'Get the rounded extended rectangle.'
roundedExtendedRectangle = []
halfSides = int(sides / 2)
halfSidesPlusOne = abs(halfSides + 1)
sideAngle = math.pi / float(halfSides)
extensionMultiplier = 1.0 / math.cos(0.5 * sideAngle)
center = complex(rectangleCenterX, 0.0)
startAngle = 0.5 * math.pi
for halfSide in xrange(halfSidesPlusOne):
unitPolar = euclidean.getWiddershinsUnitPolar(startAngle)
unitPolarExtended = complex(unitPolar.real * extensionMultiplier, unitPolar.imag)
roundedExtendedRectangle.append(unitPolarExtended * radius + center)
startAngle += sideAngle
center = complex(-rectangleCenterX, 0.0)
startAngle = -0.5 * math.pi
for halfSide in xrange(halfSidesPlusOne):
unitPolar = euclidean.getWiddershinsUnitPolar(startAngle)
unitPolarExtended = complex(unitPolar.real * extensionMultiplier, unitPolar.imag)
roundedExtendedRectangle.append(unitPolarExtended * radius + center)
startAngle += sideAngle
return roundedExtendedRectangle
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByGeometry(elementNode, getGeometryOutput(elementNode))
class LinearBearingCageDerivation(object):
'Class to hold linear bearing cage variables.'
def __init__(self, elementNode):
'Set defaults.'
self.length = evaluate.getEvaluatedFloat(50.0, elementNode, 'length')
self.demilength = 0.5 * self.length
self.elementNode = elementNode
self.radius = lineation.getFloatByPrefixBeginEnd(elementNode, 'radius', 'diameter', 5.0)
self.cageClearanceOverRadius = evaluate.getEvaluatedFloat(0.05, elementNode, 'cageClearanceOverRadius')
self.cageClearance = self.cageClearanceOverRadius * self.radius
self.cageClearance = evaluate.getEvaluatedFloat(self.cageClearance, elementNode, 'cageClearance')
self.racewayClearanceOverRadius = evaluate.getEvaluatedFloat(0.1, elementNode, 'racewayClearanceOverRadius')
self.racewayClearance = self.racewayClearanceOverRadius * self.radius
self.racewayClearance = evaluate.getEvaluatedFloat(self.racewayClearance, elementNode, 'racewayClearance')
self.typeMenuRadioStrings = 'assembly integral'.split()
self.typeString = evaluate.getEvaluatedString('assembly', elementNode, 'type')
self.typeStringFirstCharacter = self.typeString[: 1 ].lower()
self.wallThicknessOverRadius = evaluate.getEvaluatedFloat(0.5, elementNode, 'wallThicknessOverRadius')
self.wallThickness = self.wallThicknessOverRadius * self.radius
self.wallThickness = evaluate.getEvaluatedFloat(self.wallThickness, elementNode, 'wallThickness')
self.zenithAngle = evaluate.getEvaluatedFloat(45.0, elementNode, 'zenithAngle')
self.zenithRadian = math.radians(self.zenithAngle)
self.demiheight = self.radius * math.cos(self.zenithRadian) - self.racewayClearance
self.height = self.demiheight + self.demiheight
self.radiusPlusClearance = self.radius + self.cageClearance
self.cageRadius = self.radiusPlusClearance + self.wallThickness
self.demiwidth = self.cageRadius
self.bearingCenterX = self.cageRadius - self.demilength
separation = self.cageRadius + self.radiusPlusClearance
bearingLength = -self.bearingCenterX - self.bearingCenterX
self.numberOfSteps = int(math.floor(bearingLength / separation))
self.stepX = bearingLength / float(self.numberOfSteps)
self.bearingCenterXs = getBearingCenterXs(self.bearingCenterX, self.numberOfSteps, self.stepX)
if self.typeStringFirstCharacter == 'a':
self.setAssemblyCage()
self.rectangleCenterX = self.demiwidth - self.demilength
def setAssemblyCage(self):
'Set two piece assembly parameters.'
self.grooveDepthOverRadius = evaluate.getEvaluatedFloat(0.15, self.elementNode, 'grooveDepthOverRadius')
self.grooveDepth = self.grooveDepthOverRadius * self.radius
self.grooveDepth = evaluate.getEvaluatedFloat(self.grooveDepth, self.elementNode, 'grooveDepth')
self.grooveWidthOverRadius = evaluate.getEvaluatedFloat(0.6, self.elementNode, 'grooveWidthOverRadius')
self.grooveWidth = self.grooveWidthOverRadius * self.radius
self.grooveWidth = evaluate.getEvaluatedFloat(self.grooveWidth, self.elementNode, 'grooveWidth')
self.pegClearanceOverRadius = evaluate.getEvaluatedFloat(0.0, self.elementNode, 'pegClearanceOverRadius')
self.pegClearance = self.pegClearanceOverRadius * self.radius
self.pegClearance = evaluate.getEvaluatedFloat(self.pegClearance, self.elementNode, 'pegClearance')
self.halfPegClearance = 0.5 * self.pegClearance
self.pegRadiusOverRadius = evaluate.getEvaluatedFloat(0.5, self.elementNode, 'pegRadiusOverRadius')
self.pegRadius = self.pegRadiusOverRadius * self.radius
self.pegRadius = evaluate.getEvaluatedFloat(self.pegRadius, self.elementNode, 'pegRadius')
self.sides = evaluate.getSidesMinimumThreeBasedOnPrecision(self.elementNode, self.pegRadius)
self.pegRadiusArealized = evaluate.getRadiusArealizedBasedOnAreaRadius(self.elementNode, self.pegRadius, self.sides)
self.pegBevelOverPegRadius = evaluate.getEvaluatedFloat(0.25, self.elementNode, 'pegBevelOverPegRadius')
self.pegBevel = self.pegBevelOverPegRadius * self.pegRadiusArealized
self.pegBevel = evaluate.getEvaluatedFloat(self.pegBevel, self.elementNode, 'pegBevel')
self.pegMaximumRadius = self.pegRadiusArealized + abs(self.halfPegClearance)
self.separationOverRadius = evaluate.getEvaluatedFloat(0.5, self.elementNode, 'separationOverRadius')
self.separation = self.separationOverRadius * self.radius
self.separation = evaluate.getEvaluatedFloat(self.separation, self.elementNode, 'separation')
self.topOverBottom = evaluate.getEvaluatedFloat(0.8, self.elementNode, 'topOverBottom')
peg.setTopOverBottomByRadius(self, 0.0, self.pegRadiusArealized, self.height)
self.quarterHeight = 0.5 * self.demiheight
self.pegY = 0.5 * self.wallThickness + self.pegMaximumRadius
cagePegRadius = self.cageRadius + self.pegMaximumRadius
halfStepX = 0.5 * self.stepX
pegHypotenuse = math.sqrt(self.pegY * self.pegY + halfStepX * halfStepX)
if cagePegRadius > pegHypotenuse:
self.pegY = math.sqrt(cagePegRadius * cagePegRadius - halfStepX * halfStepX)
self.demiwidth = max(self.pegY + self.pegMaximumRadius + self.wallThickness, self.demiwidth)
self.innerDemiwidth = self.demiwidth
self.demiwidth += self.grooveDepth
self.halfSeparationWidth = self.demiwidth + 0.5 * self.separation
if self.pegRadiusArealized <= 0.0:
self.pegCenterXs = []
else:
self.pegCenterXs = getPegCenterXs(self.numberOfSteps, self.bearingCenterX + halfStepX, self.stepX)

View File

@ -1,305 +0,0 @@
"""
Polygon path.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getComplexByDictionary(dictionary, valueComplex):
'Get complex by dictionary.'
if 'x' in dictionary:
valueComplex = complex(euclidean.getFloatFromValue(dictionary['x']),valueComplex.imag)
if 'y' in dictionary:
valueComplex = complex(valueComplex.real, euclidean.getFloatFromValue(dictionary['y']))
return valueComplex
def getComplexByDictionaryListValue(value, valueComplex):
'Get complex by dictionary, list or value.'
if value.__class__ == complex:
return value
if value.__class__ == dict:
return getComplexByDictionary(value, valueComplex)
if value.__class__ == list:
return getComplexByFloatList(value, valueComplex)
floatFromValue = euclidean.getFloatFromValue(value)
if floatFromValue == None:
return valueComplex
return complex( floatFromValue, floatFromValue )
def getComplexByFloatList( floatList, valueComplex ):
'Get complex by float list.'
if len(floatList) > 0:
valueComplex = complex(euclidean.getFloatFromValue(floatList[0]), valueComplex.imag)
if len(floatList) > 1:
valueComplex = complex(valueComplex.real, euclidean.getFloatFromValue(floatList[1]))
return valueComplex
def getComplexByMultiplierPrefix(elementNode, multiplier, prefix, valueComplex):
'Get complex from multiplier, prefix and xml element.'
if multiplier == 0.0:
return valueComplex
oldMultipliedValueComplex = valueComplex * multiplier
complexByPrefix = getComplexByPrefix(elementNode, prefix, oldMultipliedValueComplex)
if complexByPrefix == oldMultipliedValueComplex:
return valueComplex
return complexByPrefix / multiplier
def getComplexByMultiplierPrefixes(elementNode, multiplier, prefixes, valueComplex):
'Get complex from multiplier, prefixes and xml element.'
for prefix in prefixes:
valueComplex = getComplexByMultiplierPrefix(elementNode, multiplier, prefix, valueComplex)
return valueComplex
def getComplexByPrefix(elementNode, prefix, valueComplex):
'Get complex from prefix and xml element.'
value = evaluate.getEvaluatedValue(None, elementNode, prefix)
if value != None:
valueComplex = getComplexByDictionaryListValue(value, valueComplex)
x = evaluate.getEvaluatedFloat(None, elementNode, prefix + '.x')
if x != None:
valueComplex = complex( x, getComplexIfNone( valueComplex ).imag )
y = evaluate.getEvaluatedFloat(None, elementNode, prefix + '.y')
if y != None:
valueComplex = complex( getComplexIfNone( valueComplex ).real, y )
return valueComplex
def getComplexByPrefixBeginEnd(elementNode, prefixBegin, prefixEnd, valueComplex):
'Get complex from element node, prefixBegin and prefixEnd.'
valueComplex = getComplexByPrefix(elementNode, prefixBegin, valueComplex)
if prefixEnd in elementNode.attributes:
return 0.5 * getComplexByPrefix(elementNode, valueComplex + valueComplex, prefixEnd)
else:
return valueComplex
def getComplexByPrefixes(elementNode, prefixes, valueComplex):
'Get complex from prefixes and xml element.'
for prefix in prefixes:
valueComplex = getComplexByPrefix(elementNode, prefix, valueComplex)
return valueComplex
def getComplexIfNone( valueComplex ):
'Get new complex if the original complex is none.'
if valueComplex == None:
return complex()
return valueComplex
def getFloatByPrefixBeginEnd(elementNode, prefixBegin, prefixEnd, valueFloat):
'Get float from prefixBegin, prefixEnd and xml element.'
valueFloat = evaluate.getEvaluatedFloat(valueFloat, elementNode, prefixBegin)
if prefixEnd in elementNode.attributes:
return 0.5 * evaluate.getEvaluatedFloat(valueFloat + valueFloat, elementNode, prefixEnd)
return valueFloat
def getFloatByPrefixSide(defaultValue, elementNode, prefix, side):
'Get float by prefix and side.'
if elementNode == None:
return defaultValue
if side != None:
key = prefix + 'OverSide'
if key in elementNode.attributes:
defaultValue = euclidean.getFloatFromValue(evaluate.getEvaluatedValueObliviously(elementNode, key)) * side
return evaluate.getEvaluatedFloat(defaultValue, elementNode, prefix)
def getGeometryOutput(derivation, elementNode):
'Get geometry output from paths.'
if derivation == None:
derivation = LineationDerivation(elementNode)
geometryOutput = []
for path in derivation.target:
sideLoop = SideLoop(path)
geometryOutput += getGeometryOutputByLoop(elementNode, sideLoop)
return geometryOutput
def getGeometryOutputByArguments(arguments, elementNode):
'Get vector3 vertexes from attribute dictionary by arguments.'
return getGeometryOutput(None, elementNode)
def getGeometryOutputByLoop(elementNode, sideLoop):
'Get geometry output by side loop.'
sideLoop.rotate(elementNode)
return getGeometryOutputByManipulation(elementNode, sideLoop)
def getGeometryOutputByManipulation(elementNode, sideLoop):
'Get geometry output by manipulation.'
sideLoop.loop = euclidean.getLoopWithoutCloseSequentialPoints( sideLoop.close, sideLoop.loop )
return sideLoop.getManipulationPluginLoops(elementNode)
def getInradius(defaultInradius, elementNode):
'Get inradius.'
defaultInradius = getComplexByPrefixes(elementNode, ['demisize', 'inradius'], defaultInradius)
return getComplexByMultiplierPrefix(elementNode, 2.0, 'size', defaultInradius)
def getMinimumRadius(beginComplexSegmentLength, endComplexSegmentLength, radius):
'Get minimum radius.'
return min(abs(radius), 0.5 * min(beginComplexSegmentLength, endComplexSegmentLength))
def getNewDerivation(elementNode):
'Get new derivation.'
return LineationDerivation(elementNode)
def getNumberOfBezierPoints(begin, elementNode, end):
'Get the numberOfBezierPoints.'
numberOfBezierPoints = int(math.ceil(0.5 * evaluate.getSidesMinimumThreeBasedOnPrecision(elementNode, abs(end - begin))))
return evaluate.getEvaluatedInt(numberOfBezierPoints, elementNode, 'sides')
def getPackedGeometryOutputByLoop(elementNode, sideLoop):
'Get packed geometry output by side loop.'
sideLoop.rotate(elementNode)
return getGeometryOutputByManipulation(elementNode, sideLoop)
def getRadiusAverage(radiusComplex):
'Get average radius from radiusComplex.'
return math.sqrt(radiusComplex.real * radiusComplex.imag)
def getRadiusComplex(elementNode, radius):
'Get radius complex for elementNode.'
radius = getComplexByPrefixes(elementNode, ['demisize', 'radius'], radius)
return getComplexByMultiplierPrefixes(elementNode, 2.0, ['diameter', 'size'], radius)
def getStrokeRadiusByPrefix(elementNode, prefix):
'Get strokeRadius by prefix.'
strokeRadius = getFloatByPrefixBeginEnd(elementNode, prefix + 'strokeRadius', prefix + 'strokeWidth', 1.0)
return getFloatByPrefixBeginEnd(elementNode, prefix + 'radius', prefix + 'diameter', strokeRadius)
def processElementNode(elementNode):
'Process the xml element.'
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
def processElementNodeByFunction(elementNode, manipulationFunction):
'Process the xml element by the manipulationFunction.'
elementAttributesCopy = elementNode.attributes.copy()
targets = evaluate.getElementNodesByKey(elementNode, 'target')
for target in targets:
targetAttributesCopy = target.attributes.copy()
target.attributes = elementAttributesCopy
processTargetByFunction(manipulationFunction, target)
target.attributes = targetAttributesCopy
def processTargetByFunction(manipulationFunction, target):
'Process the target by the manipulationFunction.'
if target.xmlObject == None:
print('Warning, there is no object in processTargetByFunction in lineation for:')
print(target)
return
geometryOutput = []
transformedPaths = target.xmlObject.getTransformedPaths()
for transformedPath in transformedPaths:
sideLoop = SideLoop(transformedPath)
sideLoop.rotate(target)
sideLoop.loop = euclidean.getLoopWithoutCloseSequentialPoints( sideLoop.close, sideLoop.loop )
geometryOutput += manipulationFunction(sideLoop.close, target, sideLoop.loop, '', sideLoop.sideLength)
if len(geometryOutput) < 1:
print('Warning, there is no geometryOutput in processTargetByFunction in lineation for:')
print(target)
return
removeChildNodesFromElementObject(target)
path.convertElementNode(target, geometryOutput)
def removeChildNodesFromElementObject(elementNode):
'Process the xml element by manipulationFunction.'
elementNode.removeChildNodesFromIDNameParent()
if elementNode.xmlObject != None:
if elementNode.parentNode.xmlObject != None:
if elementNode.xmlObject in elementNode.parentNode.xmlObject.archivableObjects:
elementNode.parentNode.xmlObject.archivableObjects.remove(elementNode.xmlObject)
def setClosedAttribute(elementNode, revolutions):
'Set the closed attribute of the elementNode.'
closedBoolean = evaluate.getEvaluatedBoolean(revolutions <= 1, elementNode, 'closed')
elementNode.attributes['closed'] = str(closedBoolean).lower()
class LineationDerivation(object):
'Class to hold lineation variables.'
def __init__(self, elementNode):
'Set defaults.'
self.target = evaluate.getTransformedPathsByKey([], elementNode, 'target')
class SideLoop(object):
'Class to handle loop, side angle and side length.'
def __init__(self, loop, sideAngle=None, sideLength=None):
'Initialize.'
if sideAngle == None:
if len(loop) > 0:
sideAngle = 2.0 * math.pi / float(len(loop))
else:
sideAngle = 1.0
print('Warning, loop has no sides in SideLoop in lineation.')
if sideLength == None:
if len(loop) > 0:
sideLength = euclidean.getLoopLength(loop) / float(len(loop))
else:
sideLength = 1.0
print('Warning, loop has no length in SideLoop in lineation.')
self.loop = loop
self.sideAngle = abs(sideAngle)
self.sideLength = abs(sideLength)
self.close = 0.001 * sideLength
def getManipulationPluginLoops(self, elementNode):
'Get loop manipulated by the plugins in the manipulation paths folder.'
xmlProcessor = elementNode.getXMLProcessor()
matchingPlugins = evaluate.getMatchingPlugins(elementNode, xmlProcessor.manipulationMatrixDictionary)
matchingPlugins += evaluate.getMatchingPlugins(elementNode, xmlProcessor.manipulationPathDictionary)
matchingPlugins += evaluate.getMatchingPlugins(elementNode, xmlProcessor.manipulationShapeDictionary)
matchingPlugins.sort(evaluate.compareExecutionOrderAscending)
loops = [self.loop]
for matchingPlugin in matchingPlugins:
matchingLoops = []
prefix = matchingPlugin.__name__.replace('_', '') + '.'
for loop in loops:
matchingLoops += matchingPlugin.getManipulatedPaths(self.close, elementNode, loop, prefix, self.sideLength)
loops = matchingLoops
return loops
def rotate(self, elementNode):
'Rotate.'
rotation = math.radians(evaluate.getEvaluatedFloat(0.0, elementNode, 'rotation'))
rotation += evaluate.getEvaluatedFloat(0.0, elementNode, 'rotationOverSide') * self.sideAngle
if rotation != 0.0:
planeRotation = euclidean.getWiddershinsUnitPolar( rotation )
for vertex in self.loop:
rotatedComplex = vertex.dropAxis() * planeRotation
vertex.x = rotatedComplex.real
vertex.y = rotatedComplex.imag
if 'clockwise' in elementNode.attributes:
isClockwise = euclidean.getBooleanFromValue(evaluate.getEvaluatedValueObliviously(elementNode, 'clockwise'))
if isClockwise == euclidean.getIsWiddershinsByVector3( self.loop ):
self.loop.reverse()
class Spiral(object):
'Class to add a spiral.'
def __init__(self, spiral, stepRatio):
'Initialize.'
self.spiral = spiral
if self.spiral == None:
return
self.spiralIncrement = self.spiral * stepRatio
self.spiralTotal = Vector3()
def __repr__(self):
'Get the string representation of this Spiral.'
return self.spiral
def getSpiralPoint(self, unitPolar, vector3):
'Add spiral to the vector.'
if self.spiral == None:
return vector3
vector3 += Vector3(unitPolar.real * self.spiralTotal.x, unitPolar.imag * self.spiralTotal.y, self.spiralTotal.z)
self.spiralTotal += self.spiralIncrement
return vector3

View File

@ -1,255 +0,0 @@
"""
Mechaslab.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import extrude
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.creation import peg
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import cylinder
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addAlongWay(begin, distance, end, loop):
'Get the beveled rectangle.'
endMinusBegin = end - begin
endMinusBeginLength = abs(endMinusBegin)
if endMinusBeginLength <= 0.0:
return
alongWayMultiplier = distance / endMinusBeginLength
loop.append(begin + alongWayMultiplier * endMinusBegin)
def addGroove(derivation, negatives):
'Add groove on each side of cage.'
copyShallow = derivation.elementNode.getCopyShallow()
extrude.setElementNodeToEndStart(copyShallow, Vector3(-derivation.demilength), Vector3(derivation.demilength))
extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
bottom = derivation.demiheight - 0.5 * derivation.grooveWidth
outside = derivation.demiwidth
top = derivation.demiheight
leftGroove = [
complex(-outside, bottom),
complex(-derivation.innerDemiwidth, derivation.demiheight),
complex(-outside, top)]
rightGroove = [
complex(outside, top),
complex(derivation.innerDemiwidth, derivation.demiheight),
complex(outside, bottom)]
groovesComplex = [leftGroove, rightGroove]
groovesVector3 = euclidean.getVector3Paths(groovesComplex)
extrude.addPositives(extrudeDerivation, groovesVector3, negatives)
def addHollowPegSocket(derivation, hollowPegSocket, negatives, positives):
'Add the socket and hollow peg.'
pegHeight = derivation.pegHeight
pegRadians = derivation.pegRadians
pegRadiusComplex = complex(derivation.pegRadiusArealized, derivation.pegRadiusArealized)
pegTip = 0.8 * derivation.pegRadiusArealized
sides = derivation.pegSides
start = Vector3(hollowPegSocket.center.real, hollowPegSocket.center.imag, derivation.height)
tinyHeight = 0.0001 * pegHeight
topRadians = 0.25 * math.pi
boltTop = derivation.height
if hollowPegSocket.shouldAddPeg:
boltTop = peg.getTopAddBiconicOutput(
pegRadians, pegHeight, positives, pegRadiusComplex, sides, start, pegTip, topRadians)
sides = derivation.socketSides
socketHeight = 1.05 * derivation.pegHeight
socketRadiusComplex = complex(derivation.socketRadiusArealized, derivation.socketRadiusArealized)
socketTip = 0.5 * derivation.overhangSpan
start = Vector3(hollowPegSocket.center.real, hollowPegSocket.center.imag, -tinyHeight)
topRadians = derivation.interiorOverhangRadians
if hollowPegSocket.shouldAddSocket:
peg.getTopAddBiconicOutput(pegRadians, socketHeight, negatives, socketRadiusComplex, sides, start, socketTip, topRadians)
if derivation.boltRadius <= 0.0:
return
if (not hollowPegSocket.shouldAddPeg) and (not hollowPegSocket.shouldAddSocket):
return
boltRadiusComplex = complex(derivation.boltRadius, derivation.boltRadius)
cylinder.addCylinderOutputByEndStart(boltTop + tinyHeight, boltRadiusComplex, negatives, derivation.boltSides, start)
def addSlab(derivation, positives):
'Add slab.'
copyShallow = derivation.elementNode.getCopyShallow()
copyShallow.attributes['path'] = [Vector3(), Vector3(0.0, 0.0, derivation.height)]
extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
beveledRectangle = getBeveledRectangle(derivation.bevel, -derivation.topRight)
outsidePath = euclidean.getVector3Path(beveledRectangle)
extrude.addPositives(extrudeDerivation, [outsidePath], positives)
def addXGroove(derivation, negatives, y):
'Add x groove.'
if derivation.topBevel <= 0.0:
return
bottom = derivation.height - derivation.topBevel
top = derivation.height
groove = [complex(y, bottom), complex(y - derivation.topBevel, top), complex(y + derivation.topBevel, top)]
triangle_mesh.addSymmetricXPath(negatives, groove, 1.0001 * derivation.topRight.real)
def addYGroove(derivation, negatives, x):
'Add y groove'
if derivation.topBevel <= 0.0:
return
bottom = derivation.height - derivation.topBevel
top = derivation.height
groove = [complex(x, bottom), complex(x - derivation.topBevel, top), complex(x + derivation.topBevel, top)]
triangle_mesh.addSymmetricYPath(negatives, groove, 1.0001 * derivation.topRight.imag)
def getBeveledRectangle(bevel, bottomLeft):
'Get the beveled rectangle.'
bottomRight = complex(-bottomLeft.real, bottomLeft.imag)
rectangle = [bottomLeft, bottomRight, -bottomLeft, -bottomRight]
if bevel <= 0.0:
return rectangle
beveledRectangle = []
for pointIndex, point in enumerate(rectangle):
begin = rectangle[(pointIndex + len(rectangle) - 1) % len(rectangle)]
end = rectangle[(pointIndex + 1) % len(rectangle)]
addAlongWay(point, bevel, begin, beveledRectangle)
addAlongWay(point, bevel, end, beveledRectangle)
return beveledRectangle
def getGeometryOutput(elementNode):
'Get vector3 vertexes from attribute dictionary.'
derivation = MechaslabDerivation(elementNode)
negatives = []
positives = []
addSlab(derivation, positives)
for hollowPegSocket in derivation.hollowPegSockets:
addHollowPegSocket(derivation, hollowPegSocket, negatives, positives)
if 's' in derivation.topBevelPositions:
addXGroove(derivation, negatives, -derivation.topRight.imag)
if 'n' in derivation.topBevelPositions:
addXGroove(derivation, negatives, derivation.topRight.imag)
if 'w' in derivation.topBevelPositions:
addYGroove(derivation, negatives, -derivation.topRight.real)
if 'e' in derivation.topBevelPositions:
addYGroove(derivation, negatives, derivation.topRight.real)
return extrude.getGeometryOutputByNegativesPositives(elementNode, negatives, positives)
def getGeometryOutputByArguments(arguments, elementNode):
'Get vector3 vertexes from attribute dictionary by arguments.'
evaluate.setAttributesByArguments(['length', 'radius'], arguments, elementNode)
return getGeometryOutput(elementNode)
def getNewDerivation(elementNode):
'Get new derivation.'
return MechaslabDerivation(elementNode)
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByGeometry(elementNode, getGeometryOutput(elementNode))
class CellExistence(object):
'Class to determine if a cell exists.'
def __init__(self, columns, rows, value):
'Initialize.'
self.existenceSet = None
if value == None:
return
self.existenceSet = set()
for element in value:
if element.__class__ == int:
columnIndex = (element + columns) % columns
for rowIndex in xrange(rows):
keyTuple = (columnIndex, rowIndex)
self.existenceSet.add(keyTuple)
else:
keyTuple = (element[0], element[1])
self.existenceSet.add(keyTuple)
def __repr__(self):
'Get the string representation of this CellExistence.'
return euclidean.getDictionaryString(self.__dict__)
def getIsInExistence(self, columnIndex, rowIndex):
'Detremine if the cell at the column and row exists.'
if self.existenceSet == None:
return True
return (columnIndex, rowIndex) in self.existenceSet
class HollowPegSocket(object):
'Class to hold hollow peg socket variables.'
def __init__(self, center):
'Initialize.'
self.center = center
self.shouldAddPeg = True
self.shouldAddSocket = True
def __repr__(self):
'Get the string representation of this HollowPegSocket.'
return euclidean.getDictionaryString(self.__dict__)
class MechaslabDerivation(object):
'Class to hold mechaslab variables.'
def __init__(self, elementNode):
'Set defaults.'
self.bevelOverRadius = evaluate.getEvaluatedFloat(0.2, elementNode, 'bevelOverRadius')
self.boltRadiusOverRadius = evaluate.getEvaluatedFloat(0.0, elementNode, 'boltRadiusOverRadius')
self.columns = evaluate.getEvaluatedInt(2, elementNode, 'columns')
self.elementNode = elementNode
self.heightOverRadius = evaluate.getEvaluatedFloat(2.0, elementNode, 'heightOverRadius')
self.interiorOverhangRadians = setting.getInteriorOverhangRadians(elementNode)
self.overhangSpan = setting.getOverhangSpan(elementNode)
self.pegClearanceOverRadius = evaluate.getEvaluatedFloat(0.0, elementNode, 'pegClearanceOverRadius')
self.pegRadians = math.radians(evaluate.getEvaluatedFloat(2.0, elementNode, 'pegAngle'))
self.pegHeightOverHeight = evaluate.getEvaluatedFloat(0.4, elementNode, 'pegHeightOverHeight')
self.pegRadiusOverRadius = evaluate.getEvaluatedFloat(0.7, elementNode, 'pegRadiusOverRadius')
self.radius = lineation.getFloatByPrefixBeginEnd(elementNode, 'radius', 'width', 5.0)
self.rows = evaluate.getEvaluatedInt(1, elementNode, 'rows')
self.topBevelOverRadius = evaluate.getEvaluatedFloat(0.2, elementNode, 'topBevelOverRadius')
# Set derived values.
self.bevel = evaluate.getEvaluatedFloat(self.bevelOverRadius * self.radius, elementNode, 'bevel')
self.boltRadius = evaluate.getEvaluatedFloat(self.boltRadiusOverRadius * self.radius, elementNode, 'boltRadius')
self.boltSides = evaluate.getSidesMinimumThreeBasedOnPrecision(elementNode, self.boltRadius)
self.bottomLeftCenter = complex(-float(self.columns - 1), -float(self.rows - 1)) * self.radius
self.height = evaluate.getEvaluatedFloat(self.heightOverRadius * self.radius, elementNode, 'height')
self.hollowPegSockets = []
centerY = self.bottomLeftCenter.imag
diameter = self.radius + self.radius
self.pegExistence = CellExistence(self.columns, self.rows, evaluate.getEvaluatedValue(None, elementNode, 'pegs'))
self.socketExistence = CellExistence(self.columns, self.rows, evaluate.getEvaluatedValue(None, elementNode, 'sockets'))
for rowIndex in xrange(self.rows):
centerX = self.bottomLeftCenter.real
for columnIndex in xrange(self.columns):
hollowPegSocket = HollowPegSocket(complex(centerX, centerY))
hollowPegSocket.shouldAddPeg = self.pegExistence.getIsInExistence(columnIndex, rowIndex)
hollowPegSocket.shouldAddSocket = self.socketExistence.getIsInExistence(columnIndex, rowIndex)
self.hollowPegSockets.append(hollowPegSocket)
centerX += diameter
centerY += diameter
self.pegClearance = evaluate.getEvaluatedFloat(self.pegClearanceOverRadius * self.radius, elementNode, 'pegClearance')
halfPegClearance = 0.5 * self.pegClearance
self.pegHeight = evaluate.getEvaluatedFloat(self.pegHeightOverHeight * self.height, elementNode, 'pegHeight')
self.pegRadius = evaluate.getEvaluatedFloat(self.pegRadiusOverRadius * self.radius, elementNode, 'pegRadius')
sides = 24 * max(1, math.floor(evaluate.getSidesBasedOnPrecision(elementNode, self.pegRadius) / 24))
self.socketRadius = self.pegRadius + halfPegClearance
self.pegSides = evaluate.getEvaluatedInt(sides, elementNode, 'pegSides')
self.pegRadius -= halfPegClearance
self.pegRadiusArealized = evaluate.getRadiusArealizedBasedOnAreaRadius(elementNode, self.pegRadius, self.pegSides)
self.socketSides = evaluate.getEvaluatedInt(sides, elementNode, 'socketSides')
self.socketRadiusArealized = evaluate.getRadiusArealizedBasedOnAreaRadius(elementNode, self.socketRadius, self.socketSides)
self.topBevel = evaluate.getEvaluatedFloat(self.topBevelOverRadius * self.radius, elementNode, 'topBevel')
self.topBevelPositions = evaluate.getEvaluatedString('nwse', elementNode, 'topBevelPositions').lower()
self.topRight = complex(float(self.columns), float(self.rows)) * self.radius
def __repr__(self):
'Get the string representation of this MechaslabDerivation.'
return euclidean.getDictionaryString(self.__dict__)

View File

@ -1,101 +0,0 @@
"""
Peg.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import extrude
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import cylinder
from fabmetheus_utilities.vector3 import Vector3
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addPegOutput(bevel, endZ, outputs, radiusArealized, sides, start, topOverBottom):
'Add beveled cylinder to outputs given bevel, endZ, radiusArealized and start.'
height = abs(start.z - endZ)
bevelStartRatio = max(1.0 - bevel / height, 0.5)
oneMinusBevelStartRatio = 1.0 - bevelStartRatio
trunkEndZ = bevelStartRatio * endZ + oneMinusBevelStartRatio * start.z
trunkTopOverBottom = bevelStartRatio * topOverBottom + oneMinusBevelStartRatio
cylinder.addCylinderOutputByEndStart(trunkEndZ, radiusArealized, outputs, sides, start, trunkTopOverBottom)
capRadius = radiusArealized * trunkTopOverBottom
capStart = bevelStartRatio * Vector3(start.x, start.y, endZ) + oneMinusBevelStartRatio * start
radiusMaximum = max(radiusArealized.real, radiusArealized.imag)
endRadiusMaximum = radiusMaximum * topOverBottom - bevel
trunkRadiusMaximum = radiusMaximum * trunkTopOverBottom
capTopOverBottom = endRadiusMaximum / trunkRadiusMaximum
cylinder.addCylinderOutputByEndStart(endZ, capRadius, outputs, sides, capStart, capTopOverBottom)
def getGeometryOutput(derivation, elementNode):
'Get vector3 vertexes from attribute dictionary.'
if derivation == None:
derivation = PegDerivation(elementNode)
positives = []
radiusArealized = complex(derivation.radiusArealized, derivation.radiusArealized)
addPegOutput(derivation.bevel, derivation.endZ, positives, radiusArealized, derivation.sides, derivation.start, derivation.topOverBottom)
return extrude.getGeometryOutputByNegativesPositives(elementNode, [], positives)
def getGeometryOutputByArguments(arguments, elementNode):
'Get vector3 vertexes from attribute dictionary by arguments.'
evaluate.setAttributesByArguments(['radius', 'endZ', 'start'], arguments, elementNode)
return getGeometryOutput(None, elementNode)
def getNewDerivation(elementNode):
'Get new derivation.'
return PegDerivation(elementNode)
def getTopAddBiconicOutput(bottomRadians, height, outputs, radius, sides, start, tipRadius, topRadians):
'Get top and add biconic cylinder to outputs.'
radiusMaximum = max(radius.real, radius.imag)
topRadiusMaximum = radiusMaximum - height * math.tan(bottomRadians)
trunkEndZ = start.z + height
trunkTopOverBottom = topRadiusMaximum / radiusMaximum
topRadiusComplex = trunkTopOverBottom * radius
cylinder.addCylinderOutputByEndStart(trunkEndZ, radius, outputs, sides, start, trunkTopOverBottom)
tipOverTop = tipRadius / topRadiusMaximum
if tipOverTop >= 1.0:
return trunkEndZ
capStart = Vector3(start.x, start.y, trunkEndZ)
capEndZ = trunkEndZ + (topRadiusMaximum - tipRadius) / math.tan(topRadians)
cylinder.addCylinderOutputByEndStart(capEndZ, topRadiusComplex, outputs, sides, capStart, tipOverTop)
return capEndZ
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByGeometry(elementNode, getGeometryOutput(None, elementNode))
def setTopOverBottomByRadius(derivation, endZ, radius, startZ):
'Set the derivation topOverBottom by the angle of the elementNode, the endZ, float radius and startZ.'
angleDegrees = evaluate.getEvaluatedFloat(None, derivation.elementNode, 'angle')
if angleDegrees != None:
derivation.topOverBottom = cylinder.getTopOverBottom(math.radians(angleDegrees), endZ, complex(radius, radius), startZ)
class PegDerivation(object):
'Class to hold peg variables.'
def __init__(self, elementNode):
'Set defaults.'
self.bevelOverRadius = evaluate.getEvaluatedFloat(0.25, elementNode, 'bevelOverRadius')
self.clearanceOverRadius = evaluate.getEvaluatedFloat(0.0, elementNode, 'clearanceOverRadius')
self.elementNode = elementNode
self.endZ = evaluate.getEvaluatedFloat(10.0, elementNode, 'endZ')
self.start = evaluate.getVector3ByPrefix(Vector3(), elementNode, 'start')
self.radius = lineation.getFloatByPrefixBeginEnd(elementNode, 'radius', 'diameter', 2.0)
self.sides = evaluate.getSidesMinimumThreeBasedOnPrecision(elementNode, max(self.radius.real, self.radius.imag))
self.radiusArealized = evaluate.getRadiusArealizedBasedOnAreaRadius(elementNode, self.radius, self.sides)
self.topOverBottom = evaluate.getEvaluatedFloat(0.8, elementNode, 'topOverBottom')
setTopOverBottomByRadius(self, self.endZ, self.radiusArealized, self.start.z)
# Set derived variables.
self.bevel = evaluate.getEvaluatedFloat(self.bevelOverRadius * self.radiusArealized, elementNode, 'bevel')
self.clearance = evaluate.getEvaluatedFloat(self.clearanceOverRadius * self.radiusArealized, elementNode, 'clearance')

View File

@ -1,67 +0,0 @@
"""
Polygon path.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutput(derivation, elementNode):
"Get vector3 vertexes from attribute dictionary."
if derivation == None:
derivation = PolygonDerivation(elementNode)
loop = []
spiral = lineation.Spiral(derivation.spiral, 0.5 * derivation.sideAngle / math.pi)
for side in xrange(derivation.start, derivation.start + derivation.extent + 1):
angle = float(side) * derivation.sideAngle
unitPolar = euclidean.getWiddershinsUnitPolar(angle)
vertex = spiral.getSpiralPoint(unitPolar, Vector3(unitPolar.real * derivation.radius.real, unitPolar.imag * derivation.radius.imag))
loop.append(vertex)
loop = euclidean.getLoopWithoutCloseEnds(0.000001 * max(derivation.radius.real, derivation.radius.imag), loop)
lineation.setClosedAttribute(elementNode, derivation.revolutions)
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop(loop, derivation.sideAngle))
def getGeometryOutputByArguments(arguments, elementNode):
"Get vector3 vertexes from attribute dictionary by arguments."
evaluate.setAttributesByArguments(['sides', 'radius'], arguments, elementNode)
return getGeometryOutput(None, elementNode)
def getNewDerivation(elementNode):
'Get new derivation.'
return PolygonDerivation(elementNode)
def processElementNode(elementNode):
"Process the xml element."
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
class PolygonDerivation(object):
"Class to hold polygon variables."
def __init__(self, elementNode):
'Set defaults.'
self.sides = evaluate.getEvaluatedFloat(4.0, elementNode, 'sides')
self.sideAngle = 2.0 * math.pi / self.sides
cosSide = math.cos(0.5 * self.sideAngle)
self.radius = lineation.getComplexByMultiplierPrefixes(elementNode, cosSide, ['apothem', 'inradius'], complex(1.0, 1.0))
self.radius = lineation.getComplexByPrefixes(elementNode, ['demisize', 'radius'], self.radius)
self.radius = lineation.getComplexByMultiplierPrefixes(elementNode, 2.0, ['diameter', 'size'], self.radius)
self.sidesCeiling = int(math.ceil(abs(self.sides)))
self.start = evaluate.getEvaluatedInt(0, elementNode, 'start')
end = evaluate.getEvaluatedInt(self.sidesCeiling, elementNode, 'end')
self.revolutions = evaluate.getEvaluatedInt(1, elementNode, 'revolutions')
self.extent = evaluate.getEvaluatedInt(end - self.start, elementNode, 'extent')
self.extent += self.sidesCeiling * (self.revolutions - 1)
self.spiral = evaluate.getVector3ByPrefix(None, elementNode, 'spiral')

View File

@ -1,80 +0,0 @@
"""
Shaft path.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutput(derivation, elementNode):
"Get vector3 vertexes from attribute dictionary."
if derivation == None:
derivation = ShaftDerivation(elementNode)
shaftPath = getShaftPath(derivation.depthBottom, derivation.depthTop, derivation.radius, derivation.sides)
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop(shaftPath))
def getGeometryOutputByArguments(arguments, elementNode):
"Get vector3 vertexes from attribute dictionary by arguments."
evaluate.setAttributesByArguments(['radius', 'sides'], arguments, elementNode)
return getGeometryOutput(None, elementNode)
def getNewDerivation(elementNode):
'Get new derivation.'
return ShaftDerivation(elementNode)
def getShaftPath(depthBottom, depthTop, radius, sides):
'Get shaft with the option of a flat on the top and/or bottom.'
if radius <= 0.0:
return []
sideAngle = 2.0 * math.pi / float(abs(sides))
startAngle = 0.5 * sideAngle
endAngle = math.pi - 0.1 * sideAngle
shaftProfile = []
while startAngle < endAngle:
unitPolar = euclidean.getWiddershinsUnitPolar(startAngle)
shaftProfile.append(unitPolar * radius)
startAngle += sideAngle
if abs(sides) % 2 == 1:
shaftProfile.append(complex(-radius, 0.0))
horizontalBegin = radius - depthTop
horizontalEnd = depthBottom - radius
shaftProfile = euclidean.getHorizontallyBoundedPath(horizontalBegin, horizontalEnd, shaftProfile)
for shaftPointIndex, shaftPoint in enumerate(shaftProfile):
shaftProfile[shaftPointIndex] = complex(shaftPoint.imag, shaftPoint.real)
shaftPath = euclidean.getVector3Path(euclidean.getMirrorPath(shaftProfile))
if sides > 0:
shaftPath.reverse()
return shaftPath
def processElementNode(elementNode):
"Process the xml element."
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
class ShaftDerivation(object):
"Class to hold shaft variables."
def __init__(self, elementNode):
'Set defaults.'
self.depthBottomOverRadius = evaluate.getEvaluatedFloat(0.0, elementNode, 'depthBottomOverRadius')
self.depthTopOverRadius = evaluate.getEvaluatedFloat(0.0, elementNode, 'depthOverRadius')
self.depthTopOverRadius = evaluate.getEvaluatedFloat(
self.depthTopOverRadius, elementNode, 'depthTopOverRadius')
self.radius = evaluate.getEvaluatedFloat(1.0, elementNode, 'radius')
self.sides = evaluate.getEvaluatedInt(4, elementNode, 'sides')
self.depthBottom = self.radius * self.depthBottomOverRadius
self.depthBottom = evaluate.getEvaluatedFloat(self.depthBottom, elementNode, 'depthBottom')
self.depthTop = self.radius * self.depthTopOverRadius
self.depthTop = evaluate.getEvaluatedFloat(self.depthTop, elementNode, 'depth')
self.depthTop = evaluate.getEvaluatedFloat(self.depthTop, elementNode, 'depthTop')

View File

@ -1,174 +0,0 @@
"""
Solid has functions for 3D shapes.
Solid has some of the same functions as lineation, however you can not define geometry by dictionary string in the target because there is no getGeometryOutputByArguments function. You would have to define a shape by making the shape element. Also, you can not define geometry by 'get<Creation Name>, because the target only gets element. Instead you would have the shape element, and set the target in solid to that element.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities import boolean_geometry
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutputByFunction(elementNode, geometryFunction):
'Get geometry output by manipulationFunction.'
if elementNode.xmlObject == None:
print('Warning, there is no object in getGeometryOutputByFunction in solid for:')
print(elementNode)
return None
geometryOutput = elementNode.xmlObject.getGeometryOutput()
if geometryOutput == None:
print('Warning, there is no geometryOutput in getGeometryOutputByFunction in solid for:')
print(elementNode)
return None
return geometryFunction(elementNode, geometryOutput, '')
def getGeometryOutputByManipulation(elementNode, geometryOutput):
'Get geometryOutput manipulated by the plugins in the manipulation shapes & solids folders.'
xmlProcessor = elementNode.getXMLProcessor()
matchingPlugins = getSolidMatchingPlugins(elementNode)
matchingPlugins.sort(evaluate.compareExecutionOrderAscending)
for matchingPlugin in matchingPlugins:
prefix = matchingPlugin.__name__.replace('_', '') + '.'
geometryOutput = matchingPlugin.getManipulatedGeometryOutput(elementNode, geometryOutput, prefix)
return geometryOutput
def getLoopLayersSetCopy(elementNode, geometryOutput, importRadius, radius):
'Get the loop layers and set the copyShallow.'
halfLayerHeight = 0.5 * radius
copyShallow = elementNode.getCopyShallow()
processElementNodeByGeometry(copyShallow, geometryOutput)
targetMatrix = matrix.getBranchMatrixSetElementNode(elementNode)
matrix.setElementNodeDictionaryMatrix(copyShallow, targetMatrix)
transformedVertexes = copyShallow.xmlObject.getTransformedVertexes()
minimumZ = boolean_geometry.getMinimumZ(copyShallow.xmlObject)
if minimumZ == None:
copyShallow.parentNode.xmlObject.archivableObjects.remove(copyShallow.xmlObject)
return []
maximumZ = euclidean.getTopPath(transformedVertexes)
copyShallow.attributes['visible'] = True
copyShallowObjects = [copyShallow.xmlObject]
bottomLoopLayer = euclidean.LoopLayer(minimumZ)
z = minimumZ + 0.1 * radius
zoneArrangement = triangle_mesh.ZoneArrangement(radius, transformedVertexes)
bottomLoopLayer.loops = boolean_geometry.getEmptyZLoops(copyShallowObjects, importRadius, False, z, zoneArrangement)
loopLayers = [bottomLoopLayer]
z = minimumZ + halfLayerHeight
loopLayers += boolean_geometry.getLoopLayers(copyShallowObjects, importRadius, halfLayerHeight, maximumZ, False, z, zoneArrangement)
copyShallow.parentNode.xmlObject.archivableObjects.remove(copyShallow.xmlObject)
return loopLayers
def getLoopOrEmpty(loopIndex, loopLayers):
'Get the loop, or if the loopIndex is out of range, get an empty list.'
if loopIndex < 0 or loopIndex >= len(loopLayers):
return []
return loopLayers[loopIndex].loops[0]
def getNewDerivation(elementNode):
'Get new derivation.'
return SolidDerivation(elementNode)
def getSolidMatchingPlugins(elementNode):
'Get solid plugins in the manipulation matrix, shapes & solids folders.'
xmlProcessor = elementNode.getXMLProcessor()
matchingPlugins = evaluate.getMatchingPlugins(elementNode, xmlProcessor.manipulationMatrixDictionary)
return matchingPlugins + evaluate.getMatchingPlugins(elementNode, xmlProcessor.manipulationShapeDictionary)
def processArchiveRemoveSolid(elementNode, geometryOutput):
'Process the target by the manipulationFunction.'
solidMatchingPlugins = getSolidMatchingPlugins(elementNode)
if len(solidMatchingPlugins) == 0:
elementNode.parentNode.xmlObject.archivableObjects.append(elementNode.xmlObject)
matrix.getBranchMatrixSetElementNode(elementNode)
return
processElementNodeByGeometry(elementNode, getGeometryOutputByManipulation(elementNode, geometryOutput))
def processElementNode(elementNode):
'Process the xml element.'
processElementNodeByDerivation(None, elementNode)
def processElementNodeByDerivation(derivation, elementNode):
'Process the xml element by derivation.'
if derivation == None:
derivation = SolidDerivation(elementNode)
elementAttributesCopy = elementNode.attributes.copy()
for target in derivation.targets:
targetAttributesCopy = target.attributes.copy()
target.attributes = elementAttributesCopy
processTarget(target)
target.attributes = targetAttributesCopy
def processElementNodeByFunction(elementNode, manipulationFunction):
'Process the xml element.'
if 'target' not in elementNode.attributes:
print('Warning, there was no target in processElementNodeByFunction in solid for:')
print(elementNode)
return
target = evaluate.getEvaluatedLinkValue(elementNode, str(elementNode.attributes['target']).strip())
if target.__class__.__name__ == 'ElementNode':
manipulationFunction(elementNode, target)
return
path.convertElementNode(elementNode, target)
manipulationFunction(elementNode, elementNode)
def processElementNodeByFunctionPair(elementNode, geometryFunction, pathFunction):
'Process the xml element by the appropriate manipulationFunction.'
elementAttributesCopy = elementNode.attributes.copy()
targets = evaluate.getElementNodesByKey(elementNode, 'target')
for target in targets:
targetAttributesCopy = target.attributes.copy()
target.attributes = elementAttributesCopy
processTargetByFunctionPair(geometryFunction, pathFunction, target)
target.attributes = targetAttributesCopy
def processElementNodeByGeometry(elementNode, geometryOutput):
'Process the xml element by geometryOutput.'
if geometryOutput != None:
elementNode.getXMLProcessor().convertElementNode(elementNode, geometryOutput)
def processTarget(target):
'Process the target.'
if target.xmlObject == None:
print('Warning, there is no object in processElementNode in solid for:')
print(target)
return
geometryOutput = target.xmlObject.getGeometryOutput()
if geometryOutput == None:
print('Warning, there is no geometryOutput in processElementNode in solid for:')
print(target.xmlObject)
return
geometryOutput = getGeometryOutputByManipulation(target, geometryOutput)
lineation.removeChildNodesFromElementObject(target)
target.getXMLProcessor().convertElementNode(target, geometryOutput)
def processTargetByFunctionPair(geometryFunction, pathFunction, target):
'Process the target by the manipulationFunction.'
if target.xmlObject == None:
print('Warning, there is no object in processTargetByFunctions in solid for:')
print(target)
return
if len(target.xmlObject.getPaths()) > 0:
lineation.processTargetByFunction(pathFunction, target)
return
geometryOutput = getGeometryOutputByFunction(target, geometryFunction)
lineation.removeChildNodesFromElementObject(target)
target.getXMLProcessor().convertElementNode(target, geometryOutput)
class SolidDerivation(object):
'Class to hold solid variables.'
def __init__(self, elementNode):
'Set defaults.'
self.targets = evaluate.getElementNodesByKey(elementNode, 'target')

View File

@ -1,155 +0,0 @@
"""
Sponge slice.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
import random
import time
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutput(derivation, elementNode):
"Get vector3 vertexes from attribute dictionary."
if derivation == None:
derivation = SpongeSliceDerivation(elementNode)
awayPoints = []
vector3Path = euclidean.getVector3Path(euclidean.getSquareLoopWiddershins(-derivation.inradius, derivation.inradius))
geometryOutput = lineation.SideLoop(vector3Path).getManipulationPluginLoops(elementNode)
minimumDistanceFromOther = derivation.wallThickness + derivation.minimumRadius + derivation.minimumRadius
if derivation.inradiusMinusRadiusThickness.real <= 0.0 or derivation.inradiusMinusRadiusThickness.imag <= 0.0:
return geometryOutput
for point in derivation.path:
if abs(point.x) <= derivation.inradiusMinusRadiusThickness.real and abs(point.y) <= derivation.inradiusMinusRadiusThickness.imag:
awayPoints.append(point)
awayCircles = []
for point in awayPoints:
if getIsPointAway(minimumDistanceFromOther, point, awayCircles):
awayCircles.append(SpongeCircle(point, derivation.minimumRadius))
averagePotentialBubbleArea = derivation.potentialBubbleArea / float(len(awayCircles))
averageBubbleRadius = math.sqrt(averagePotentialBubbleArea / math.pi) - 0.5 * derivation.wallThickness
sides = -4 * (max(evaluate.getSidesBasedOnPrecision(elementNode, averageBubbleRadius), 4) / 4)
sideAngle = math.pi / sides
cosSide = math.cos(sideAngle)
overlapArealRatio = (1 - cosSide) / cosSide
for circleIndex, circle in enumerate(awayCircles):
otherCircles = awayCircles[: circleIndex] + awayCircles[circleIndex + 1 :]
circle.radius = circle.getRadius(circle.center, derivation, otherCircles, overlapArealRatio)
if derivation.searchAttempts > 0:
for circleIndex, circle in enumerate(awayCircles):
otherCircles = awayCircles[: circleIndex] + awayCircles[circleIndex + 1 :]
circle.moveCircle(derivation, otherCircles, overlapArealRatio)
for circle in awayCircles:
vector3Path = euclidean.getVector3Path(euclidean.getComplexPolygon(circle.center.dropAxis(), circle.radius, sides, sideAngle))
geometryOutput += lineation.SideLoop(vector3Path).getManipulationPluginLoops(elementNode)
return geometryOutput
def getGeometryOutputByArguments(arguments, elementNode):
"Get vector3 vertexes from attribute dictionary by arguments."
return getGeometryOutput(None, elementNode)
def getIsPointAway(minimumDistance, point, spongeCircles):
'Determine if the point is at least the minimumDistance away from other points.'
for otherSpongeCircle in spongeCircles:
if abs(otherSpongeCircle.center - point) < minimumDistance:
return False
return True
def getNewDerivation(elementNode):
'Get new derivation.'
return SpongeSliceDerivation(elementNode)
def processElementNode(elementNode):
"Process the xml element."
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
class SpongeCircle(object):
"Class to hold sponge circle."
def __init__(self, center, radius=0.0):
'Initialize.'
self.center = center
self.radius = radius
def getRadius(self, center, derivation, otherCircles, overlapArealRatio):
'Get sponge bubble radius.'
radius = 987654321.0
for otherSpongeCircle in otherCircles:
distance = abs(otherSpongeCircle.center.dropAxis() - center.dropAxis())
radius = min(distance - derivation.wallThickness - otherSpongeCircle.radius, radius)
overlapAreal = overlapArealRatio * radius
radius = min(derivation.inradiusMinusThickness.real + overlapAreal - abs(center.x), radius)
return min(derivation.inradiusMinusThickness.imag + overlapAreal - abs(center.y), radius)
def moveCircle(self, derivation, otherCircles, overlapArealRatio):
'Move circle into an open spot.'
angle = (abs(self.center) + self.radius) % euclidean.globalTau
movedCenter = self.center
searchRadius = derivation.searchRadiusOverRadius * self.radius
distanceIncrement = searchRadius / float(derivation.searchAttempts)
distance = 0.0
greatestRadius = self.radius
searchCircles = []
searchCircleDistance = searchRadius + searchRadius + self.radius + derivation.wallThickness
for otherCircle in otherCircles:
if abs(self.center - otherCircle.center) <= searchCircleDistance + otherCircle.radius:
searchCircles.append(otherCircle)
for attemptIndex in xrange(derivation.searchAttempts):
angle += euclidean.globalGoldenAngle
distance += distanceIncrement
offset = distance * euclidean.getWiddershinsUnitPolar(angle)
attemptCenter = self.center + Vector3(offset.real, offset.imag)
radius = self.getRadius(attemptCenter, derivation, searchCircles, overlapArealRatio)
if radius > greatestRadius:
greatestRadius = radius
movedCenter = attemptCenter
self.center = movedCenter
self.radius = greatestRadius
class SpongeSliceDerivation(object):
"Class to hold sponge slice variables."
def __init__(self, elementNode):
'Initialize.'
elementNode.attributes['closed'] = 'true'
self.density = evaluate.getEvaluatedFloat(1.0, elementNode, 'density')
self.minimumRadiusOverThickness = evaluate.getEvaluatedFloat(1.0, elementNode, 'minimumRadiusOverThickness')
self.mobile = evaluate.getEvaluatedBoolean(False, elementNode, 'mobile')
self.inradius = lineation.getInradius(complex(10.0, 10.0), elementNode)
self.path = None
if 'path' in elementNode.attributes:
self.path = evaluate.getPathByKey([], elementNode, 'path')
self.searchAttempts = evaluate.getEvaluatedInt(0, elementNode, 'searchAttempts')
self.searchRadiusOverRadius = evaluate.getEvaluatedFloat(1.0, elementNode, 'searchRadiusOverRadius')
self.seed = evaluate.getEvaluatedInt(None, elementNode, 'seed')
self.wallThickness = evaluate.getEvaluatedFloat(2.0 * setting.getEdgeWidth(elementNode), elementNode, 'wallThickness')
# Set derived variables.
self.halfWallThickness = 0.5 * self.wallThickness
self.inradiusMinusThickness = self.inradius - complex(self.wallThickness, self.wallThickness)
self.minimumRadius = evaluate.getEvaluatedFloat(self.minimumRadiusOverThickness * self.wallThickness, elementNode, 'minimumRadius')
self.inradiusMinusRadiusThickness = self.inradiusMinusThickness - complex(self.minimumRadius, self.minimumRadius)
self.potentialBubbleArea = 4.0 * self.inradiusMinusThickness.real * self.inradiusMinusThickness.imag
if self.path == None:
radiusPlusHalfThickness = self.minimumRadius + self.halfWallThickness
numberOfPoints = int(math.ceil(self.density * self.potentialBubbleArea / math.pi / radiusPlusHalfThickness / radiusPlusHalfThickness))
self.path = []
if self.seed == None:
self.seed = time.time()
print('Sponge slice seed used was: %s' % self.seed)
random.seed(self.seed)
for pointIndex in xrange(numberOfPoints):
point = euclidean.getRandomComplex(-self.inradiusMinusRadiusThickness, self.inradiusMinusRadiusThickness)
self.path.append(Vector3(point.real, point.imag))

View File

@ -1,78 +0,0 @@
"""
Square path.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutput(derivation, elementNode):
"Get vector3 vertexes from attribute dictionary."
if derivation == None:
derivation = SquareDerivation(elementNode)
topRight = complex(derivation.topDemiwidth, derivation.demiheight)
topLeft = complex(-derivation.topDemiwidth, derivation.demiheight)
bottomLeft = complex(-derivation.bottomDemiwidth, -derivation.demiheight)
bottomRight = complex(derivation.bottomDemiwidth, -derivation.demiheight)
if derivation.interiorAngle != 90.0:
interiorPlaneAngle = euclidean.getWiddershinsUnitPolar(math.radians(derivation.interiorAngle - 90.0))
topRight = (topRight - bottomRight) * interiorPlaneAngle + bottomRight
topLeft = (topLeft - bottomLeft) * interiorPlaneAngle + bottomLeft
lineation.setClosedAttribute(elementNode, derivation.revolutions)
complexLoop = [topRight, topLeft, bottomLeft, bottomRight]
originalLoop = complexLoop[:]
for revolution in xrange(1, derivation.revolutions):
complexLoop += originalLoop
spiral = lineation.Spiral(derivation.spiral, 0.25)
loop = []
loopCentroid = euclidean.getLoopCentroid(originalLoop)
for point in complexLoop:
unitPolar = euclidean.getNormalized(point - loopCentroid)
loop.append(spiral.getSpiralPoint(unitPolar, Vector3(point.real, point.imag)))
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop(loop, 0.5 * math.pi))
def getGeometryOutputByArguments(arguments, elementNode):
"Get vector3 vertexes from attribute dictionary by arguments."
if len(arguments) < 1:
return getGeometryOutput(None, elementNode)
inradius = 0.5 * euclidean.getFloatFromValue(arguments[0])
elementNode.attributes['inradius.x'] = str(inradius)
if len(arguments) > 1:
inradius = 0.5 * euclidean.getFloatFromValue(arguments[1])
elementNode.attributes['inradius.y'] = str(inradius)
return getGeometryOutput(None, elementNode)
def getNewDerivation(elementNode):
'Get new derivation.'
return SquareDerivation(elementNode)
def processElementNode(elementNode):
"Process the xml element."
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
class SquareDerivation(object):
"Class to hold square variables."
def __init__(self, elementNode):
'Set defaults.'
self.inradius = lineation.getInradius(complex(1.0, 1.0), elementNode)
self.demiwidth = lineation.getFloatByPrefixBeginEnd(elementNode, 'demiwidth', 'width', self.inradius.real)
self.demiheight = lineation.getFloatByPrefixBeginEnd(elementNode, 'demiheight', 'height', self.inradius.imag)
self.bottomDemiwidth = lineation.getFloatByPrefixBeginEnd(elementNode, 'bottomdemiwidth', 'bottomwidth', self.demiwidth)
self.topDemiwidth = lineation.getFloatByPrefixBeginEnd(elementNode, 'topdemiwidth', 'topwidth', self.demiwidth)
self.interiorAngle = evaluate.getEvaluatedFloat(90.0, elementNode, 'interiorangle')
self.revolutions = evaluate.getEvaluatedInt(1, elementNode, 'revolutions')
self.spiral = evaluate.getVector3ByPrefix(None, elementNode, 'spiral')

View File

@ -1,114 +0,0 @@
"""
Teardrop path.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import extrude
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addNegativesByRadius(elementNode, end, negatives, radius, start):
"Add teardrop drill hole to negatives."
if radius <= 0.0:
return
copyShallow = elementNode.getCopyShallow()
extrude.setElementNodeToEndStart(copyShallow, end, start)
extrudeDerivation = extrude.ExtrudeDerivation(copyShallow)
extrude.addNegatives(extrudeDerivation, negatives, [getTeardropPathByEndStart(elementNode, end, radius, start)])
def getGeometryOutput(derivation, elementNode):
"Get vector3 vertexes from attribute dictionary."
if derivation == None:
derivation = TeardropDerivation(elementNode)
teardropPath = getTeardropPath(
derivation.inclination, derivation.overhangRadians, derivation.overhangSpan, derivation.radiusArealized, derivation.sides)
return lineation.getGeometryOutputByLoop(elementNode, lineation.SideLoop(teardropPath))
def getGeometryOutputByArguments(arguments, elementNode):
"Get vector3 vertexes from attribute dictionary by arguments."
evaluate.setAttributesByArguments(['radius', 'inclination'], arguments, elementNode)
return getGeometryOutput(None, elementNode)
def getInclination(end, start):
"Get inclination."
if end == None or start == None:
return 0.0
endMinusStart = end - start
return math.atan2(endMinusStart.z, abs(endMinusStart.dropAxis()))
def getNewDerivation(elementNode):
'Get new derivation.'
return TeardropDerivation(elementNode)
def getTeardropPath(inclination, overhangRadians, overhangSpan, radiusArealized, sides):
"Get vector3 teardrop path."
sideAngle = 2.0 * math.pi / float(sides)
overhangPlaneAngle = euclidean.getWiddershinsUnitPolar(overhangRadians)
overhangRadians = math.atan2(overhangPlaneAngle.imag, overhangPlaneAngle.real * math.cos(inclination))
tanOverhangAngle = math.tan(overhangRadians)
beginAngle = overhangRadians
beginMinusEndAngle = math.pi + overhangRadians + overhangRadians
withinSides = int(math.ceil(beginMinusEndAngle / sideAngle))
withinSideAngle = -beginMinusEndAngle / float(withinSides)
teardropPath = []
for side in xrange(withinSides + 1):
unitPolar = euclidean.getWiddershinsUnitPolar(beginAngle)
teardropPath.append(unitPolar * radiusArealized)
beginAngle += withinSideAngle
firstPoint = teardropPath[0]
if overhangSpan <= 0.0:
teardropPath.append(complex(0.0, firstPoint.imag + firstPoint.real / tanOverhangAngle))
else:
deltaX = (radiusArealized - firstPoint.imag) * tanOverhangAngle
overhangPoint = complex(firstPoint.real - deltaX, radiusArealized)
remainingDeltaX = max(0.0, overhangPoint.real - 0.5 * overhangSpan )
overhangPoint += complex(-remainingDeltaX, remainingDeltaX / tanOverhangAngle)
teardropPath.append(complex(-overhangPoint.real, overhangPoint.imag))
teardropPath.append(overhangPoint)
return euclidean.getVector3Path(teardropPath)
def getTeardropPathByEndStart(elementNode, end, radius, start):
"Get vector3 teardrop path by end and start."
inclination = getInclination(end, start)
sides = evaluate.getSidesMinimumThreeBasedOnPrecisionSides(elementNode, radius)
radiusArealized = evaluate.getRadiusArealizedBasedOnAreaRadius(elementNoderadius, sides)
return getTeardropPath(inclination, setting.getOverhangRadians(elementNode), setting.getOverhangSpan(elementNode), radiusArealized, sides)
def processElementNode(elementNode):
"Process the xml element."
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
class TeardropDerivation(object):
"Class to hold teardrop variables."
def __init__(self, elementNode):
'Set defaults.'
end = evaluate.getVector3ByPrefix(None, elementNode, 'end')
start = evaluate.getVector3ByPrefix(Vector3(), elementNode, 'start')
inclinationDegree = math.degrees(getInclination(end, start))
self.elementNode = elementNode
self.inclination = math.radians(evaluate.getEvaluatedFloat(inclinationDegree, elementNode, 'inclination'))
self.overhangRadians = setting.getOverhangRadians(elementNode)
self.overhangSpan = setting.getOverhangSpan(elementNode)
self.radius = lineation.getFloatByPrefixBeginEnd(elementNode, 'radius', 'diameter', 1.0)
size = evaluate.getEvaluatedFloat(None, elementNode, 'size')
if size != None:
self.radius = 0.5 * size
self.sides = evaluate.getEvaluatedFloat(None, elementNode, 'sides')
if self.sides == None:
self.sides = evaluate.getSidesMinimumThreeBasedOnPrecisionSides(elementNode, self.radius)
self.radiusArealized = evaluate.getRadiusArealizedBasedOnAreaRadius(elementNode, self.radius, self.sides)

View File

@ -1,61 +0,0 @@
"""
Text vertexes.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import svg_reader
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getGeometryOutput(derivation, elementNode):
"Get vector3 vertexes from attributes."
if derivation == None:
derivation = TextDerivation(elementNode)
if derivation.textString == '':
print('Warning, textString is empty in getGeometryOutput in text for:')
print(elementNode)
return []
geometryOutput = []
for textComplexLoop in svg_reader.getTextComplexLoops(derivation.fontFamily, derivation.fontSize, derivation.textString):
textComplexLoop.reverse()
vector3Path = euclidean.getVector3Path(textComplexLoop)
sideLoop = lineation.SideLoop(vector3Path)
sideLoop.rotate(elementNode)
geometryOutput += lineation.getGeometryOutputByManipulation(elementNode, sideLoop)
return geometryOutput
def getGeometryOutputByArguments(arguments, elementNode):
"Get vector3 vertexes from attribute dictionary by arguments."
evaluate.setAttributesByArguments(['text', 'fontSize', 'fontFamily'], arguments, elementNode)
return getGeometryOutput(None, elementNode)
def getNewDerivation(elementNode):
'Get new derivation.'
return TextDerivation(elementNode)
def processElementNode(elementNode):
"Process the xml element."
path.convertElementNode(elementNode, getGeometryOutput(None, elementNode))
class TextDerivation(object):
"Class to hold text variables."
def __init__(self, elementNode):
'Set defaults.'
self.fontFamily = evaluate.getEvaluatedString('Gentium Basic Regular', elementNode, 'font-family')
self.fontFamily = evaluate.getEvaluatedString(self.fontFamily, elementNode, 'fontFamily')
self.fontSize = evaluate.getEvaluatedFloat(12.0, elementNode, 'font-size')
self.fontSize = evaluate.getEvaluatedFloat(self.fontSize, elementNode, 'fontSize')
self.textString = elementNode.getTextContent()
self.textString = evaluate.getEvaluatedString(self.textString, elementNode, 'text')

View File

@ -1,176 +0,0 @@
"""
Boolean geometry dictionary object.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import xml_simple_writer
import cStringIO
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getAllPaths(paths, xmlObject):
'Get all paths.'
for archivableObject in xmlObject.archivableObjects:
paths += archivableObject.getPaths()
return paths
def getAllTransformedPaths(transformedPaths, xmlObject):
'Get all transformed paths.'
for archivableObject in xmlObject.archivableObjects:
transformedPaths += archivableObject.getTransformedPaths()
return transformedPaths
def getAllTransformedVertexes(transformedVertexes, xmlObject):
'Get all transformed vertexes.'
for archivableObject in xmlObject.archivableObjects:
transformedVertexes += archivableObject.getTransformedVertexes()
return transformedVertexes
def getAllVertexes(vertexes, xmlObject):
'Get all vertexes.'
for archivableObject in xmlObject.archivableObjects:
vertexes += archivableObject.getVertexes()
return vertexes
def processElementNode(elementNode):
'Process the xml element.'
evaluate.processArchivable( Dictionary, elementNode)
class Dictionary(object):
'A dictionary object.'
def __init__(self):
'Add empty lists.'
self.archivableObjects = []
self.elementNode = None
def __repr__(self):
'Get the string representation of this object info.'
output = xml_simple_writer.getBeginGeometryXMLOutput(self.elementNode)
self.addXML( 1, output )
return xml_simple_writer.getEndGeometryXMLString(output)
def addXML(self, depth, output):
'Add xml for this object.'
attributeCopy = {}
if self.elementNode != None:
attributeCopy = evaluate.getEvaluatedDictionaryByCopyKeys(['paths', 'target', 'vertexes'], self.elementNode)
euclidean.removeElementsFromDictionary(attributeCopy, matrix.getKeysM())
euclidean.removeTrueFromDictionary(attributeCopy, 'visible')
innerOutput = cStringIO.StringIO()
self.addXMLInnerSection(depth + 1, innerOutput)
self.addXMLArchivableObjects(depth + 1, innerOutput)
xml_simple_writer.addBeginEndInnerXMLTag(attributeCopy, depth, innerOutput.getvalue(), self.getXMLLocalName(), output)
def addXMLArchivableObjects(self, depth, output):
'Add xml for this object.'
xml_simple_writer.addXMLFromObjects( depth, self.archivableObjects, output )
def addXMLInnerSection(self, depth, output):
'Add xml section for this object.'
pass
def createShape(self):
'Create the shape.'
pass
def getAttributes(self):
'Get attribute table.'
if self.elementNode == None:
return {}
return self.elementNode.attributes
def getComplexTransformedPathLists(self):
'Get complex transformed path lists.'
complexTransformedPathLists = []
for archivableObject in self.archivableObjects:
complexTransformedPathLists.append(euclidean.getComplexPaths(archivableObject.getTransformedPaths()))
return complexTransformedPathLists
def getFabricationExtension(self):
'Get fabrication extension.'
return 'xml'
def getFabricationText(self, addLayerTemplate):
'Get fabrication text.'
return self.__repr__()
def getGeometryOutput(self):
'Get geometry output dictionary.'
shapeOutput = []
for visibleObject in evaluate.getVisibleObjects(self.archivableObjects):
geometryOutput = visibleObject.getGeometryOutput()
if geometryOutput != None:
visibleObject.transformGeometryOutput(geometryOutput)
shapeOutput.append(geometryOutput)
if len(shapeOutput) < 1:
return None
return {self.getXMLLocalName() : {'shapes' : shapeOutput}}
def getMatrix4X4(self):
"Get the matrix4X4."
return None
def getMatrixChainTetragrid(self):
'Get the matrix chain tetragrid.'
return self.elementNode.parentNode.xmlObject.getMatrixChainTetragrid()
def getMinimumZ(self):
'Get the minimum z.'
return None
def getPaths(self):
'Get all paths.'
return getAllPaths([], self)
def getTransformedPaths(self):
'Get all transformed paths.'
return getAllTransformedPaths([], self)
def getTransformedVertexes(self):
'Get all transformed vertexes.'
return getAllTransformedVertexes([], self)
def getTriangleMeshes(self):
'Get all triangleMeshes.'
triangleMeshes = []
for archivableObject in self.archivableObjects:
triangleMeshes += archivableObject.getTriangleMeshes()
return triangleMeshes
def getType(self):
'Get type.'
return self.__class__.__name__
def getVertexes(self):
'Get all vertexes.'
return getAllVertexes([], self)
def getVisible(self):
'Get visible.'
return False
def getXMLLocalName(self):
'Get xml local name.'
return self.__class__.__name__.lower()
def setToElementNode(self, elementNode):
'Set the shape of this carvable object info.'
self.elementNode = elementNode
elementNode.parentNode.xmlObject.archivableObjects.append(self)
def transformGeometryOutput(self, geometryOutput):
'Transform the geometry output by the local matrix4x4.'
if self.getMatrix4X4() != None:
matrix.transformVector3sByMatrix(self.getMatrix4X4().tetragrid, matrix.getVertexes(geometryOutput))

View File

@ -1,162 +0,0 @@
"""
Face of a triangle mesh.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities import xml_simple_reader
from fabmetheus_utilities import xml_simple_writer
import cStringIO
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addFaces(geometryOutput, faces):
'Add the faces.'
if geometryOutput.__class__ == list:
for element in geometryOutput:
addFaces(element, faces)
return
if geometryOutput.__class__ != dict:
return
for geometryOutputKey in geometryOutput.keys():
geometryOutputValue = geometryOutput[geometryOutputKey]
if geometryOutputKey == 'face':
for face in geometryOutputValue:
faces.append(face)
else:
addFaces(geometryOutputValue, faces)
def addGeometryList(elementNode, faces):
"Add vertex elements to an xml element."
for face in faces:
faceElement = xml_simple_reader.ElementNode()
face.addToAttributes( faceElement.attributes )
faceElement.localName = 'face'
faceElement.parentNode = elementNode
elementNode.childNodes.append( faceElement )
def getCommonVertexIndex( edgeFirst, edgeSecond ):
"Get the vertex index that both edges have in common."
for edgeFirstVertexIndex in edgeFirst.vertexIndexes:
if edgeFirstVertexIndex == edgeSecond.vertexIndexes[0] or edgeFirstVertexIndex == edgeSecond.vertexIndexes[1]:
return edgeFirstVertexIndex
print("Inconsistent GNU Triangulated Surface")
print(edgeFirst)
print(edgeSecond)
return 0
def getFaces(geometryOutput):
'Get the faces.'
faces = []
addFaces(geometryOutput, faces)
return faces
def processElementNode(elementNode):
"Process the xml element."
face = Face()
face.index = len(elementNode.parentNode.xmlObject.faces)
for vertexIndexIndex in xrange(3):
face.vertexIndexes.append(evaluate.getEvaluatedInt(None, elementNode, 'vertex' + str(vertexIndexIndex)))
elementNode.parentNode.xmlObject.faces.append(face)
class Edge(object):
"An edge of a triangle mesh."
def __init__(self):
"Set the face indexes to None."
self.faceIndexes = []
self.vertexIndexes = []
self.zMaximum = None
self.zMinimum = None
def __repr__(self):
"Get the string representation of this Edge."
return str( self.index ) + ' ' + str( self.faceIndexes ) + ' ' + str(self.vertexIndexes)
def addFaceIndex( self, faceIndex ):
"Add first None face index to input face index."
self.faceIndexes.append( faceIndex )
def getFromVertexIndexes( self, edgeIndex, vertexIndexes ):
"Initialize from two vertex indices."
self.index = edgeIndex
self.vertexIndexes = vertexIndexes[:]
self.vertexIndexes.sort()
return self
class Face(object):
"A face of a triangle mesh."
def __init__(self):
"Initialize."
self.edgeIndexes = []
self.index = None
self.vertexIndexes = []
def __repr__(self):
"Get the string representation of this object info."
output = cStringIO.StringIO()
self.addXML( 2, output )
return output.getvalue()
def addToAttributes(self, attributes):
"Add to the attribute dictionary."
for vertexIndexIndex in xrange(len(self.vertexIndexes)):
vertexIndex = self.vertexIndexes[vertexIndexIndex]
attributes['vertex' + str(vertexIndexIndex)] = str(vertexIndex)
def addXML(self, depth, output):
"Add the xml for this object."
attributes = {}
self.addToAttributes(attributes)
xml_simple_writer.addClosedXMLTag( attributes, depth, 'face', output )
def copy(self):
'Get the copy of this face.'
faceCopy = Face()
faceCopy.edgeIndexes = self.edgeIndexes[:]
faceCopy.index = self.index
faceCopy.vertexIndexes = self.vertexIndexes[:]
return faceCopy
def getFromEdgeIndexes( self, edgeIndexes, edges, faceIndex ):
"Initialize from edge indices."
if len(self.vertexIndexes) > 0:
return
self.index = faceIndex
self.edgeIndexes = edgeIndexes
for edgeIndex in edgeIndexes:
edges[ edgeIndex ].addFaceIndex( faceIndex )
for triangleIndex in xrange(3):
indexFirst = ( 3 - triangleIndex ) % 3
indexSecond = ( 4 - triangleIndex ) % 3
self.vertexIndexes.append( getCommonVertexIndex( edges[ edgeIndexes[ indexFirst ] ], edges[ edgeIndexes[ indexSecond ] ] ) )
return self
def setEdgeIndexesToVertexIndexes( self, edges, edgeTable ):
"Set the edge indexes to the vertex indexes."
if len(self.edgeIndexes) > 0:
return
for triangleIndex in xrange(3):
indexFirst = ( 3 - triangleIndex ) % 3
indexSecond = ( 4 - triangleIndex ) % 3
vertexIndexFirst = self.vertexIndexes[ indexFirst ]
vertexIndexSecond = self.vertexIndexes[ indexSecond ]
vertexIndexPair = [ vertexIndexFirst, vertexIndexSecond ]
vertexIndexPair.sort()
edgeIndex = len( edges )
if str( vertexIndexPair ) in edgeTable:
edgeIndex = edgeTable[ str( vertexIndexPair ) ]
else:
edgeTable[ str( vertexIndexPair ) ] = edgeIndex
edge = Edge().getFromVertexIndexes( edgeIndex, vertexIndexPair )
edges.append( edge )
edges[ edgeIndex ].addFaceIndex( self.index )
self.edgeIndexes.append( edgeIndex )

View File

@ -1,202 +0,0 @@
"""
Path.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_tools import dictionary
from fabmetheus_utilities.geometry.geometry_tools import vertex
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import svg_writer
from fabmetheus_utilities import xml_simple_reader
from fabmetheus_utilities import xml_simple_writer
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def convertElementNode(elementNode, geometryOutput):
'Convert the xml element by geometryOutput.'
if geometryOutput == None:
return
if len(geometryOutput) < 1:
return
if len(geometryOutput) == 1:
firstLoop = geometryOutput[0]
if firstLoop.__class__ == list:
geometryOutput = firstLoop
firstElement = geometryOutput[0]
if firstElement.__class__ == list:
if len(firstElement) > 1:
convertElementNodeRenameByPaths(elementNode, geometryOutput)
else:
convertElementNodeByPath(elementNode, firstElement)
else:
convertElementNodeByPath(elementNode, geometryOutput)
def convertElementNodeByPath(elementNode, geometryOutput):
'Convert the xml element to a path xml element.'
createLinkPath(elementNode)
elementNode.xmlObject.vertexes = geometryOutput
vertex.addGeometryList(elementNode, geometryOutput)
def convertElementNodeRenameByPaths(elementNode, geometryOutput):
'Convert the xml element to a path xml element and add paths.'
createLinkPath(elementNode)
for geometryOutputChild in geometryOutput:
pathElement = xml_simple_reader.ElementNode()
pathElement.setParentAddToChildNodes(elementNode)
convertElementNodeByPath(pathElement, geometryOutputChild)
def createLinkPath(elementNode):
'Create and link a path object.'
elementNode.localName = 'path'
elementNode.linkObject(Path())
def processElementNode(elementNode):
'Process the xml element.'
evaluate.processArchivable(Path, elementNode)
class Path(dictionary.Dictionary):
'A path.'
def __init__(self):
'Add empty lists.'
dictionary.Dictionary.__init__(self)
self.matrix4X4 = matrix.Matrix()
self.oldChainTetragrid = None
self.transformedPath = None
self.vertexes = []
def addXMLInnerSection(self, depth, output):
'Add the xml section for this object.'
if self.matrix4X4 != None:
self.matrix4X4.addXML(depth, output)
xml_simple_writer.addXMLFromVertexes(depth, output, self.vertexes)
def getFabricationExtension(self):
'Get fabrication extension.'
return 'svg'
def getFabricationText(self, addLayerTemplate):
'Get fabrication text.'
carving = SVGFabricationCarving(addLayerTemplate, self.elementNode)
carving.setCarveLayerHeight(setting.getSheetThickness(self.elementNode))
carving.processSVGElement(self.elementNode.getOwnerDocument().fileName)
return str(carving)
def getMatrix4X4(self):
"Get the matrix4X4."
return self.matrix4X4
def getMatrixChainTetragrid(self):
'Get the matrix chain tetragrid.'
return matrix.getTetragridTimesOther(self.elementNode.parentNode.xmlObject.getMatrixChainTetragrid(), self.matrix4X4.tetragrid)
def getPaths(self):
'Get all paths.'
self.transformedPath = None
if len(self.vertexes) > 0:
return dictionary.getAllPaths([self.vertexes], self)
return dictionary.getAllPaths([], self)
def getTransformedPaths(self):
'Get all transformed paths.'
if self.elementNode == None:
return dictionary.getAllPaths([self.vertexes], self)
chainTetragrid = self.getMatrixChainTetragrid()
if self.oldChainTetragrid != chainTetragrid:
self.oldChainTetragrid = chainTetragrid
self.transformedPath = None
if self.transformedPath == None:
self.transformedPath = matrix.getTransformedVector3s(chainTetragrid, self.vertexes)
if len(self.transformedPath) > 0:
return dictionary.getAllTransformedPaths([self.transformedPath], self)
return dictionary.getAllTransformedPaths([], self)
class SVGFabricationCarving(object):
'An svg carving.'
def __init__(self, addLayerTemplate, elementNode):
'Add empty lists.'
self.addLayerTemplate = addLayerTemplate
self.elementNode = elementNode
self.layerHeight = 1.0
self.loopLayers = []
def __repr__(self):
'Get the string representation of this carving.'
return self.getCarvedSVG()
def addXML(self, depth, output):
'Add xml for this object.'
xml_simple_writer.addXMLFromObjects(depth, self.loopLayers, output)
def getCarveBoundaryLayers(self):
'Get the boundary layers.'
return self.loopLayers
def getCarveCornerMaximum(self):
'Get the corner maximum of the vertexes.'
return self.cornerMaximum
def getCarveCornerMinimum(self):
'Get the corner minimum of the vertexes.'
return self.cornerMinimum
def getCarvedSVG(self):
'Get the carved svg text.'
return svg_writer.getSVGByLoopLayers(self.addLayerTemplate, self, self.loopLayers)
def getCarveLayerHeight(self):
'Get the layer height.'
return self.layerHeight
def getFabmetheusXML(self):
'Return the fabmetheus XML.'
return self.elementNode.getOwnerDocument().getOriginalRoot()
def getInterpretationSuffix(self):
'Return the suffix for a carving.'
return 'svg'
def processSVGElement(self, fileName):
'Parse SVG element and store the layers.'
self.fileName = fileName
paths = self.elementNode.xmlObject.getPaths()
oldZ = None
self.loopLayers = []
loopLayer = None
for path in paths:
if len(path) > 0:
z = path[0].z
if z != oldZ:
loopLayer = euclidean.LoopLayer(z)
self.loopLayers.append(loopLayer)
oldZ = z
loopLayer.loops.append(euclidean.getComplexPath(path))
if len(self.loopLayers) < 1:
return
self.cornerMaximum = Vector3(-987654321.0, -987654321.0, -987654321.0)
self.cornerMinimum = Vector3(987654321.0, 987654321.0, 987654321.0)
svg_writer.setSVGCarvingCorners(self.cornerMaximum, self.cornerMinimum, self.layerHeight, self.loopLayers)
def setCarveImportRadius( self, importRadius ):
'Set the import radius.'
pass
def setCarveIsCorrectMesh( self, isCorrectMesh ):
'Set the is correct mesh flag.'
pass
def setCarveLayerHeight( self, layerHeight ):
'Set the layer height.'
self.layerHeight = layerHeight

View File

@ -1,48 +0,0 @@
"""
Arc vertexes.
From:
http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import svg_reader
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getArcPath(elementNode):
"Get the arc path.rx ry x-axis-rotation large-arc-flag sweep-flag"
begin = elementNode.getPreviousVertex(Vector3())
end = evaluate.getVector3FromElementNode(elementNode)
largeArcFlag = evaluate.getEvaluatedBoolean(True, elementNode, 'largeArcFlag')
radius = lineation.getComplexByPrefix(elementNode, 'radius', complex(1.0, 1.0))
sweepFlag = evaluate.getEvaluatedBoolean(True, elementNode, 'sweepFlag')
xAxisRotation = math.radians(evaluate.getEvaluatedFloat(0.0, elementNode, 'xAxisRotation'))
arcComplexes = svg_reader.getArcComplexes(begin.dropAxis(), end.dropAxis(), largeArcFlag, radius, sweepFlag, xAxisRotation)
path = []
if len(arcComplexes) < 1:
return []
incrementZ = (end.z - begin.z) / float(len(arcComplexes))
z = begin.z
for pointIndex in xrange(len(arcComplexes)):
pointComplex = arcComplexes[pointIndex]
z += incrementZ
path.append(Vector3(pointComplex.real, pointComplex.imag, z))
if len(path) > 0:
path[-1] = end
return path
def processElementNode(elementNode):
"Process the xml element."
elementNode.parentNode.xmlObject.vertexes += getArcPath(elementNode)

View File

@ -1,56 +0,0 @@
"""
Cubic vertexes.
From:
http://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import svg_reader
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getCubicPath(elementNode):
"Get the cubic path."
end = evaluate.getVector3FromElementNode(elementNode)
previousElementNode = elementNode.getPreviousElementNode()
if previousElementNode == None:
print('Warning, can not get previousElementNode in getCubicPath in cubic for:')
print(elementNode)
return [end]
begin = elementNode.getPreviousVertex(Vector3())
evaluatedControlPoints = evaluate.getTransformedPathByKey([], elementNode, 'controlPoints')
if len(evaluatedControlPoints) > 1:
return getCubicPathByBeginEnd(begin, evaluatedControlPoints, elementNode, end)
controlPoint0 = evaluate.getVector3ByPrefix(None, elementNode, 'controlPoint0')
controlPoint1 = evaluate.getVector3ByPrefix(None, elementNode, 'controlPoint1')
if len(evaluatedControlPoints) == 1:
controlPoint1 = evaluatedControlPoints[0]
if controlPoint0 == None:
oldControlPoint = evaluate.getVector3ByPrefixes(previousElementNode, ['controlPoint','controlPoint1'], None)
if oldControlPoint == None:
oldControlPoints = evaluate.getTransformedPathByKey([], previousElementNode, 'controlPoints')
if len(oldControlPoints) > 0:
oldControlPoint = oldControlPoints[-1]
if oldControlPoint == None:
oldControlPoint = end
controlPoint0 = begin + begin - oldControlPoint
return getCubicPathByBeginEnd(begin, [controlPoint0, controlPoint1], elementNode, end)
def getCubicPathByBeginEnd(begin, controlPoints, elementNode, end):
"Get the cubic path by begin and end."
return svg_reader.getCubicPoints(begin, controlPoints, end, lineation.getNumberOfBezierPoints(begin, elementNode, end))
def processElementNode(elementNode):
"Process the xml element."
elementNode.parentNode.xmlObject.vertexes += getCubicPath(elementNode)

View File

@ -1,43 +0,0 @@
"""
Quadratic vertexes.
From:
http://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import svg_reader
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getQuadraticPath(elementNode):
"Get the quadratic path."
end = evaluate.getVector3FromElementNode(elementNode)
previousElementNode = elementNode.getPreviousElementNode()
if previousElementNode == None:
print('Warning, can not get previousElementNode in getQuadraticPath in quadratic for:')
print(elementNode)
return [end]
begin = elementNode.getPreviousVertex(Vector3())
controlPoint = evaluate.getVector3ByPrefix(None, elementNode, 'controlPoint')
if controlPoint == None:
oldControlPoint = evaluate.getVector3ByPrefixes(previousElementNode, ['controlPoint','controlPoint1'], None)
if oldControlPoint == None:
oldControlPoint = end
controlPoint = begin + begin - oldControlPoint
evaluate.addVector3ToElementNode(elementNode, 'controlPoint', controlPoint)
return svg_reader.getQuadraticPoints(begin, controlPoint, end, lineation.getNumberOfBezierPoints(begin, elementNode, end))
def processElementNode(elementNode):
"Process the xml element."
elementNode.parentNode.xmlObject.vertexes += getQuadraticPath(elementNode)

View File

@ -1,43 +0,0 @@
"""
Vertex of a triangle mesh.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities import xml_simple_reader
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addGeometryList(elementNode, vertexes):
"Add vertex elements to an xml element."
for vertex in vertexes:
vertexElement = getUnboundVertexElement(vertex)
vertexElement.parentNode = elementNode
elementNode.childNodes.append( vertexElement )
def addVertexToAttributes(attributes, vertex):
"Add to the attribute dictionary."
if vertex.x != 0.0:
attributes['x'] = str(vertex.x)
if vertex.y != 0.0:
attributes['y'] = str(vertex.y)
if vertex.z != 0.0:
attributes['z'] = str(vertex.z)
def getUnboundVertexElement(vertex):
"Add vertex element to an xml element."
vertexElement = xml_simple_reader.ElementNode()
addVertexToAttributes(vertexElement.attributes, vertex)
vertexElement.localName = 'vertex'
return vertexElement
def processElementNode(elementNode):
"Process the xml element."
elementNode.parentNode.xmlObject.vertexes.append(evaluate.getVector3FromElementNode(elementNode))

View File

@ -1,193 +0,0 @@
"""
This page is in the table of contents.
The xml.py script is an import translator plugin to get a carving from an Art of Illusion xml file.
An import plugin is a script in the interpret_plugins folder which has the function getCarving. It is meant to be run from the interpret tool. To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
The getCarving function takes the file name of an xml file and returns the carving.
An xml file can be exported from Art of Illusion by going to the "File" menu, then going into the "Export" menu item, then picking the XML choice. This will bring up the XML file chooser window, choose a place to save the file then click "OK". Leave the "compressFile" checkbox unchecked. All the objects from the scene will be exported, this plugin will ignore the light and camera. If you want to fabricate more than one object at a time, you can have multiple objects in the Art of Illusion scene and they will all be carved, then fabricated together.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import boolean_solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import xml_simple_writer
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getEmptyZLoops(archivableObjects, importRadius, shouldPrintWarning, z, zoneArrangement):
'Get loops at empty z level.'
emptyZ = zoneArrangement.getEmptyZ(z)
visibleObjects = evaluate.getVisibleObjects(archivableObjects)
visibleObjectLoopsList = boolean_solid.getVisibleObjectLoopsList(importRadius, visibleObjects, emptyZ)
loops = euclidean.getConcatenatedList(visibleObjectLoopsList)
if euclidean.isLoopListIntersecting(loops):
loops = boolean_solid.getLoopsUnion(importRadius, visibleObjectLoopsList)
if shouldPrintWarning:
print('Warning, the triangle mesh slice intersects itself in getExtruderPaths in boolean_geometry.')
print('Something will still be printed, but there is no guarantee that it will be the correct shape.')
print('Once the gcode is saved, you should check over the layer with a z of:')
print(z)
return loops
def getLoopLayers(archivableObjects, importRadius, layerHeight, maximumZ, shouldPrintWarning, z, zoneArrangement):
'Get loop layers.'
loopLayers = []
while z <= maximumZ:
triangle_mesh.getLoopLayerAppend(loopLayers, z).loops = getEmptyZLoops(archivableObjects, importRadius, True, z, zoneArrangement)
z += layerHeight
return loopLayers
def getMinimumZ(geometryObject):
'Get the minimum of the minimum z of the archivableObjects and the object.'
booleanGeometry = BooleanGeometry()
booleanGeometry.archivableObjects = geometryObject.archivableObjects
booleanGeometry.importRadius = setting.getImportRadius(geometryObject.elementNode)
booleanGeometry.layerHeight = setting.getLayerHeight(geometryObject.elementNode)
archivableMinimumZ = booleanGeometry.getMinimumZ()
geometryMinimumZ = geometryObject.getMinimumZ()
if archivableMinimumZ == None:
return geometryMinimumZ
if geometryMinimumZ == None:
return archivableMinimumZ
return min(archivableMinimumZ, geometryMinimumZ)
class BooleanGeometry(object):
'A boolean geometry scene.'
def __init__(self):
'Add empty lists.'
self.archivableObjects = []
self.belowLoops = []
self.importRadius = 0.6
self.layerHeight = 0.4
self.loopLayers = []
def __repr__(self):
'Get the string representation of this carving.'
elementNode = None
if len(self.archivableObjects) > 0:
elementNode = self.archivableObjects[0].elementNode
output = xml_simple_writer.getBeginGeometryXMLOutput(elementNode)
self.addXML( 1, output )
return xml_simple_writer.getEndGeometryXMLString(output)
def addXML(self, depth, output):
'Add xml for this object.'
xml_simple_writer.addXMLFromObjects( depth, self.archivableObjects, output )
def getCarveBoundaryLayers(self):
'Get the boundary layers.'
if self.getMinimumZ() == None:
return []
z = self.minimumZ + 0.5 * self.layerHeight
self.loopLayers = getLoopLayers(self.archivableObjects, self.importRadius, self.layerHeight, self.maximumZ, True, z, self.zoneArrangement)
self.cornerMaximum = Vector3(-912345678.0, -912345678.0, -912345678.0)
self.cornerMinimum = Vector3(912345678.0, 912345678.0, 912345678.0)
for loopLayer in self.loopLayers:
for loop in loopLayer.loops:
for point in loop:
pointVector3 = Vector3(point.real, point.imag, loopLayer.z)
self.cornerMaximum.maximize(pointVector3)
self.cornerMinimum.minimize(pointVector3)
self.cornerMaximum.z += self.halfHeight
self.cornerMinimum.z -= self.halfHeight
for loopLayerIndex in xrange(len(self.loopLayers) -1, -1, -1):
loopLayer = self.loopLayers[loopLayerIndex]
if len(loopLayer.loops) > 0:
return self.loopLayers[: loopLayerIndex + 1]
return []
def getCarveCornerMaximum(self):
'Get the corner maximum of the vertexes.'
return self.cornerMaximum
def getCarveCornerMinimum(self):
'Get the corner minimum of the vertexes.'
return self.cornerMinimum
def getCarveLayerHeight(self):
'Get the layer height.'
return self.layerHeight
def getFabmetheusXML(self):
'Return the fabmetheus XML.'
if len(self.archivableObjects) > 0:
return self.archivableObjects[0].elementNode.getOwnerDocument().getOriginalRoot()
return None
def getInterpretationSuffix(self):
'Return the suffix for a boolean carving.'
return 'xml'
def getMatrix4X4(self):
'Get the matrix4X4.'
return None
def getMatrixChainTetragrid(self):
'Get the matrix chain tetragrid.'
return None
def getMinimumZ(self):
'Get the minimum z.'
vertexes = []
for visibleObject in evaluate.getVisibleObjects(self.archivableObjects):
vertexes += visibleObject.getTransformedVertexes()
if len(vertexes) < 1:
return None
self.maximumZ = -912345678.0
self.minimumZ = 912345678.0
for vertex in vertexes:
self.maximumZ = max(self.maximumZ, vertex.z)
self.minimumZ = min(self.minimumZ, vertex.z)
self.zoneArrangement = triangle_mesh.ZoneArrangement(self.layerHeight, vertexes)
self.halfHeight = 0.5 * self.layerHeight
self.setActualMinimumZ()
return self.minimumZ
def getNumberOfEmptyZLoops(self, z):
'Get number of empty z loops.'
return len(getEmptyZLoops(self.archivableObjects, self.importRadius, False, z, self.zoneArrangement))
def setActualMinimumZ(self):
'Get the actual minimum z at the lowest rotated boundary layer.'
halfHeightOverMyriad = 0.0001 * self.halfHeight
while self.minimumZ < self.maximumZ:
if self.getNumberOfEmptyZLoops(self.minimumZ + halfHeightOverMyriad) > 0:
if self.getNumberOfEmptyZLoops(self.minimumZ - halfHeightOverMyriad) < 1:
return
increment = -self.halfHeight
while abs(increment) > halfHeightOverMyriad:
self.minimumZ += increment
increment = 0.5 * abs(increment)
if self.getNumberOfEmptyZLoops(self.minimumZ) > 0:
increment = -increment
self.minimumZ = round(self.minimumZ, -int(round(math.log10(halfHeightOverMyriad) + 1.5)))
return
self.minimumZ += self.layerHeight
def setCarveImportRadius( self, importRadius ):
'Set the import radius.'
self.importRadius = importRadius
def setCarveIsCorrectMesh( self, isCorrectMesh ):
'Set the is correct mesh flag.'
self.isCorrectMesh = isCorrectMesh
def setCarveLayerHeight( self, layerHeight ):
'Set the layer height.'
self.layerHeight = layerHeight

View File

@ -1,229 +0,0 @@
"""
This page is in the table of contents.
The xml.py script is an import translator plugin to get a carving from an Art of Illusion xml file.
An import plugin is a script in the interpret_plugins folder which has the function getCarving. It is meant to be run from the interpret tool. To ensure that the plugin works on platforms which do not handle file capitalization properly, give the plugin a lower case name.
The getCarving function takes the file name of an xml file and returns the carving.
An xml file can be exported from Art of Illusion by going to the "File" menu, then going into the "Export" menu item, then picking the XML choice. This will bring up the XML file chooser window, choose a place to save the file then click "OK". Leave the "compressFile" checkbox unchecked. All the objects from the scene will be exported, this plugin will ignore the light and camera. If you want to fabricate more than one object at a time, you can have multiple objects in the Art of Illusion scene and they will all be carved, then fabricated together.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import group
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import intercircle
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addLineLoopsIntersections( loopLoopsIntersections, loops, pointBegin, pointEnd ):
'Add intersections of the line with the loops.'
normalizedSegment = pointEnd - pointBegin
normalizedSegmentLength = abs( normalizedSegment )
if normalizedSegmentLength <= 0.0:
return
lineLoopsIntersections = []
normalizedSegment /= normalizedSegmentLength
segmentYMirror = complex(normalizedSegment.real, -normalizedSegment.imag)
pointBeginRotated = segmentYMirror * pointBegin
pointEndRotated = segmentYMirror * pointEnd
addLoopsXSegmentIntersections( lineLoopsIntersections, loops, pointBeginRotated.real, pointEndRotated.real, segmentYMirror, pointBeginRotated.imag )
for lineLoopsIntersection in lineLoopsIntersections:
point = complex( lineLoopsIntersection, pointBeginRotated.imag ) * normalizedSegment
loopLoopsIntersections.append(point)
def addLineXSegmentIntersection( lineLoopsIntersections, segmentFirstX, segmentSecondX, vector3First, vector3Second, y ):
'Add intersections of the line with the x segment.'
xIntersection = euclidean.getXIntersectionIfExists( vector3First, vector3Second, y )
if xIntersection == None:
return
if xIntersection < min( segmentFirstX, segmentSecondX ):
return
if xIntersection <= max( segmentFirstX, segmentSecondX ):
lineLoopsIntersections.append( xIntersection )
def addLoopLoopsIntersections( loop, loopsLoopsIntersections, otherLoops ):
'Add intersections of the loop with the other loops.'
for pointIndex in xrange(len(loop)):
pointBegin = loop[pointIndex]
pointEnd = loop[(pointIndex + 1) % len(loop)]
addLineLoopsIntersections( loopsLoopsIntersections, otherLoops, pointBegin, pointEnd )
def addLoopsXSegmentIntersections( lineLoopsIntersections, loops, segmentFirstX, segmentSecondX, segmentYMirror, y ):
'Add intersections of the loops with the x segment.'
for loop in loops:
addLoopXSegmentIntersections( lineLoopsIntersections, loop, segmentFirstX, segmentSecondX, segmentYMirror, y )
def addLoopXSegmentIntersections( lineLoopsIntersections, loop, segmentFirstX, segmentSecondX, segmentYMirror, y ):
'Add intersections of the loop with the x segment.'
rotatedLoop = euclidean.getRotatedComplexes( segmentYMirror, loop )
for pointIndex in xrange( len( rotatedLoop ) ):
pointFirst = rotatedLoop[pointIndex]
pointSecond = rotatedLoop[ (pointIndex + 1) % len( rotatedLoop ) ]
addLineXSegmentIntersection( lineLoopsIntersections, segmentFirstX, segmentSecondX, pointFirst, pointSecond, y )
def getInBetweenLoopsFromLoops(loops, radius):
'Get the in between loops from loops.'
inBetweenLoops = []
for loop in loops:
inBetweenLoop = []
for pointIndex in xrange(len(loop)):
pointBegin = loop[pointIndex]
pointEnd = loop[(pointIndex + 1) % len(loop)]
intercircle.addPointsFromSegment(pointBegin, pointEnd, inBetweenLoop, radius)
inBetweenLoops.append(inBetweenLoop)
return inBetweenLoops
def getInsetPointsByInsetLoop( insetLoop, inside, loops, radius ):
'Get the inset points of the inset loop inside the loops.'
insetPointsByInsetLoop = []
for pointIndex in xrange( len( insetLoop ) ):
pointBegin = insetLoop[ ( pointIndex + len( insetLoop ) - 1 ) % len( insetLoop ) ]
pointCenter = insetLoop[pointIndex]
pointEnd = insetLoop[ (pointIndex + 1) % len( insetLoop ) ]
if getIsInsetPointInsideLoops( inside, loops, pointBegin, pointCenter, pointEnd, radius ):
insetPointsByInsetLoop.append( pointCenter )
return insetPointsByInsetLoop
def getInsetPointsByInsetLoops( insetLoops, inside, loops, radius ):
'Get the inset points of the inset loops inside the loops.'
insetPointsByInsetLoops = []
for insetLoop in insetLoops:
insetPointsByInsetLoops += getInsetPointsByInsetLoop( insetLoop, inside, loops, radius )
return insetPointsByInsetLoops
def getIsInsetPointInsideLoops( inside, loops, pointBegin, pointCenter, pointEnd, radius ):
'Determine if the inset point is inside the loops.'
centerMinusBegin = euclidean.getNormalized( pointCenter - pointBegin )
centerMinusBeginWiddershins = complex( - centerMinusBegin.imag, centerMinusBegin.real )
endMinusCenter = euclidean.getNormalized( pointEnd - pointCenter )
endMinusCenterWiddershins = complex( - endMinusCenter.imag, endMinusCenter.real )
widdershinsNormalized = euclidean.getNormalized( centerMinusBeginWiddershins + endMinusCenterWiddershins ) * radius
return euclidean.getIsInFilledRegion( loops, pointCenter + widdershinsNormalized ) == inside
def getLoopsDifference(importRadius, loopLists):
'Get difference loops.'
halfImportRadius = 0.5 * importRadius # so that there are no misses on shallow angles
radiusSide = 0.01 * importRadius
negativeLoops = getLoopsUnion(importRadius, loopLists[1 :])
intercircle.directLoops(False, negativeLoops)
positiveLoops = loopLists[0]
intercircle.directLoops(True, positiveLoops)
corners = getInsetPointsByInsetLoops(negativeLoops, True, positiveLoops, radiusSide)
corners += getInsetPointsByInsetLoops(positiveLoops, False, negativeLoops, radiusSide)
allPoints = corners[:]
allPoints += getInsetPointsByInsetLoops(getInBetweenLoopsFromLoops(negativeLoops, halfImportRadius), True, positiveLoops, radiusSide)
allPoints += getInsetPointsByInsetLoops(getInBetweenLoopsFromLoops(positiveLoops, halfImportRadius), False, negativeLoops, radiusSide)
return triangle_mesh.getDescendingAreaOrientedLoops(allPoints, corners, importRadius)
def getLoopsIntersection(importRadius, loopLists):
'Get intersection loops.'
intercircle.directLoopLists(True, loopLists)
if len(loopLists) < 1:
return []
if len(loopLists) < 2:
return loopLists[0]
intercircle.directLoopLists(True, loopLists)
loopsIntersection = loopLists[0]
for loopList in loopLists[1 :]:
loopsIntersection = getLoopsIntersectionByPair(importRadius, loopsIntersection, loopList)
return loopsIntersection
def getLoopsIntersectionByPair(importRadius, loopsFirst, loopsLast):
'Get intersection loops for a pair of loop lists.'
halfImportRadius = 0.5 * importRadius # so that there are no misses on shallow angles
radiusSide = 0.01 * importRadius
corners = []
corners += getInsetPointsByInsetLoops(loopsFirst, True, loopsLast, radiusSide)
corners += getInsetPointsByInsetLoops(loopsLast, True, loopsFirst, radiusSide)
allPoints = corners[:]
allPoints += getInsetPointsByInsetLoops(getInBetweenLoopsFromLoops(loopsFirst, halfImportRadius), True, loopsLast, radiusSide)
allPoints += getInsetPointsByInsetLoops(getInBetweenLoopsFromLoops(loopsLast, halfImportRadius), True, loopsFirst, radiusSide)
return triangle_mesh.getDescendingAreaOrientedLoops(allPoints, corners, importRadius)
def getLoopsListsIntersections( loopsList ):
'Get intersections betweens the loops lists.'
loopsListsIntersections = []
for loopsIndex in xrange( len( loopsList ) ):
loops = loopsList[ loopsIndex ]
for otherLoops in loopsList[ : loopsIndex ]:
loopsListsIntersections += getLoopsLoopsIntersections( loops, otherLoops )
return loopsListsIntersections
def getLoopsLoopsIntersections( loops, otherLoops ):
'Get all the intersections of the loops with the other loops.'
loopsLoopsIntersections = []
for loop in loops:
addLoopLoopsIntersections( loop, loopsLoopsIntersections, otherLoops )
return loopsLoopsIntersections
def getLoopsUnion(importRadius, loopLists):
'Get joined loops sliced through shape.'
allPoints = []
corners = getLoopsListsIntersections(loopLists)
radiusSideNegative = -0.01 * importRadius
intercircle.directLoopLists(True, loopLists)
for loopListIndex in xrange(len(loopLists)):
insetLoops = loopLists[ loopListIndex ]
inBetweenInsetLoops = getInBetweenLoopsFromLoops(insetLoops, importRadius)
otherLoops = euclidean.getConcatenatedList(loopLists[: loopListIndex] + loopLists[loopListIndex + 1 :])
corners += getInsetPointsByInsetLoops(insetLoops, False, otherLoops, radiusSideNegative)
allPoints += getInsetPointsByInsetLoops(inBetweenInsetLoops, False, otherLoops, radiusSideNegative)
allPoints += corners[:]
return triangle_mesh.getDescendingAreaOrientedLoops(allPoints, corners, importRadius)
def getVisibleObjectLoopsList( importRadius, visibleObjects, z ):
'Get visible object loops list.'
visibleObjectLoopsList = []
for visibleObject in visibleObjects:
visibleObjectLoops = visibleObject.getLoops(importRadius, z)
visibleObjectLoopsList.append( visibleObjectLoops )
return visibleObjectLoopsList
class BooleanSolid( group.Group ):
'A boolean solid object.'
def getDifference(self, importRadius, visibleObjectLoopsList):
'Get subtracted loops sliced through shape.'
return getLoopsDifference(importRadius, visibleObjectLoopsList)
def getIntersection(self, importRadius, visibleObjectLoopsList):
'Get intersected loops sliced through shape.'
return getLoopsIntersection(importRadius, visibleObjectLoopsList)
def getLoops(self, importRadius, z):
'Get loops sliced through shape.'
visibleObjects = evaluate.getVisibleObjects(self.archivableObjects)
if len( visibleObjects ) < 1:
return []
visibleObjectLoopsList = getVisibleObjectLoopsList( importRadius, visibleObjects, z )
loops = self.getLoopsFromObjectLoopsList(importRadius, visibleObjectLoopsList)
return euclidean.getSimplifiedLoops( loops, importRadius )
def getLoopsFromObjectLoopsList(self, importRadius, visibleObjectLoopsList):
'Get loops from visible object loops list.'
return self.operationFunction(importRadius, visibleObjectLoopsList)
def getTransformedPaths(self):
'Get all transformed paths.'
importRadius = setting.getImportRadius(self.elementNode)
loopsFromObjectLoopsList = self.getLoopsFromObjectLoopsList(importRadius, self.getComplexTransformedPathLists())
return euclidean.getVector3Paths(loopsFromObjectLoopsList)
def getUnion(self, importRadius, visibleObjectLoopsList):
'Get joined loops sliced through shape.'
return getLoopsUnion(importRadius, visibleObjectLoopsList)
def getXMLLocalName(self):
'Get xml class name.'
return self.operationFunction.__name__.lower()[ len('get') : ]

View File

@ -1,56 +0,0 @@
"""
Boolean geometry utilities.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities import archive
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def _getAccessibleAttribute(attributeName, elementNode):
'Get the accessible attribute.'
functionName = attributeName[len('get') :].lower()
if functionName not in evaluate.globalCreationDictionary:
print('Warning, functionName not in globalCreationDictionary in _getAccessibleAttribute in creation for:')
print(functionName)
print(elementNode)
return None
pluginModule = archive.getModuleWithPath(evaluate.globalCreationDictionary[functionName])
if pluginModule == None:
print('Warning, _getAccessibleAttribute in creation can not get a pluginModule for:')
print(functionName)
print(elementNode)
return None
return Creation(elementNode, pluginModule).getCreation
class Creation(object):
'Class to handle a creation.'
def __init__(self, elementNode, pluginModule):
'Initialize.'
self.elementNode = elementNode
self.pluginModule = pluginModule
def __repr__(self):
"Get the string representation of this creation."
return self.elementNode
def getCreation(self, *arguments):
"Get creation."
dictionary = {'_fromCreationEvaluator': 'true'}
firstArgument = None
if len(arguments) > 0:
firstArgument = arguments[0]
if firstArgument.__class__ == dict:
dictionary.update(firstArgument)
return self.pluginModule.getGeometryOutput(None, self.elementNode.getCopyShallow(dictionary))
copyShallow = self.elementNode.getCopyShallow(dictionary)
return self.pluginModule.getGeometryOutputByArguments(arguments, copyShallow)

View File

@ -1,95 +0,0 @@
"""
Boolean geometry utilities.
"""
from __future__ import absolute_import
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def _getAccessibleAttribute(attributeName, elementNode):
'Get the accessible attribute.'
if attributeName in globalGetAccessibleAttributeSet:
return getattr(Document(elementNode), attributeName, None)
return None
class Document(object):
'Class to handle elementNodes in a document.'
def __init__(self, elementNode):
'Initialize.'
self.elementNode = elementNode
def __repr__(self):
'Get the string representation of this Document.'
return self.elementNode
def getCascadeBoolean(self, defaultBoolean, key):
'Get cascade boolean.'
return self.elementNode.getCascadeBoolean(defaultBoolean, key)
def getCascadeFloat(self, defaultFloat, key):
'Get cascade float.'
return self.elementNode.getCascadeFloat(defaultFloat, key)
def getDocumentElement(self):
'Get document element element.'
return self.elementNode.getDocumentElement()
def getElementByID(self, idKey):
'Get element by id.'
elementByID = self.elementNode.getElementNodeByID(idKey)
if elementByID == None:
print('Warning, could not get elementByID in getElementByID in document for:')
print(idKey)
print(self.elementNode)
return elementByID
def getElementsByName(self, nameKey):
'Get element by name.'
elementsByName = self.elementNode.getElementNodesByName(nameKey)
if elementsByName == None:
print('Warning, could not get elementsByName in getElementsByName in document for:')
print(nameKey)
print(self.elementNode)
return elementsByName
def getElementsByTag(self, tagKey):
'Get element by tag.'
elementsByTag = self.elementNode.getElementNodesByTag(tagKey)
if elementsByTag == None:
print('Warning, could not get elementsByTag in getElementsByTag in document for:')
print(tagKey)
print(self.elementNode)
return elementsByTag
def getParentNode(self):
'Get parentNode element.'
return self.elementNode.parentNode
def getPrevious(self):
'Get previous element.'
return self.getPreviousElement()
def getPreviousElement(self):
'Get previous element.'
return self.elementNode.getPreviousElementNode()
def getPreviousVertex(self):
'Get previous element.'
return self.elementNode.getPreviousVertex()
def getSelfElement(self):
'Get self element.'
return self.elementNode
globalAccessibleAttributeDictionary = 'getCascadeBoolean getCascadeFloat getDocumentElement getElementByID getElementsByName'.split()
globalAccessibleAttributeDictionary += 'getElementsByTag getParentNode getPrevious getPreviousElement getPreviousVertex'.split()
globalAccessibleAttributeDictionary += 'getSelfElement'.split()
globalGetAccessibleAttributeSet = set(globalAccessibleAttributeDictionary)

View File

@ -1,178 +0,0 @@
"""
Boolean geometry utilities.
"""
from __future__ import absolute_import
from skeinforge_application.skeinforge_utilities import skeinforge_craft
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def _getAccessibleAttribute(attributeName, elementNode):
'Get the accessible attribute.'
if attributeName in globalGetAccessibleAttributeSet:
return getattr(Setting(elementNode), attributeName, None)
return None
def getCascadeFloatWithoutSelf(defaultFloat, elementNode, key):
'Get the cascade float.'
if key in elementNode.attributes:
value = elementNode.attributes[key]
functionName = 'get' + key[0].upper() + key[1 :]
if functionName in value:
if elementNode.parentNode == None:
return defaultFloat
else:
elementNode = elementNode.parentNode
return elementNode.getCascadeFloat(defaultFloat, key)
def getEdgeWidth(elementNode):
'Get the edge width.'
if elementNode == None:
return 0.72
preferences = skeinforge_craft.getCraftPreferences('carve')
layerHeight = skeinforge_craft.getCraftValue('Layer Height', preferences)
layerHeight = getCascadeFloatWithoutSelf(layerHeight, elementNode, 'layerHeight')
edgeWidthOverHeight = skeinforge_craft.getCraftValue('Edge Width over Height', preferences)
edgeWidthOverHeight = getCascadeFloatWithoutSelf(edgeWidthOverHeight, elementNode, 'edgeWidthOverHeight')
return getCascadeFloatWithoutSelf(edgeWidthOverHeight * layerHeight, elementNode, 'edgeWidth')
def getImportCoarseness(elementNode, preferences=None):
'Get the importCoarseness.'
if elementNode == None:
return 1.0
if preferences == None:
preferences = skeinforge_craft.getCraftPreferences('carve')
importCoarseness = skeinforge_craft.getCraftValue('Import Coarseness', preferences)
return getCascadeFloatWithoutSelf(importCoarseness, elementNode, 'importCoarseness')
def getImportRadius(elementNode):
'Get the importRadius.'
if elementNode == None:
return 0.36
preferences = skeinforge_craft.getCraftPreferences('carve')
importCoarseness = getImportCoarseness(elementNode, preferences)
layerHeight = skeinforge_craft.getCraftValue('Layer Height', preferences)
layerHeight = getCascadeFloatWithoutSelf(layerHeight, elementNode, 'layerHeight')
edgeWidthOverHeight = skeinforge_craft.getCraftValue('Edge Width over Height', preferences)
edgeWidthOverHeight = getCascadeFloatWithoutSelf(edgeWidthOverHeight, elementNode, 'edgeWidthOverHeight')
return getCascadeFloatWithoutSelf(0.5 * importCoarseness * layerHeight * edgeWidthOverHeight, elementNode, 'importRadius')
def getInteriorOverhangAngle(elementNode):
'Get the interior overhang support angle in degrees.'
return getCascadeFloatWithoutSelf(30.0, elementNode, 'interiorOverhangAngle')
def getInteriorOverhangRadians(elementNode):
'Get the interior overhang support angle in radians.'
return math.radians(getInteriorOverhangAngle(elementNode))
def getLayerHeight(elementNode):
'Get the layer height.'
if elementNode == None:
return 0.4
preferences = skeinforge_craft.getCraftPreferences('carve')
return getCascadeFloatWithoutSelf(skeinforge_craft.getCraftValue('Layer Height', preferences), elementNode, 'layerHeight')
def getOverhangAngle(elementNode):
'Get the overhang support angle in degrees.'
return getCascadeFloatWithoutSelf(45.0, elementNode, 'overhangAngle')
def getOverhangRadians(elementNode):
'Get the overhang support angle in radians.'
return math.radians(getOverhangAngle(elementNode))
def getOverhangSpan(elementNode):
'Get the overhang span.'
return getCascadeFloatWithoutSelf(2.0 * getLayerHeight(elementNode), elementNode, 'overhangSpan')
def getPrecision(elementNode):
'Get the cascade precision.'
return getCascadeFloatWithoutSelf(0.2 * getLayerHeight(elementNode), elementNode, 'precision')
def getSheetThickness(elementNode):
'Get the sheet thickness.'
return getCascadeFloatWithoutSelf(3.0, elementNode, 'sheetThickness')
def getTwistPrecision(elementNode):
'Get the twist precision in degrees.'
return getCascadeFloatWithoutSelf(5.0, elementNode, 'twistPrecision')
def getTwistPrecisionRadians(elementNode):
'Get the twist precision in radians.'
return math.radians(getTwistPrecision(elementNode))
class Setting(object):
'Class to get handle elementNodes in a setting.'
def __init__(self, elementNode):
'Initialize.'
self.elementNode = elementNode
def __repr__(self):
'Get the string representation of this Setting.'
return self.elementNode
def getEdgeWidth(self):
'Get the edge width.'
return getEdgeWidth(self.elementNode)
def getImportCoarseness(self):
'Get the importCoarseness.'
return getImportCoarseness(self.elementNode)
def getImportRadius(self):
'Get the importRadius.'
return getImportRadius(self.elementNode)
def getInteriorOverhangAngle(self):
'Get the interior overhang support angle in degrees.'
return getInteriorOverhangAngle(self.elementNode)
def getInteriorOverhangRadians(self):
'Get the interior overhang support angle in radians.'
return getInteriorOverhangRadians(self.elementNode)
def getLayerHeight(self):
'Get the layer height.'
return getLayerHeight(self.elementNode)
def getOverhangAngle(self):
'Get the overhang support angle in degrees.'
return getOverhangAngle(self.elementNode)
def getOverhangRadians(self):
'Get the overhang support angle in radians.'
return getOverhangRadians(self.elementNode)
def getOverhangSpan(self):
'Get the overhang span.'
return getOverhangSpan(self.elementNode)
def getPrecision(self):
'Get the cascade precision.'
return getPrecision(self.elementNode)
def getSheetThickness(self):
'Get the sheet thickness.'
return getSheetThickness(self.elementNode)
def getTwistPrecision(self):
'Get the twist precision in degrees.'
return getTwistPrecision(self.elementNode)
def getTwistPrecisionRadians(self):
'Get the twist precision in radians.'
return getTwistPrecisionRadians(self.elementNode)
globalAccessibleAttributeDictionary = 'getEdgeWidth getImportCoarseness getImportRadius getInteriorOverhangAngle getInteriorOverhangRadians'.split()
globalAccessibleAttributeDictionary += 'getLayerHeight getOverhangSpan getOverhangAngle getOverhangRadians'.split()
globalAccessibleAttributeDictionary += 'getPrecision getSheetThickness getTwistPrecision getTwistPrecisionRadians'.split()
globalGetAccessibleAttributeSet = set(globalAccessibleAttributeDictionary)

View File

@ -1,100 +0,0 @@
"""
Dictionary object attributes.
"""
from __future__ import absolute_import
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def _getAccessibleAttribute(attributeName, dictionaryObject):
'Get the accessible attribute.'
if attributeName in globalNativeFunctionSet:
return getattr(dictionaryObject, attributeName, None)
if attributeName in globalGetAccessibleAttributeSet:
stringAttribute = DictionaryAttribute(dictionaryObject)
return getattr(stringAttribute, attributeName, None)
return None
class DictionaryAttribute(object):
'Class to handle a dictionary.'
def __init__(self, dictionaryObject):
'Initialize.'
self.dictionaryObject = dictionaryObject
def __repr__(self):
"Get the dictionary representation of this DictionaryAttribute."
return str(self.dictionaryObject)
def count(self, value):
'Get the count.'
countTotal = 0
for key, iteratorValue in self.dictionaryObject.iteritems():
if iteratorValue == value:
countTotal += 1
return countTotal
def delete(self, arguments):
'Get the delete dictionary.'
if arguments.__class__ != list:
del self.dictionaryObject[arguments]
return self.dictionaryObject
if len(arguments) == 0:
self.dictionaryObject.clear()
return self.dictionaryObject
if len(arguments) == 1:
del self.dictionaryObject[arguments[0]]
return self.dictionaryObject
for enumeratorKey in euclidean.getEnumeratorKeysAlwaysList(self.dictionaryObject, arguments):
del self.dictionaryObject[enumeratorKey]
return self.dictionaryObject
def getIsIn(self, value):
'Determine if the value is in.'
return value in self.dictionaryObject
def getIsNotIn(self, value):
'Determine if the value is in.'
return not(value in self.dictionaryObject)
def getLength(self):
'Get the length.'
return len(self.dictionaryObject)
def getMax(self):
'Get the max.'
return max(self.dictionaryObject)
def getMin(self):
'Get the min.'
return min(self.dictionaryObject)
def index(self, value):
'Get the index element.'
for key, iteratorValue in self.dictionaryObject.iteritems():
if iteratorValue == value:
return key
raise ValueError('Value (%s) not found in index in DictionaryAttribute for (%s).' % (value, self.dictionaryObject))
def length(self):
'Get the length.'
return len(self.dictionaryObject)
def set(self, itemIndex, value):
'Set value.'
self.dictionaryObject[itemIndex] = value
return self.dictionaryObject
globalAccessibleAttributeDictionary = 'count delete getIsIn getIsNotIn getLength getMax getMin index length set'.split()
globalGetAccessibleAttributeSet = set(globalAccessibleAttributeDictionary)
globalNativeFunctions = 'clear copy fromkeys get items keys pop popitem remove setdefault update values'.split()
globalNativeFunctionSet = set(globalNativeFunctions)

View File

@ -1,121 +0,0 @@
"""
List object attributes.
"""
from __future__ import absolute_import
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def _getAccessibleAttribute(attributeName, listObject):
'Get the accessible attribute.'
if attributeName in globalNativeFunctionSet:
return getattr(listObject, attributeName, None)
if attributeName in globalGetAccessibleAttributeSet:
stringAttribute = ListAttribute(listObject)
return getattr(stringAttribute, attributeName, None)
return None
class ListAttribute(object):
'Class to handle a list.'
def __init__(self, listObject):
'Initialize.'
self.listObject = listObject
def __repr__(self):
"Get the list representation of this ListAttribute."
return str(self.listObject)
def add(self, value):
'Get the concatenation, same as append.'
return self.listObject + [value]
def copy(self):
'Get the copy.'
return self.listObject[:]
def delete(self, arguments):
'Get the delete list.'
deleteList = []
enumeratorSet = set(euclidean.getEnumeratorKeysAlwaysList(self.listObject, arguments))
for elementIndex, element in enumerate(self.listObject):
if elementIndex not in enumeratorSet:
deleteList.append(element)
return deleteList
def get(self, itemIndex):
'Get value by index'
return self.listObject[itemIndex]
def getExpansion(self, items):
'Get the concatenated copies.'
expansion = []
for itemIndex in xrange(items):
expansion += self.listObject[:]
return expansion
def getIsIn(self, value):
'Determine if the value is in.'
return value in self.listObject
def getIsNotIn(self, value):
'Determine if the value is in.'
return not(value in self.listObject)
def getLength(self):
'Get the length.'
return len(self.listObject)
def getMax(self):
'Get the max.'
return max(self.listObject)
def getMin(self):
'Get the min.'
return min(self.listObject)
def insert(self, insertIndex, value):
'Get the insert list.'
if insertIndex < 0:
insertIndex += len(self.listObject)
insertIndex = max(0, insertIndex)
return self.listObject[: insertIndex] + [value] + self.listObject[insertIndex :]
def keys(self):
'Get the keys.'
return range(len(self.listObject))
def length(self):
'Get the length.'
return len(self.listObject)
def rindex(self, value):
'Get the rindex element.'
for elementIndex, element in enumerate(self.listObject):
if element == value:
return elementIndex
raise ValueError('Value (%s) not found in rindex in ListAttribute for (%s).' % (value, self.listObject))
def set(self, itemIndex, value):
'Set value.'
self.listObject[itemIndex] = value
return self.listObject
def values(self, arguments=None):
'Get the values.'
return self.listObject
globalAccessibleAttributeDictionary = 'add copy count delete get getExpansion getIsIn getIsNotIn getLength getMax getMin'.split()
globalAccessibleAttributeDictionary += 'insert keys length rindex set values'.split()
globalGetAccessibleAttributeSet = set(globalAccessibleAttributeDictionary)
globalNativeFunctions = 'append extend index pop remove reverse sort'.split()
globalNativeFunctionSet = set(globalNativeFunctions)

View File

@ -1,134 +0,0 @@
"""
String object attributes.
"""
from __future__ import absolute_import
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def _getAccessibleAttribute(attributeName, stringObject):
'Get the accessible attribute.'
if attributeName in globalNativeFunctionSet:
return getattr(stringObject, attributeName, None)
if attributeName in globalGetAccessibleAttributeSet:
stringAttribute = StringAttribute(stringObject)
return getattr(stringAttribute, attributeName, None)
return None
class StringAttribute(object):
'Class to handle a string.'
def __init__(self, stringObject):
'Initialize.'
self.stringObject = stringObject
def __repr__(self):
"Get the string representation of this StringAttribute."
return self.stringObject
def add(self, nextString):
'Get the add string, same as append.'
return self.stringObject + nextString
def append(self, nextString):
'Get the append string.'
return self.stringObject + nextString
def copy(self):
'Get the copy.'
return self.stringObject[:]
def delete(self, arguments):
'Get the delete string.'
deleteString = ''
enumeratorSet = set(euclidean.getEnumeratorKeysAlwaysList(self.stringObject, arguments))
for characterIndex, character in enumerate(self.stringObject):
if characterIndex not in enumeratorSet:
deleteString += character
return deleteString
def get(self, itemIndex):
'Get value by characterIndex'
return self.stringObject[itemIndex]
def getExpansion(self, items):
'Get the concatenated copies.'
expansion = ''
for itemIndex in xrange(items):
expansion += self.stringObject
return expansion
def getIsIn(self, value):
'Determine if the value is in.'
return value in self.stringObject
def getIsNotIn(self, value):
'Determine if the value is in.'
return not(value in self.stringObject)
def getLength(self):
'Get the length.'
return len(self.stringObject)
def getMax(self):
'Get the max.'
return max(self.stringObject)
def getMin(self):
'Get the min.'
return min(self.stringObject)
def insert(self, insertIndex, value):
'Get the insert string.'
if insertIndex < 0:
insertIndex += len(self.stringObject)
insertIndex = max(0, insertIndex)
return self.stringObject[: insertIndex] + value + self.stringObject[insertIndex :]
def keys(self):
'Get the keys.'
return range(len(self.stringObject))
def length(self):
'Get the length.'
return len(self.stringObject)
def remove(self, value):
'Get the remove string.'
removeIndex = self.stringObject.find(value)
if removeIndex > -1:
return self.stringObject[: removeIndex] + self.stringObject[removeIndex + len(value) :]
return self.stringObject
def reverse(self):
'Get the reverse string.'
return self.stringObject[: : -1]
def set(self, itemIndex, value):
'Set value.'
self.stringObject[itemIndex] = value
return self.stringObject
def values(self):
'Get the values.'
values = []
for character in self.stringObject:
values.append(character)
return values
globalAccessibleAttributeDictionary = 'add append copy delete get getExpansion getIsIn getIsNotIn getLength getMax getMin'.split()
globalAccessibleAttributeDictionary += 'insert keys length remove reverse set values'.split()
globalGetAccessibleAttributeSet = set(globalAccessibleAttributeDictionary)
globalNativeFunctions = 'capitalize center count decode encode endswith expandtabs find format index isalnum join'.split()
globalNativeFunctions += 'isalpha isdigit islower isspace istitle isupper ljust lower lstrip partition replace rfind rindex'.split()
globalNativeFunctions += 'rjust rpartition rsplit rstrip split splitlines startswith strip swapcase title translate upper zfill'.split()
globalNativeFunctionSet = set(globalNativeFunctions)

View File

@ -1,99 +0,0 @@
"""
Boolean geometry utilities.
"""
from __future__ import absolute_import
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalNativeFunctions = 'acos asin atan atan2 ceil cos cosh degrees e exp fabs floor fmod frexp hypot'.split()
globalNativeFunctions += 'ldexp log log10 modf pi pow radians sin sinh sqrt tan tanh trunc'.split()
globalNativeFunctionSet = set(globalNativeFunctions)
#Constants from: http://www.physlink.com/reference/MathConstants.cfm
#Tau is from: http://tauday.com/
#If anyone wants to add stuff, more constants are at: http://en.wikipedia.org/wiki/Mathematical_constant
globalMathConstantDictionary = {
'euler' : 0.5772156649015328606065120,
'golden' : euclidean.globalGoldenRatio,
'goldenAngle' : euclidean.globalGoldenAngle,
'goldenRatio' : euclidean.globalGoldenRatio,
'tau' : euclidean.globalTau}
def _getAccessibleAttribute(attributeName):
'Get the accessible attribute.'
if attributeName in globalMathConstantDictionary:
return globalMathConstantDictionary[attributeName]
if attributeName in globalNativeFunctionSet:
return math.__dict__[attributeName]
if attributeName in globalAccessibleAttributeDictionary:
return globalAccessibleAttributeDictionary[attributeName]
return None
def getAbs(value):
'Get the abs.'
return abs(value)
def getBoolean(value):
'Get the boolean.'
return bool(value)
def getDivmod(x, y):
'Get the divmod.'
return divmod(x, y)
def getFloat(value):
'Get the float.'
return float(value)
def getHex(value):
'Get the hex.'
return hex(value)
def getInt(value):
'Get the int.'
return int(value)
def getLong(value):
'Get the long.'
return long(value)
def getMax(first, second):
'Get the max.'
return max(first, second)
def getMin(first, second):
'Get the min.'
return min(first, second)
def getRound(value):
'Get the round.'
return round(value)
def getString(value):
'Get the string.'
return str(value)
globalAccessibleAttributeDictionary = {
'abs' : getAbs,
'boolean' : getBoolean,
'divmod' : getDivmod,
'float' : getFloat,
'hex' : getHex,
'int' : getInt,
'long' : getLong,
'max' : getMax,
'min' : getMin,
'round' : getRound,
'string' : getString}

View File

@ -1,93 +0,0 @@
"""
Boolean geometry utilities.
"""
from __future__ import absolute_import
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities.vector3index import Vector3Index
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def _getAccessibleAttribute(attributeName):
'Get the accessible attribute.'
if attributeName in globalAccessibleAttributeDictionary:
return globalAccessibleAttributeDictionary[attributeName]
return None
def getComplex(x=0.0, y=0.0):
'Get the complex.'
return complex(x, y)
def getCylindrical(azimuthDegrees, radius=1.0, z=0.0):
'Get the cylindrical vector3 by degrees.'
return getCylindricalByRadians(math.radians(azimuthDegrees), radius, z)
def getCylindricalByRadians(azimuthRadians, radius=1.0, z=0.0):
'Get the cylindrical vector3 by radians.'
polar = radius * euclidean.getWiddershinsUnitPolar(azimuthRadians)
return Vector3(polar.real, polar.imag, z)
def getNestedVectorTestExample(x=0.0, y=0.0, z=0.0):
'Get the NestedVectorTestExample.'
return NestedVectorTestExample(Vector3(x, y, z))
def getPolar(angleDegrees, radius=1.0):
'Get the complex polar by degrees.'
return radius * euclidean.getWiddershinsUnitPolar(math.radians(angleDegrees))
def getPolarByRadians(angleRadians, radius=1.0):
'Get the complex polar by radians.'
return radius * euclidean.getWiddershinsUnitPolar(angleRadians)
def getSpherical(azimuthDegrees, elevationDegrees, radius=1.0):
'Get the spherical vector3 unit by degrees.'
return getSphericalByRadians(math.radians(azimuthDegrees), math.radians(elevationDegrees), radius)
def getSphericalByRadians(azimuthRadians, elevationRadians, radius=1.0):
'Get the spherical vector3 unit by radians.'
elevationComplex = euclidean.getWiddershinsUnitPolar(elevationRadians)
azimuthComplex = euclidean.getWiddershinsUnitPolar(azimuthRadians) * elevationComplex.real
return Vector3(azimuthComplex.real, azimuthComplex.imag, elevationComplex.imag) * radius
def getVector3(x=0.0, y=0.0, z=0.0):
'Get the vector3.'
return Vector3(x, y, z)
def getVector3Index(index=0, x=0.0, y=0.0, z=0.0):
'Get the vector3.'
return Vector3Index(index, x, y, z)
class NestedVectorTestExample(object):
'Class to test local attribute.'
def __init__(self, vector3):
'Get the accessible attribute.'
self.vector3 = vector3
def _getAccessibleAttribute(self, attributeName):
"Get the accessible attribute."
if attributeName == 'vector3':
return getattr(self, attributeName, None)
return None
globalAccessibleAttributeDictionary = {
'complex' : getComplex,
'getCylindrical' : getCylindrical,
'getCylindricalByRadians' : getCylindricalByRadians,
'getPolar' : getPolar,
'getPolarByRadians' : getPolarByRadians,
'getSpherical' : getSpherical,
'getSphericalByRadians' : getSphericalByRadians,
'NestedVectorTestExample' : getNestedVectorTestExample,
'Vector3' : getVector3,
'Vector3Index' : getVector3Index}

View File

@ -1,59 +0,0 @@
"""
Boolean geometry utilities.
"""
from __future__ import absolute_import
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def _getAccessibleAttribute(attributeName):
'Get the accessible attribute.'
if attributeName in globalAccessibleAttributeDictionary:
return globalAccessibleAttributeDictionary[attributeName]
return None
def getBoundingBoxByPaths(elementNode):
'Get bounding box of the transformed paths of the xmlObject of the elementNode.'
transformedPaths = elementNode.xmlObject.getTransformedPaths()
maximum = euclidean.getMaximumByVector3Paths(transformedPaths)
minimum = euclidean.getMinimumByVector3Paths(transformedPaths)
return [minimum, maximum]
def getCenterByPaths(elementNode):
'Get center of the transformed paths of the xmlObject of the elementNode.'
transformedPaths = elementNode.xmlObject.getTransformedPaths()
return 0.5 * (euclidean.getMaximumByVector3Paths(transformedPaths) + euclidean.getMinimumByVector3Paths(transformedPaths))
def getExtentByPaths(elementNode):
'Get extent of the transformed paths of the xmlObject of the elementNode.'
transformedPaths = elementNode.xmlObject.getTransformedPaths()
return euclidean.getMaximumByVector3Paths(transformedPaths) - euclidean.getMinimumByVector3Paths(transformedPaths)
def getInradiusByPaths(elementNode):
'Get inradius of the transformed paths of the xmlObject of the elementNode.'
return 0.5 * getExtentByPaths(elementNode)
def getMinimumByPaths(elementNode):
'Get minimum of the transformed paths of the xmlObject of the elementNode.'
return euclidean.getMinimumByVector3Paths(elementNode.xmlObject.getTransformedPaths())
def getMaximumByPaths(elementNode):
'Get maximum of the transformed paths of the xmlObject of the elementNode.'
return euclidean.getMaximumByVector3Paths(elementNode.xmlObject.getTransformedPaths())
globalAccessibleAttributeDictionary = {
'getBoundingBoxByPaths' : getBoundingBoxByPaths,
'getCenterByPaths' : getCenterByPaths,
'getExtentByPaths' : getExtentByPaths,
'getInradiusByPaths' : getInradiusByPaths,
'getMaximumByPaths' : getMaximumByPaths,
'getMinimumByPaths' : getMinimumByPaths}

View File

@ -1,34 +0,0 @@
"""
Boolean geometry utilities.
"""
from __future__ import absolute_import
import sys
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def _getAccessibleAttribute(attributeName):
'Get the accessible attribute.'
if attributeName in globalAccessibleAttributeDictionary:
return globalAccessibleAttributeDictionary[attributeName]
return None
def continuous(valueString):
'Print continuous.'
sys.stdout.write(str(valueString))
return valueString
def line(valueString):
'Print line.'
print(valueString)
return valueString
globalAccessibleAttributeDictionary = {'continuous' : continuous, 'line' : line}

View File

@ -1,22 +0,0 @@
"A"
0 0
2 8
4 0
1 4
3 4
"B"
0 4
2 4
4 5
4 7
3 8
0 8
0 0
3 0
4 1
4 3
2 4
"C"
1 A
2 0 0
3 2 8
4 4 0
5
6 1 4
7 3 4
8
9 B
10 0 4
11 2 4
12 4 5
13 4 7
14 3 8
15 0 8
16 0 0
17 3 0
18 4 1
19 4 3
20 2 4
21
22 C

View File

@ -1,492 +0,0 @@
"""
Boolean geometry four by four matrix.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import xml_simple_writer
import cStringIO
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 300
def addVertexes(geometryOutput, vertexes):
'Add the vertexes.'
if geometryOutput.__class__ == list:
for element in geometryOutput:
addVertexes(element, vertexes)
return
if geometryOutput.__class__ == dict:
for geometryOutputKey in geometryOutput.keys():
if geometryOutputKey == 'vertex':
vertexes += geometryOutput[geometryOutputKey]
else:
addVertexes(geometryOutput[geometryOutputKey], vertexes)
def getBranchMatrix(elementNode):
'Get matrix starting from the object if it exists, otherwise get a matrix starting from stratch.'
branchMatrix = Matrix()
matrixChildElement = elementNode.getFirstChildByLocalName('matrix')
if matrixChildElement != None:
branchMatrix = branchMatrix.getFromElementNode(matrixChildElement, '')
branchMatrix = branchMatrix.getFromElementNode(elementNode, 'matrix.')
if elementNode.xmlObject == None:
return branchMatrix
elementNodeMatrix = elementNode.xmlObject.getMatrix4X4()
if elementNodeMatrix == None:
return branchMatrix
return elementNodeMatrix.getOtherTimesSelf(branchMatrix.tetragrid)
def getBranchMatrixSetElementNode(elementNode):
'Get matrix starting from the object if it exists, otherwise get a matrix starting from stratch.'
branchMatrix = getBranchMatrix(elementNode)
setElementNodeDictionaryMatrix(elementNode, branchMatrix)
return branchMatrix
def getCumulativeVector3Remove(defaultVector3, elementNode, prefix):
'Get cumulative vector3 and delete the prefixed attributes.'
if prefix == '':
defaultVector3.x = evaluate.getEvaluatedFloat(defaultVector3.x, elementNode, 'x')
defaultVector3.y = evaluate.getEvaluatedFloat(defaultVector3.y, elementNode, 'y')
defaultVector3.z = evaluate.getEvaluatedFloat(defaultVector3.z, elementNode, 'z')
euclidean.removeElementsFromDictionary(elementNode.attributes, ['x', 'y', 'z'])
prefix = 'cartesian'
defaultVector3 = evaluate.getVector3ByPrefix(defaultVector3, elementNode, prefix)
euclidean.removePrefixFromDictionary(elementNode.attributes, prefix)
return defaultVector3
def getDiagonalSwitchedTetragrid(angleDegrees, diagonals):
'Get the diagonals and switched matrix by degrees.'
return getDiagonalSwitchedTetragridByRadians(math.radians(angleDegrees), diagonals)
def getDiagonalSwitchedTetragridByPolar(diagonals, unitPolar):
'Get the diagonals and switched matrix by unitPolar.'
diagonalSwitchedTetragrid = getIdentityTetragrid()
for diagonal in diagonals:
diagonalSwitchedTetragrid[diagonal][diagonal] = unitPolar.real
diagonalSwitchedTetragrid[diagonals[0]][diagonals[1]] = -unitPolar.imag
diagonalSwitchedTetragrid[diagonals[1]][diagonals[0]] = unitPolar.imag
return diagonalSwitchedTetragrid
def getDiagonalSwitchedTetragridByRadians(angleRadians, diagonals):
'Get the diagonals and switched matrix by radians.'
return getDiagonalSwitchedTetragridByPolar(diagonals, euclidean.getWiddershinsUnitPolar(angleRadians))
def getIdentityTetragrid(tetragrid=None):
'Get four by four matrix with diagonal elements set to one.'
if tetragrid == None:
return [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]
return tetragrid
def getIsIdentityTetragrid(tetragrid):
'Determine if the tetragrid is the identity tetragrid.'
for column in xrange(4):
for row in xrange(4):
if column == row:
if tetragrid[column][row] != 1.0:
return False
elif tetragrid[column][row] != 0.0:
return False
return True
def getIsIdentityTetragridOrNone(tetragrid):
'Determine if the tetragrid is None or if it is the identity tetragrid.'
if tetragrid == None:
return True
return getIsIdentityTetragrid(tetragrid)
def getKeyA(row, column, prefix=''):
'Get the a format key string from row & column, counting from zero.'
return '%sa%s%s' % (prefix, row, column)
def getKeyM(row, column, prefix=''):
'Get the m format key string from row & column, counting from one.'
return '%sm%s%s' % (prefix, row + 1, column + 1)
def getKeysA(prefix=''):
'Get the matrix keys, counting from zero.'
keysA = []
for row in xrange(4):
for column in xrange(4):
key = getKeyA(row, column, prefix)
keysA.append(key)
return keysA
def getKeysM(prefix=''):
'Get the matrix keys, counting from one.'
keysM = []
for row in xrange(4):
for column in xrange(4):
key = getKeyM(row, column, prefix)
keysM.append(key)
return keysM
def getRemovedFloat(defaultFloat, elementNode, key, prefix):
'Get the float by the key and the prefix.'
prefixKey = prefix + key
if prefixKey in elementNode.attributes:
floatValue = evaluate.getEvaluatedFloat(None, elementNode, prefixKey)
if floatValue == None:
print('Warning, evaluated value in getRemovedFloatByKeys in matrix is None for key:')
print(prefixKey)
print('for elementNode dictionary value:')
print(elementNode.attributes[prefixKey])
print('for elementNode dictionary:')
print(elementNode.attributes)
else:
defaultFloat = floatValue
del elementNode.attributes[prefixKey]
return defaultFloat
def getRemovedFloatByKeys(defaultFloat, elementNode, keys, prefix):
'Get the float by the keys and the prefix.'
for key in keys:
defaultFloat = getRemovedFloat(defaultFloat, elementNode, key, prefix)
return defaultFloat
def getRotateAroundAxisTetragrid(elementNode, prefix):
'Get rotate around axis tetragrid and delete the axis and angle attributes.'
angle = getRemovedFloatByKeys(0.0, elementNode, ['angle', 'counterclockwise'], prefix)
angle -= getRemovedFloat(0.0, elementNode, 'clockwise', prefix)
if angle == 0.0:
return None
angleRadians = math.radians(angle)
axis = getCumulativeVector3Remove(Vector3(), elementNode, prefix + 'axis')
axisLength = abs(axis)
if axisLength <= 0.0:
print('Warning, axisLength was zero in getRotateAroundAxisTetragrid in matrix so nothing will be done for:')
print(elementNode)
return None
axis /= axisLength
tetragrid = getIdentityTetragrid()
cosAngle = math.cos(angleRadians)
sinAngle = math.sin(angleRadians)
oneMinusCos = 1.0 - math.cos(angleRadians)
xx = axis.x * axis.x
xy = axis.x * axis.y
xz = axis.x * axis.z
yy = axis.y * axis.y
yz = axis.y * axis.z
zz = axis.z * axis.z
tetragrid[0] = [cosAngle + xx * oneMinusCos, xy * oneMinusCos - axis.z * sinAngle, xz * oneMinusCos + axis.y * sinAngle, 0.0]
tetragrid[1] = [xy * oneMinusCos + axis.z * sinAngle, cosAngle + yy * oneMinusCos, yz * oneMinusCos - axis.x * sinAngle, 0.0]
tetragrid[2] = [xz * oneMinusCos - axis.y * sinAngle, yz * oneMinusCos + axis.x * sinAngle, cosAngle + zz * oneMinusCos, 0.0]
return tetragrid
def getRotateTetragrid(elementNode, prefix):
'Get rotate tetragrid and delete the rotate attributes.'
# http://en.wikipedia.org/wiki/Rotation_matrix
rotateMatrix = Matrix()
rotateMatrix.tetragrid = getRotateAroundAxisTetragrid(elementNode, prefix)
zAngle = getRemovedFloatByKeys(0.0, elementNode, ['axisclockwisez', 'observerclockwisez', 'z'], prefix)
zAngle -= getRemovedFloatByKeys(0.0, elementNode, ['axiscounterclockwisez', 'observercounterclockwisez'], prefix)
if zAngle != 0.0:
rotateMatrix.tetragrid = getTetragridTimesOther(getDiagonalSwitchedTetragrid(-zAngle, [0, 1]), rotateMatrix.tetragrid)
xAngle = getRemovedFloatByKeys(0.0, elementNode, ['axisclockwisex', 'observerclockwisex', 'x'], prefix)
xAngle -= getRemovedFloatByKeys(0.0, elementNode, ['axiscounterclockwisex', 'observercounterclockwisex'], prefix)
if xAngle != 0.0:
rotateMatrix.tetragrid = getTetragridTimesOther(getDiagonalSwitchedTetragrid(-xAngle, [1, 2]), rotateMatrix.tetragrid)
yAngle = getRemovedFloatByKeys(0.0, elementNode, ['axiscounterclockwisey', 'observerclockwisey', 'y'], prefix)
yAngle -= getRemovedFloatByKeys(0.0, elementNode, ['axisclockwisey', 'observercounterclockwisey'], prefix)
if yAngle != 0.0:
rotateMatrix.tetragrid = getTetragridTimesOther(getDiagonalSwitchedTetragrid(yAngle, [0, 2]), rotateMatrix.tetragrid)
return rotateMatrix.tetragrid
def getScaleTetragrid(elementNode, prefix):
'Get scale matrix and delete the scale attributes.'
scaleDefaultVector3 = Vector3(1.0, 1.0, 1.0)
scale = getCumulativeVector3Remove(scaleDefaultVector3.copy(), elementNode, prefix)
if scale == scaleDefaultVector3:
return None
return [[scale.x, 0.0, 0.0, 0.0], [0.0, scale.y, 0.0, 0.0], [0.0, 0.0, scale.z, 0.0], [0.0, 0.0, 0.0, 1.0]]
def getTetragridA(elementNode, prefix, tetragrid):
'Get the tetragrid from the elementNode letter a values.'
keysA = getKeysA(prefix)
evaluatedDictionary = evaluate.getEvaluatedDictionaryByEvaluationKeys(elementNode, keysA)
if len(evaluatedDictionary.keys()) < 1:
return tetragrid
for row in xrange(4):
for column in xrange(4):
key = getKeyA(row, column, prefix)
if key in evaluatedDictionary:
value = evaluatedDictionary[key]
if value == None or value == 'None':
print('Warning, value in getTetragridA in matrix is None for key for dictionary:')
print(key)
print(evaluatedDictionary)
else:
tetragrid = getIdentityTetragrid(tetragrid)
tetragrid[row][column] = float(value)
euclidean.removeElementsFromDictionary(elementNode.attributes, keysA)
return tetragrid
def getTetragridC(elementNode, prefix, tetragrid):
'Get the matrix Tetragrid from the elementNode letter c values.'
columnKeys = 'Pc1 Pc2 Pc3 Pc4'.replace('P', prefix).split()
evaluatedDictionary = evaluate.getEvaluatedDictionaryByEvaluationKeys(elementNode, columnKeys)
if len(evaluatedDictionary.keys()) < 1:
return tetragrid
for columnKeyIndex, columnKey in enumerate(columnKeys):
if columnKey in evaluatedDictionary:
value = evaluatedDictionary[columnKey]
if value == None or value == 'None':
print('Warning, value in getTetragridC in matrix is None for columnKey for dictionary:')
print(columnKey)
print(evaluatedDictionary)
else:
tetragrid = getIdentityTetragrid(tetragrid)
for elementIndex, element in enumerate(value):
tetragrid[elementIndex][columnKeyIndex] = element
euclidean.removeElementsFromDictionary(elementNode.attributes, columnKeys)
return tetragrid
def getTetragridCopy(tetragrid):
'Get tetragrid copy.'
if tetragrid == None:
return None
tetragridCopy = []
for tetragridRow in tetragrid:
tetragridCopy.append(tetragridRow[:])
return tetragridCopy
def getTetragridM(elementNode, prefix, tetragrid):
'Get the tetragrid from the elementNode letter m values.'
keysM = getKeysM(prefix)
evaluatedDictionary = evaluate.getEvaluatedDictionaryByEvaluationKeys(elementNode, keysM)
if len(evaluatedDictionary.keys()) < 1:
return tetragrid
for row in xrange(4):
for column in xrange(4):
key = getKeyM(row, column, prefix)
if key in evaluatedDictionary:
value = evaluatedDictionary[key]
if value == None or value == 'None':
print('Warning, value in getTetragridM in matrix is None for key for dictionary:')
print(key)
print(evaluatedDictionary)
else:
tetragrid = getIdentityTetragrid(tetragrid)
tetragrid[row][column] = float(value)
euclidean.removeElementsFromDictionary(elementNode.attributes, keysM)
return tetragrid
def getTetragridMatrix(elementNode, prefix, tetragrid):
'Get the tetragrid from the elementNode matrix value.'
matrixKey = prefix + 'matrix'
evaluatedDictionary = evaluate.getEvaluatedDictionaryByEvaluationKeys(elementNode, [matrixKey])
if len(evaluatedDictionary.keys()) < 1:
return tetragrid
value = evaluatedDictionary[matrixKey]
if value == None or value == 'None':
print('Warning, value in getTetragridMatrix in matrix is None for matrixKey for dictionary:')
print(matrixKey)
print(evaluatedDictionary)
else:
tetragrid = getIdentityTetragrid(tetragrid)
for rowIndex, row in enumerate(value):
for elementIndex, element in enumerate(row):
tetragrid[rowIndex][elementIndex] = element
euclidean.removeElementsFromDictionary(elementNode.attributes, [matrixKey])
return tetragrid
def getTetragridR(elementNode, prefix, tetragrid):
'Get the tetragrid from the elementNode letter r values.'
rowKeys = 'Pr1 Pr2 Pr3 Pr4'.replace('P', prefix).split()
evaluatedDictionary = evaluate.getEvaluatedDictionaryByEvaluationKeys(elementNode, rowKeys)
if len(evaluatedDictionary.keys()) < 1:
return tetragrid
for rowKeyIndex, rowKey in enumerate(rowKeys):
if rowKey in evaluatedDictionary:
value = evaluatedDictionary[rowKey]
if value == None or value == 'None':
print('Warning, value in getTetragridR in matrix is None for rowKey for dictionary:')
print(rowKey)
print(evaluatedDictionary)
else:
tetragrid = getIdentityTetragrid(tetragrid)
for elementIndex, element in enumerate(value):
tetragrid[rowKeyIndex][elementIndex] = element
euclidean.removeElementsFromDictionary(elementNode.attributes, rowKeys)
return tetragrid
def getTetragridTimesOther(firstTetragrid, otherTetragrid ):
'Get this matrix multiplied by the other matrix.'
#A down, B right from http://en.wikipedia.org/wiki/Matrix_multiplication
if firstTetragrid == None:
return otherTetragrid
if otherTetragrid == None:
return firstTetragrid
tetragridTimesOther = []
for row in xrange(4):
matrixRow = firstTetragrid[row]
tetragridTimesOtherRow = []
tetragridTimesOther.append(tetragridTimesOtherRow)
for column in xrange(4):
dotProduct = 0
for elementIndex in xrange(4):
dotProduct += matrixRow[elementIndex] * otherTetragrid[elementIndex][column]
tetragridTimesOtherRow.append(dotProduct)
return tetragridTimesOther
def getTransformedByList(floatList, point):
'Get the point transformed by the array.'
return floatList[0] * point.x + floatList[1] * point.y + floatList[2] * point.z + floatList[3]
def getTransformedVector3(tetragrid, vector3):
'Get the vector3 multiplied by a matrix.'
if getIsIdentityTetragridOrNone(tetragrid):
return vector3.copy()
return getTransformedVector3Blindly(tetragrid, vector3)
def getTransformedVector3Blindly(tetragrid, vector3):
'Get the vector3 multiplied by a tetragrid without checking if the tetragrid exists.'
return Vector3(
getTransformedByList(tetragrid[0], vector3),
getTransformedByList(tetragrid[1], vector3),
getTransformedByList(tetragrid[2], vector3))
def getTransformedVector3s(tetragrid, vector3s):
'Get the vector3s multiplied by a matrix.'
if getIsIdentityTetragridOrNone(tetragrid):
return euclidean.getPathCopy(vector3s)
transformedVector3s = []
for vector3 in vector3s:
transformedVector3s.append(getTransformedVector3Blindly(tetragrid, vector3))
return transformedVector3s
def getTransformTetragrid(elementNode, prefix):
'Get the tetragrid from the elementNode.'
tetragrid = getTetragridA(elementNode, prefix, None)
tetragrid = getTetragridC(elementNode, prefix, tetragrid)
tetragrid = getTetragridM(elementNode, prefix, tetragrid)
tetragrid = getTetragridMatrix(elementNode, prefix, tetragrid)
tetragrid = getTetragridR(elementNode, prefix, tetragrid)
return tetragrid
def getTranslateTetragrid(elementNode, prefix):
'Get translate matrix and delete the translate attributes.'
translation = getCumulativeVector3Remove(Vector3(), elementNode, prefix)
if translation.getIsDefault():
return None
return getTranslateTetragridByTranslation(translation)
def getTranslateTetragridByTranslation(translation):
'Get translate tetragrid by translation.'
return [[1.0, 0.0, 0.0, translation.x], [0.0, 1.0, 0.0, translation.y], [0.0, 0.0, 1.0, translation.z], [0.0, 0.0, 0.0, 1.0]]
def getVertexes(geometryOutput):
'Get the vertexes.'
vertexes = []
addVertexes(geometryOutput, vertexes)
return vertexes
def setAttributesToMultipliedTetragrid(elementNode, tetragrid):
'Set the element attribute dictionary and element matrix to the matrix times the tetragrid.'
setElementNodeDictionaryMatrix(elementNode, getBranchMatrix(elementNode).getOtherTimesSelf(tetragrid))
def setElementNodeDictionaryMatrix(elementNode, matrix4X4):
'Set the element attribute dictionary or element matrix to the matrix.'
if elementNode.xmlObject == None:
elementNode.attributes.update(matrix4X4.getAttributes('matrix.'))
else:
elementNode.xmlObject.matrix4X4 = matrix4X4
def transformVector3Blindly(tetragrid, vector3):
'Transform the vector3 by a tetragrid without checking to see if it exists.'
x = getTransformedByList(tetragrid[0], vector3)
y = getTransformedByList(tetragrid[1], vector3)
z = getTransformedByList(tetragrid[2], vector3)
vector3.x = x
vector3.y = y
vector3.z = z
def transformVector3ByMatrix(tetragrid, vector3):
'Transform the vector3 by a matrix.'
if getIsIdentityTetragridOrNone(tetragrid):
return
transformVector3Blindly(tetragrid, vector3)
def transformVector3sByMatrix(tetragrid, vector3s):
'Transform the vector3s by a matrix.'
if getIsIdentityTetragridOrNone(tetragrid):
return
for vector3 in vector3s:
transformVector3Blindly(tetragrid, vector3)
class Matrix(object):
'A four by four matrix.'
def __init__(self, tetragrid=None):
'Add empty lists.'
self.tetragrid = getTetragridCopy(tetragrid)
def __eq__(self, other):
'Determine whether this matrix is identical to other one.'
if other == None:
return False
if other.__class__ != self.__class__:
return False
return other.tetragrid == self.tetragrid
def __ne__(self, other):
'Determine whether this vector is not identical to other one.'
return not self.__eq__(other)
def __repr__(self):
'Get the string representation of this four by four matrix.'
output = cStringIO.StringIO()
self.addXML(0, output)
return output.getvalue()
def addXML(self, depth, output):
'Add xml for this object.'
attributes = self.getAttributes()
if len(attributes) > 0:
xml_simple_writer.addClosedXMLTag(attributes, depth, self.__class__.__name__.lower(), output)
def getAttributes(self, prefix=''):
'Get the attributes from row column attribute strings, counting from one.'
attributes = {}
if self.tetragrid == None:
return attributes
for row in xrange(4):
for column in xrange(4):
default = float(column == row)
value = self.tetragrid[row][column]
if abs( value - default ) > 0.00000000000001:
if abs(value) < 0.00000000000001:
value = 0.0
attributes[prefix + getKeyM(row, column)] = value
return attributes
def getFromElementNode(self, elementNode, prefix):
'Get the values from row column attribute strings, counting from one.'
attributes = elementNode.attributes
if attributes == None:
return self
self.tetragrid = getTetragridTimesOther(getTransformTetragrid(elementNode, prefix), self.tetragrid)
self.tetragrid = getTetragridTimesOther(getScaleTetragrid(elementNode, 'scale.'), self.tetragrid)
self.tetragrid = getTetragridTimesOther(getRotateTetragrid(elementNode, 'rotate.'), self.tetragrid)
self.tetragrid = getTetragridTimesOther(getTranslateTetragrid(elementNode, 'translate.'), self.tetragrid)
return self
def getOtherTimesSelf(self, otherTetragrid):
'Get this matrix reverse multiplied by the other matrix.'
return Matrix(getTetragridTimesOther(otherTetragrid, self.tetragrid))
def getSelfTimesOther(self, otherTetragrid):
'Get this matrix multiplied by the other matrix.'
return Matrix(getTetragridTimesOther(self.tetragrid, otherTetragrid))

View File

@ -1,65 +0,0 @@
"""
Boolean geometry scale.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities.vector3 import Vector3
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 340
def getManipulatedGeometryOutput(elementNode, geometryOutput, prefix):
"Get equated geometryOutput."
scalePoints( elementNode, matrix.getVertexes(geometryOutput), prefix )
return geometryOutput
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get equated paths."
scalePoints( elementNode, loop, prefix )
return [loop]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return ScaleDerivation(elementNode)
def manipulateElementNode(elementNode, target):
"Manipulate the xml element."
derivation = ScaleDerivation(elementNode)
if derivation.scaleTetragrid == None:
print('Warning, scaleTetragrid was None in scale so nothing will be done for:')
print(elementNode)
return
matrix.setAttributesToMultipliedTetragrid(target, derivation.scaleTetragrid)
def processElementNode(elementNode):
"Process the xml element."
solid.processElementNodeByFunction(elementNode, manipulateElementNode)
def scalePoints(elementNode, points, prefix):
"Scale the points."
scaleVector3Default = Vector3(1.0, 1.0, 1.0)
scaleVector3 = matrix.getCumulativeVector3Remove(scaleVector3Default.copy(), elementNode, prefix)
if scaleVector3 == scaleVector3Default:
return
for point in points:
point.x *= scaleVector3.x
point.y *= scaleVector3.y
point.z *= scaleVector3.z
class ScaleDerivation(object):
"Class to hold scale variables."
def __init__(self, elementNode):
'Set defaults.'
self.scaleTetragrid = matrix.getScaleTetragrid(elementNode, '')

View File

@ -1,62 +0,0 @@
"""
Boolean geometry rotate.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import matrix
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 360
def getManipulatedGeometryOutput(elementNode, geometryOutput, prefix):
'Get equated geometryOutput.'
rotatePoints(elementNode, matrix.getVertexes(geometryOutput), prefix)
return geometryOutput
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
'Get equated paths.'
rotatePoints(elementNode, loop, prefix)
return [loop]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return RotateDerivation(elementNode, prefix)
def manipulateElementNode(elementNode, target):
'Manipulate the xml element.'
derivation = RotateDerivation(elementNode, '')
if derivation.rotateTetragrid == None:
print('Warning, rotateTetragrid was None in rotate so nothing will be done for:')
print(elementNode)
return
matrix.setAttributesToMultipliedTetragrid(target, derivation.rotateTetragrid)
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByFunction(elementNode, manipulateElementNode)
def rotatePoints(elementNode, points, prefix):
'Rotate the points.'
derivation = RotateDerivation(elementNode, prefix)
if derivation.rotateTetragrid == None:
print('Warning, rotateTetragrid was None in rotate so nothing will be done for:')
print(elementNode)
return
matrix.transformVector3sByMatrix(derivation.rotateTetragrid, points)
class RotateDerivation(object):
"Class to hold rotate variables."
def __init__(self, elementNode, prefix):
'Set defaults.'
self.rotateTetragrid = matrix.getRotateTetragrid(elementNode, prefix)

View File

@ -1,62 +0,0 @@
"""
Boolean geometry transform.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import matrix
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 320
def getManipulatedGeometryOutput(elementNode, geometryOutput, prefix):
'Get equated geometryOutput.'
transformPoints(elementNode, matrix.getVertexes(geometryOutput), prefix)
return geometryOutput
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
'Get equated paths.'
transformPoints(elementNode, loop, prefix)
return [loop]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return TransformDerivation(elementNode, prefix)
def manipulateElementNode(elementNode, target):
'Manipulate the xml element.'
derivation = TransformDerivation(elementNode, '')
if derivation.transformTetragrid == None:
print('Warning, transformTetragrid was None in transform so nothing will be done for:')
print(elementNode)
return
matrix.setAttributesToMultipliedTetragrid(target, derivation.transformTetragrid)
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByFunction(elementNode, manipulateElementNode)
def transformPoints(elementNode, points, prefix):
'Transform the points.'
derivation = TransformDerivation(elementNode, prefix)
if derivation.transformTetragrid == None:
print('Warning, transformTetragrid was None in transform so nothing will be done for:')
print(elementNode)
return
matrix.transformVector3sByMatrix(derivation.transformTetragrid, points)
class TransformDerivation(object):
"Class to hold transform variables."
def __init__(self, elementNode, prefix):
'Set defaults.'
self.transformTetragrid = matrix.getTransformTetragrid(elementNode, prefix)

View File

@ -1,66 +0,0 @@
"""
Boolean geometry translation.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 380
def getManipulatedGeometryOutput(elementNode, geometryOutput, prefix):
"Get equated geometryOutput."
translatePoints(elementNode, matrix.getVertexes(geometryOutput), prefix)
return geometryOutput
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get equated paths."
translatePoints(elementNode, loop, prefix)
return [loop]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return TranslateDerivation(elementNode)
def manipulateElementNode(elementNode, target):
"Manipulate the xml element."
derivation = TranslateDerivation(elementNode)
if derivation.translateTetragrid == None:
print('Warning, translateTetragrid was None in translate so nothing will be done for:')
print(elementNode)
return
matrix.setAttributesToMultipliedTetragrid(target, derivation.translateTetragrid)
def processElementNode(elementNode):
"Process the xml element."
solid.processElementNodeByFunction(elementNode, manipulateElementNode)
def translateNegativesPositives(negatives, positives, translation):
'Translate the negatives and postives.'
euclidean.translateVector3Path(matrix.getVertexes(negatives), translation)
euclidean.translateVector3Path(matrix.getVertexes(positives), translation)
def translatePoints(elementNode, points, prefix):
"Translate the points."
translateVector3 = matrix.getCumulativeVector3Remove(Vector3(), elementNode, prefix)
if abs(translateVector3) > 0.0:
euclidean.translateVector3Path(points, translateVector3)
class TranslateDerivation(object):
"Class to hold translate variables."
def __init__(self, elementNode):
'Set defaults.'
self.translateTetragrid = matrix.getTranslateTetragrid(elementNode, '')

View File

@ -1,126 +0,0 @@
"""
Boolean geometry array.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addPathToGroup(derivation, groupDictionaryCopy, path, targetMatrix, totalIndex):
'Add path to the array group.'
for pointIndex, point in enumerate(path):
arrayElement = derivation.target.getCopy(derivation.elementNode.getIDSuffix(totalIndex), derivation.elementNode)
arrayDictionary = arrayElement.attributes
arrayDictionary['visible'] = str(derivation.visible).lower()
arrayDictionary.update(groupDictionaryCopy)
euclidean.removeTrueFromDictionary(arrayDictionary, 'visible')
vertexMatrix = matrix.Matrix(matrix.getTranslateTetragridByTranslation(point))
zAngle = totalIndex * 50.0
rotationMatrix = getRotationMatrix(arrayDictionary, derivation, path, point, pointIndex)
arrayElementMatrix = vertexMatrix.getSelfTimesOther(rotationMatrix.getSelfTimesOther(targetMatrix.tetragrid).tetragrid)
arrayDictionary.update(arrayElementMatrix.getAttributes('matrix.'))
arrayDictionary['_arrayIndex'] = totalIndex
arrayDictionary['_arrayPoint'] = point
totalIndex += 1
def getNewDerivation(elementNode):
'Get new derivation.'
return ArrayDerivation(elementNode)
def getRotationMatrix(arrayDictionary, derivation, path, point, pointIndex):
'Get rotationMatrix.'
if len(path) < 2 or not derivation.track:
return matrix.Matrix()
point = point.dropAxis()
begin = path[(pointIndex + len(path) - 1) % len(path)].dropAxis()
end = path[(pointIndex + 1) % len(path)].dropAxis()
pointMinusBegin = point - begin
pointMinusBeginLength = abs(pointMinusBegin)
endMinusPoint = end - point
endMinusPointLength = abs(endMinusPoint)
if not derivation.closed:
if pointIndex == 0 and endMinusPointLength > 0.0:
return getRotationMatrixByPolar(arrayDictionary, endMinusPoint, endMinusPointLength)
elif pointIndex == len(path) - 1 and pointMinusBeginLength > 0.0:
return getRotationMatrixByPolar(arrayDictionary, pointMinusBegin, pointMinusBeginLength)
if pointMinusBeginLength <= 0.0:
print('Warning, point equals previous point in getRotationMatrix in array for:')
print(path)
print(pointIndex)
print(derivation.elementNode)
return matrix.Matrix()
pointMinusBegin /= pointMinusBeginLength
if endMinusPointLength <= 0.0:
print('Warning, point equals next point in getRotationMatrix in array for:')
print(path)
print(pointIndex)
print(derivation.elementNode)
return matrix.Matrix()
endMinusPoint /= endMinusPointLength
averagePolar = pointMinusBegin + endMinusPoint
averagePolarLength = abs(averagePolar)
if averagePolarLength <= 0.0:
print('Warning, averagePolarLength is zero in getRotationMatrix in array for:')
print(path)
print(pointIndex)
print(derivation.elementNode)
return matrix.Matrix()
return getRotationMatrixByPolar(arrayDictionary, averagePolar, averagePolarLength)
def getRotationMatrixByPolar(arrayDictionary, polar, polarLength):
'Get rotationMatrix by polar and polarLength.'
polar /= polarLength
arrayDictionary['_arrayRotation'] = math.degrees(math.atan2(polar.imag, polar.real))
return matrix.Matrix(matrix.getDiagonalSwitchedTetragridByPolar([0, 1], polar))
def processElementNode(elementNode):
"Process the xml element."
processElementNodeByDerivation(None, elementNode)
def processElementNodeByDerivation(derivation, elementNode):
'Process the xml element by derivation.'
if derivation == None:
derivation = ArrayDerivation(elementNode)
if derivation.target == None:
print('Warning, array could not get target for:')
print(elementNode)
return
if len(derivation.paths) < 1:
print('Warning, array could not get paths for:')
print(elementNode)
return
groupDictionaryCopy = elementNode.attributes.copy()
euclidean.removeElementsFromDictionary(groupDictionaryCopy, ['closed', 'paths', 'target', 'track', 'vertexes'])
evaluate.removeIdentifiersFromDictionary(groupDictionaryCopy)
targetMatrix = matrix.getBranchMatrixSetElementNode(derivation.target)
elementNode.localName = 'group'
totalIndex = 0
for path in derivation.paths:
addPathToGroup(derivation, groupDictionaryCopy, path, targetMatrix, totalIndex)
elementNode.getXMLProcessor().processElementNode(elementNode)
class ArrayDerivation(object):
"Class to hold array variables."
def __init__(self, elementNode):
'Set defaults.'
self.closed = evaluate.getEvaluatedBoolean(True, elementNode, 'closed')
self.elementNode = elementNode
self.paths = evaluate.getTransformedPathsByKey([], elementNode, 'paths')
vertexTargets = evaluate.getElementNodesByKey(elementNode, 'vertexes')
for vertexTarget in vertexTargets:
self.paths.append(vertexTarget.getVertexes())
self.target = evaluate.getElementNodeByKey(elementNode, 'target')
self.track = evaluate.getEvaluatedBoolean(True, elementNode, 'track')
self.visible = evaluate.getEvaluatedBoolean(True, elementNode, 'visible')

View File

@ -1,93 +0,0 @@
"""
Boolean geometry carve.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import boolean_geometry
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import xml_simple_reader
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getLinkedElementNode(idSuffix, parentNode, target):
'Get elementNode with identifiers and parentNode.'
linkedElementNode = xml_simple_reader.ElementNode()
euclidean.overwriteDictionary(target.attributes, ['id', 'name', 'quantity'], linkedElementNode.attributes)
linkedElementNode.addSuffixToID(idSuffix)
tagKeys = target.getTagKeys()
tagKeys.append('carve')
tagKeys.sort()
tags = ', '.join(tagKeys)
linkedElementNode.attributes['tags'] = tags
linkedElementNode.setParentAddToChildNodes(parentNode)
linkedElementNode.addToIdentifierDictionaries()
return linkedElementNode
def getNewDerivation(elementNode):
'Get new derivation.'
return CarveDerivation(elementNode)
def processElementNode(elementNode):
'Process the xml element.'
processElementNodeByDerivation(None, elementNode)
def processElementNodeByDerivation(derivation, elementNode):
'Process the xml element by derivation.'
if derivation == None:
derivation = CarveDerivation(elementNode)
targetElementNode = derivation.targetElementNode
if targetElementNode == None:
print('Warning, carve could not get target for:')
print(elementNode)
return
xmlObject = targetElementNode.xmlObject
if xmlObject == None:
print('Warning, processElementNodeByDerivation in carve could not get xmlObject for:')
print(targetElementNode)
print(derivation.elementNode)
return
matrix.getBranchMatrixSetElementNode(targetElementNode)
transformedVertexes = xmlObject.getTransformedVertexes()
if len(transformedVertexes) < 1:
print('Warning, transformedVertexes is zero in processElementNodeByDerivation in carve for:')
print(xmlObject)
print(targetElementNode)
print(derivation.elementNode)
return
elementNode.localName = 'group'
elementNode.getXMLProcessor().processElementNode(elementNode)
minimumZ = boolean_geometry.getMinimumZ(xmlObject)
maximumZ = euclidean.getTopPath(transformedVertexes)
zoneArrangement = triangle_mesh.ZoneArrangement(derivation.layerHeight, transformedVertexes)
oldVisibleString = targetElementNode.attributes['visible']
targetElementNode.attributes['visible'] = True
z = minimumZ + 0.5 * derivation.layerHeight
loopLayers = boolean_geometry.getLoopLayers([xmlObject], derivation.importRadius, derivation.layerHeight, maximumZ, False, z, zoneArrangement)
targetElementNode.attributes['visible'] = oldVisibleString
for loopLayerIndex, loopLayer in enumerate(loopLayers):
if len(loopLayer.loops) > 0:
pathElement = getLinkedElementNode('_carve_%s' % loopLayerIndex, elementNode, targetElementNode)
vector3Loops = euclidean.getVector3Paths(loopLayer.loops, loopLayer.z)
path.convertElementNode(pathElement, vector3Loops)
class CarveDerivation(object):
"Class to hold carve variables."
def __init__(self, elementNode):
'Set defaults.'
self.elementNode = elementNode
self.importRadius = setting.getImportRadius(elementNode)
self.layerHeight = setting.getLayerHeight(elementNode)
self.targetElementNode = evaluate.getElementNodeByKey(elementNode, 'target')

View File

@ -1,70 +0,0 @@
"""
Boolean geometry copy.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getNewDerivation(elementNode):
'Get new derivation.'
return CopyDerivation(elementNode)
def processElementNode(elementNode):
'Process the xml element.'
processElementNodeByDerivation(None, elementNode)
def processElementNodeByDerivation(derivation, elementNode):
'Process the xml element by derivation.'
if derivation == None:
derivation = CopyDerivation(elementNode)
if derivation.target == None:
print('Warning, copy could not get target for:')
print(elementNode)
return
del elementNode.attributes['target']
copyMatrix = matrix.getBranchMatrixSetElementNode(elementNode)
targetMatrix = matrix.getBranchMatrixSetElementNode(derivation.target)
targetDictionaryCopy = evaluate.removeIdentifiersFromDictionary(derivation.target.attributes.copy())
targetDictionaryCopy.update(elementNode.attributes)
elementNode.attributes = targetDictionaryCopy
euclidean.removeTrueFromDictionary(elementNode.attributes, 'visible')
elementNode.localName = derivation.target.localName
derivation.target.copyXMLChildNodes(elementNode.getIDSuffix(), elementNode)
elementNode.getXMLProcessor().processElementNode(elementNode)
if copyMatrix != None and targetMatrix != None:
elementNode.xmlObject.matrix4X4 = copyMatrix.getSelfTimesOther(targetMatrix.tetragrid)
if elementNode.xmlObject == None:
return
if len(elementNode.xmlObject.getPaths()) > 0:
lineation.processElementNode(elementNode)
return
geometryOutput = elementNode.xmlObject.getGeometryOutput()
if geometryOutput == None:
return
solidMatchingPlugins = solid.getSolidMatchingPlugins(elementNode)
if len(solidMatchingPlugins) == 0:
return
geometryOutput = solid.getGeometryOutputByManipulation(elementNode, geometryOutput)
elementNode.xmlObject.transformGeometryOutput(geometryOutput)
lineation.removeChildNodesFromElementObject(elementNode)
elementNode.getXMLProcessor().convertElementNode(elementNode, geometryOutput)
class CopyDerivation(object):
"Class to hold copy variables."
def __init__(self, elementNode):
'Set defaults.'
self.target = evaluate.getElementNodeByKey(elementNode, 'target')

View File

@ -1,112 +0,0 @@
"""
Boolean geometry disjoin.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_tools import path
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import boolean_geometry
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities.geometry.solids import difference
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import xml_simple_reader
from fabmetheus_utilities.vector3 import Vector3
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getLinkedElementNode(idSuffix, parentNode, target):
'Get elementNode with identifiers and parentNode.'
linkedElementNode = xml_simple_reader.ElementNode()
euclidean.overwriteDictionary(target.attributes, ['id', 'name', 'quantity'], linkedElementNode.attributes)
linkedElementNode.addSuffixToID(idSuffix)
tagKeys = target.getTagKeys()
tagKeys.append('disjoin')
tagKeys.sort()
tags = ', '.join(tagKeys)
linkedElementNode.attributes['tags'] = tags
linkedElementNode.setParentAddToChildNodes(parentNode)
linkedElementNode.addToIdentifierDictionaries()
return linkedElementNode
def getNewDerivation(elementNode):
'Get new derivation.'
return DisjoinDerivation(elementNode)
def processElementNode(elementNode):
'Process the xml element.'
processElementNodeByDerivation(None, elementNode)
def processElementNodeByDerivation(derivation, elementNode):
'Process the xml element by derivation.'
if derivation == None:
derivation = DisjoinDerivation(elementNode)
targetElementNode = derivation.targetElementNode
if targetElementNode == None:
print('Warning, disjoin could not get target for:')
print(elementNode)
return
xmlObject = targetElementNode.xmlObject
if xmlObject == None:
print('Warning, processElementNodeByDerivation in disjoin could not get xmlObject for:')
print(targetElementNode)
print(derivation.elementNode)
return
matrix.getBranchMatrixSetElementNode(targetElementNode)
transformedVertexes = xmlObject.getTransformedVertexes()
if len(transformedVertexes) < 1:
print('Warning, transformedVertexes is zero in processElementNodeByDerivation in disjoin for:')
print(xmlObject)
print(targetElementNode)
print(derivation.elementNode)
return
elementNode.localName = 'group'
elementNode.getXMLProcessor().processElementNode(elementNode)
targetChainMatrix = matrix.Matrix(xmlObject.getMatrixChainTetragrid())
minimumZ = boolean_geometry.getMinimumZ(xmlObject)
z = minimumZ + 0.5 * derivation.sheetThickness
zoneArrangement = triangle_mesh.ZoneArrangement(derivation.layerHeight, transformedVertexes)
oldVisibleString = targetElementNode.attributes['visible']
targetElementNode.attributes['visible'] = True
loops = boolean_geometry.getEmptyZLoops([xmlObject], derivation.importRadius, False, z, zoneArrangement)
targetElementNode.attributes['visible'] = oldVisibleString
vector3Loops = euclidean.getVector3Paths(loops, z)
pathElement = getLinkedElementNode('_sheet', elementNode, targetElementNode)
path.convertElementNode(pathElement, vector3Loops)
targetOutput = xmlObject.getGeometryOutput()
differenceElement = getLinkedElementNode('_solid', elementNode, targetElementNode)
targetElementCopy = targetElementNode.getCopy('_positive', differenceElement)
targetElementCopy.attributes['visible'] = True
targetElementCopy.attributes.update(targetChainMatrix.getAttributes('matrix.'))
complexMaximum = euclidean.getMaximumByVector3Path(transformedVertexes).dropAxis()
complexMinimum = euclidean.getMinimumByVector3Path(transformedVertexes).dropAxis()
centerComplex = 0.5 * (complexMaximum + complexMinimum)
centerVector3 = Vector3(centerComplex.real, centerComplex.imag, minimumZ)
slightlyMoreThanHalfExtent = 0.501 * (complexMaximum - complexMinimum)
inradius = Vector3(slightlyMoreThanHalfExtent.real, slightlyMoreThanHalfExtent.imag, derivation.sheetThickness)
cubeElement = xml_simple_reader.ElementNode()
cubeElement.attributes['inradius'] = str(inradius)
if not centerVector3.getIsDefault():
cubeElement.attributes['translate.'] = str(centerVector3)
cubeElement.localName = 'cube'
cubeElement.setParentAddToChildNodes(differenceElement)
difference.processElementNode(differenceElement)
class DisjoinDerivation(object):
"Class to hold disjoin variables."
def __init__(self, elementNode):
'Set defaults.'
self.elementNode = elementNode
self.importRadius = setting.getImportRadius(elementNode)
self.layerHeight = setting.getLayerHeight(elementNode)
self.sheetThickness = setting.getSheetThickness(elementNode)
self.targetElementNode = evaluate.getElementNodeByKey(elementNode, 'target')

View File

@ -1,93 +0,0 @@
"""
Boolean geometry group of solids.
"""
from __future__ import absolute_import
from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import group
from fabmetheus_utilities import xml_simple_reader
from fabmetheus_utilities import xml_simple_writer
from fabmetheus_utilities import archive
import os
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def appendAttributes(fromElementNode, toElementNode):
'Append the attributes from the child nodes of fromElementNode to the attributes of toElementNode.'
for childNode in fromElementNode.childNodes:
toElementNode.attributes.update(evaluate.removeIdentifiersFromDictionary(childNode.attributes.copy()))
def getNewDerivation(elementNode):
'Get new derivation.'
return ImportDerivation(elementNode)
def getXMLFromCarvingFileName(fileName):
'Get xml text from xml text.'
carving = fabmetheus_interpret.getCarving(fileName)
if carving == None:
return ''
output = xml_simple_writer.getBeginGeometryXMLOutput()
carving.addXML(0, output)
return xml_simple_writer.getEndGeometryXMLString(output)
def processElementNode(elementNode):
"Process the xml element."
processElementNodeByDerivation(None, elementNode)
def processElementNodeByDerivation(derivation, elementNode):
'Process the xml element by derivation.'
if derivation == None:
derivation = ImportDerivation(elementNode)
if derivation.fileName == None:
return
parserFileName = elementNode.getOwnerDocument().fileName
absoluteFileName = archive.getAbsoluteFolderPath(parserFileName, derivation.fileName)
if 'models/' not in absoluteFileName:
print('Warning, models/ was not in the absolute file path, so for security nothing will be done for:')
print(elementNode)
print('For which the absolute file path is:')
print(absoluteFileName)
print('The import tool can only read a file which has models/ in the file path.')
print('To import the file, move the file into a folder called model/ or a subfolder which is inside the model folder tree.')
return
xmlText = ''
if derivation.fileName.endswith('.xml'):
xmlText = archive.getFileText(absoluteFileName)
else:
xmlText = getXMLFromCarvingFileName(absoluteFileName)
print('The import tool is opening the file:')
print(absoluteFileName)
if xmlText == '':
print('The file %s could not be found by processElementNode in import.' % derivation.fileName)
return
if derivation.importName == None:
elementNode.attributes['_importName'] = archive.getUntilDot(derivation.fileName)
if derivation.basename:
elementNode.attributes['_importName'] = os.path.basename(elementNode.attributes['_importName'])
xml_simple_reader.createAppendByText(elementNode, xmlText)
if derivation.appendDocumentElement:
appendAttributes(elementNode, elementNode.getDocumentElement())
if derivation.appendElement:
appendAttributes(elementNode, elementNode)
elementNode.localName = 'group'
evaluate.processArchivable(group.Group, elementNode)
class ImportDerivation(object):
"Class to hold import variables."
def __init__(self, elementNode):
'Set defaults.'
self.appendDocumentElement = evaluate.getEvaluatedBoolean(False, elementNode, 'appendDocumentElement')
self.appendElement = evaluate.getEvaluatedBoolean(False, elementNode, 'appendElement')
self.basename = evaluate.getEvaluatedBoolean(True, elementNode, 'basename')
self.elementNode = elementNode
self.fileName = evaluate.getEvaluatedString('', elementNode, 'file')
self.importName = evaluate.getEvaluatedString(None, elementNode, '_importName')

View File

@ -1,94 +0,0 @@
"""
Boolean geometry write.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities import archive
import os
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def getNewDerivation(elementNode):
'Get new derivation.'
return WriteDerivation(elementNode)
def processElementNode(elementNode):
"Process the xml element."
processElementNodeByDerivation(None, elementNode)
def processElementNodeByDerivation(derivation, elementNode):
'Process the xml element by derivation.'
if derivation == None:
derivation = WriteDerivation(elementNode)
if len(derivation.targets) < 1:
print('Warning, processElementNode in write could not get targets for:')
print(elementNode)
return
fileNames = []
for target in derivation.targets:
writeElementNode(derivation, fileNames, target)
def writeElementNode(derivation, fileNames, target):
"Write a quantity of the target."
xmlObject = target.xmlObject
if xmlObject == None:
print('Warning, writeTarget in write could not get xmlObject for:')
print(target)
print(derivation.elementNode)
return
parserDirectory = os.path.dirname(derivation.elementNode.getOwnerDocument().fileName)
absoluteFolderDirectory = os.path.abspath(os.path.join(parserDirectory, derivation.folderName))
if '/models' not in absoluteFolderDirectory:
print('Warning, models/ was not in the absolute file path, so for security nothing will be done for:')
print(derivation.elementNode)
print('For which the absolute folder path is:')
print(absoluteFolderDirectory)
print('The write tool can only write a file which has models/ in the file path.')
print('To write the file, move the file into a folder called model/ or a subfolder which is inside the model folder tree.')
return
quantity = evaluate.getEvaluatedInt(1, target, 'quantity')
for itemIndex in xrange(quantity):
writeXMLObject(absoluteFolderDirectory, derivation, fileNames, target, xmlObject)
def writeXMLObject(absoluteFolderDirectory, derivation, fileNames, target, xmlObject):
"Write one instance of the xmlObject."
extension = evaluate.getEvaluatedString(xmlObject.getFabricationExtension(), derivation.elementNode, 'extension')
fileNameRoot = derivation.fileName
if fileNameRoot == '':
fileNameRoot = evaluate.getEvaluatedString('', target, 'name')
fileNameRoot = evaluate.getEvaluatedString(fileNameRoot, target, 'id')
fileNameRoot += derivation.suffix
fileName = '%s.%s' % (fileNameRoot, extension)
suffixIndex = 2
while fileName in fileNames:
fileName = '%s_%s.%s' % (fileNameRoot, suffixIndex, extension)
suffixIndex += 1
absoluteFileName = os.path.join(absoluteFolderDirectory, fileName)
fileNames.append(fileName)
archive.makeDirectory(absoluteFolderDirectory)
if not derivation.writeMatrix:
xmlObject.matrix4X4 = matrix.Matrix()
print('The write tool generated the file:')
print(absoluteFileName)
archive.writeFileText(absoluteFileName, xmlObject.getFabricationText(derivation.addLayerTemplate))
class WriteDerivation(object):
"Class to hold write variables."
def __init__(self, elementNode):
'Set defaults.'
self.addLayerTemplate = evaluate.getEvaluatedBoolean(False, elementNode, 'addLayerTemplate')
self.elementNode = elementNode
self.fileName = evaluate.getEvaluatedString('', elementNode, 'file')
self.folderName = evaluate.getEvaluatedString('', elementNode, 'folder')
self.suffix = evaluate.getEvaluatedString('', elementNode, 'suffix')
self.targets = evaluate.getElementNodesByKey(elementNode, 'target')
self.writeMatrix = evaluate.getEvaluatedBoolean(True, elementNode, 'writeMatrix')

View File

@ -1,68 +0,0 @@
"""
Add material to support overhang or remove material at the overhang angle.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 20
def getBevelPath( begin, center, close, end, radius ):
"Get bevel path."
beginComplex = begin.dropAxis()
centerComplex = center.dropAxis()
endComplex = end.dropAxis()
beginComplexSegmentLength = abs( centerComplex - beginComplex )
endComplexSegmentLength = abs( centerComplex - endComplex )
minimumRadius = lineation.getMinimumRadius( beginComplexSegmentLength, endComplexSegmentLength, radius )
if minimumRadius <= close:
return [ center ]
beginBevel = center + minimumRadius / beginComplexSegmentLength * ( begin - center )
endBevel = center + minimumRadius / endComplexSegmentLength * ( end - center )
if radius > 0.0:
return [ beginBevel, endBevel ]
midpointComplex = 0.5 * ( beginBevel.dropAxis() + endBevel.dropAxis() )
spikeComplex = centerComplex + centerComplex - midpointComplex
return [ beginBevel, Vector3( spikeComplex.real, spikeComplex.imag, center.z ), endBevel ]
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get bevel loop."
if len(loop) < 3:
return [loop]
derivation = BevelDerivation(elementNode, prefix, sideLength)
if derivation.radius == 0.0:
return loop
bevelLoop = []
for pointIndex in xrange(len(loop)):
begin = loop[(pointIndex + len(loop) - 1) % len(loop)]
center = loop[pointIndex]
end = loop[(pointIndex + 1) % len(loop)]
bevelLoop += getBevelPath(begin, center, close, end, derivation.radius)
return [euclidean.getLoopWithoutCloseSequentialPoints(close, bevelLoop)]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return BevelDerivation(elementNode, prefix, sideLength)
def processElementNode(elementNode):
"Process the xml element."
lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
class BevelDerivation(object):
"Class to hold bevel variables."
def __init__(self, elementNode, prefix, sideLength):
'Set defaults.'
self.radius = lineation.getFloatByPrefixSide(0.0, elementNode, prefix + 'radius', sideLength)

View File

@ -1,35 +0,0 @@
"""
Create outline.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 80
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get path with overhangs removed or filled in."
if len(loop) < 4:
return [loop]
loopComplex = euclidean.getComplexPath(loop)
return euclidean.getVector3Paths([euclidean.getLoopConvex(loopComplex)], loop[0].z)
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return evaluate.EmptyObject()
def processElementNode(elementNode):
"Process the xml element."
lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)

View File

@ -1,50 +0,0 @@
"""
Create outline.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import intercircle
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 80
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get path with outline."
if len(loop) < 2:
return [loop]
derivation = OutlineDerivation(elementNode, prefix, sideLength)
loopComplex = euclidean.getComplexPath(loop)
if derivation.isClosed:
loopComplexes = intercircle.getAroundsFromLoop(loopComplex, derivation.radius)
else:
loopComplexes = intercircle.getAroundsFromPath(loopComplex, derivation.radius)
return euclidean.getVector3Paths(loopComplexes, loop[0].z)
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return OutlineDerivation(elementNode, prefix, sideLength)
def processElementNode(elementNode):
"Process the xml element."
lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
class OutlineDerivation(object):
"Class to hold outline variables."
def __init__(self, elementNode, prefix, sideLength):
'Set defaults.'
self.isClosed = evaluate.getEvaluatedBoolean(False, elementNode, prefix + 'closed')
self.radius = evaluate.getEvaluatedFloat(setting.getEdgeWidth(elementNode), elementNode, prefix + 'radius')

View File

@ -1,395 +0,0 @@
"""
Add material to support overhang or remove material at the overhang angle.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 100
def addUnsupportedPointIndexes( alongAway ):
"Add the indexes of the unsupported points."
addedUnsupportedPointIndexes = []
for pointIndex in xrange( len( alongAway.loop ) ):
point = alongAway.loop[pointIndex]
if pointIndex not in alongAway.unsupportedPointIndexes:
if not alongAway.getIsClockwisePointSupported(point):
alongAway.unsupportedPointIndexes.append( pointIndex )
addedUnsupportedPointIndexes.append( pointIndex )
for pointIndex in addedUnsupportedPointIndexes:
point = alongAway.loop[pointIndex]
point.y += alongAway.maximumYPlus
def alterClockwiseSupportedPath( alongAway, elementNode ):
"Get clockwise path with overhangs carved out."
alongAway.bottomPoints = []
alongAway.overhangSpan = setting.getOverhangSpan(elementNode)
maximumY = - 987654321.0
minimumYPointIndex = 0
for pointIndex in xrange( len( alongAway.loop ) ):
point = alongAway.loop[pointIndex]
if point.y < alongAway.loop[ minimumYPointIndex ].y:
minimumYPointIndex = pointIndex
maximumY = max( maximumY, point.y )
alongAway.maximumYPlus = 2.0 * ( maximumY - alongAway.loop[ minimumYPointIndex ].y )
alongAway.loop = euclidean.getAroundLoop( minimumYPointIndex, minimumYPointIndex, alongAway.loop )
overhangClockwise = OverhangClockwise( alongAway )
alongAway.unsupportedPointIndexes = []
oldUnsupportedPointIndexesLength = - 987654321.0
while len( alongAway.unsupportedPointIndexes ) > oldUnsupportedPointIndexesLength:
oldUnsupportedPointIndexesLength = len( alongAway.unsupportedPointIndexes )
addUnsupportedPointIndexes( alongAway )
for pointIndex in alongAway.unsupportedPointIndexes:
point = alongAway.loop[pointIndex]
point.y -= alongAway.maximumYPlus
alongAway.unsupportedPointIndexes.sort()
alongAway.unsupportedPointIndexLists = []
oldUnsupportedPointIndex = - 987654321.0
unsupportedPointIndexList = None
for unsupportedPointIndex in alongAway.unsupportedPointIndexes:
if unsupportedPointIndex > oldUnsupportedPointIndex + 1:
unsupportedPointIndexList = []
alongAway.unsupportedPointIndexLists.append( unsupportedPointIndexList )
oldUnsupportedPointIndex = unsupportedPointIndex
unsupportedPointIndexList.append( unsupportedPointIndex )
alongAway.unsupportedPointIndexLists.reverse()
for unsupportedPointIndexList in alongAway.unsupportedPointIndexLists:
overhangClockwise.alterLoop( unsupportedPointIndexList )
def alterWiddershinsSupportedPath( alongAway, close ):
"Get widdershins path with overhangs filled in."
alongAway.bottomPoints = []
alongAway.minimumY = getMinimumYByPath( alongAway.loop )
for point in alongAway.loop:
if point.y - alongAway.minimumY < close:
alongAway.addToBottomPoints(point)
ascendingYPoints = alongAway.loop[:]
ascendingYPoints.sort( compareYAscending )
overhangWiddershinsLeft = OverhangWiddershinsLeft( alongAway )
overhangWiddershinsRight = OverhangWiddershinsRight( alongAway )
for point in ascendingYPoints:
alterWiddershinsSupportedPathByPoint( alongAway, overhangWiddershinsLeft, overhangWiddershinsRight, point )
def alterWiddershinsSupportedPathByPoint( alongAway, overhangWiddershinsLeft, overhangWiddershinsRight, point ):
"Get widdershins path with overhangs filled in for point."
if alongAway.getIsWiddershinsPointSupported(point):
return
overhangWiddershins = overhangWiddershinsLeft
if overhangWiddershinsRight.getDistance() < overhangWiddershinsLeft.getDistance():
overhangWiddershins = overhangWiddershinsRight
overhangWiddershins.alterLoop()
def compareYAscending( point, pointOther ):
"Get comparison in order to sort points in ascending y."
if point.y < pointOther.y:
return - 1
return int( point.y > pointOther.y )
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get path with overhangs removed or filled in."
if len(loop) < 3:
print('Warning, loop has less than three sides in getManipulatedPaths in overhang for:')
print(elementNode)
return [loop]
derivation = OverhangDerivation(elementNode, prefix)
overhangPlaneAngle = euclidean.getWiddershinsUnitPolar(0.5 * math.pi - derivation.overhangRadians)
if derivation.overhangInclinationRadians != 0.0:
overhangInclinationCosine = abs(math.cos(derivation.overhangInclinationRadians))
if overhangInclinationCosine == 0.0:
return [loop]
imaginaryTimesCosine = overhangPlaneAngle.imag * overhangInclinationCosine
overhangPlaneAngle = euclidean.getNormalized(complex(overhangPlaneAngle.real, imaginaryTimesCosine))
alongAway = AlongAway(loop, overhangPlaneAngle)
if euclidean.getIsWiddershinsByVector3(loop):
alterWiddershinsSupportedPath(alongAway, close)
else:
alterClockwiseSupportedPath(alongAway, elementNode)
return [euclidean.getLoopWithoutCloseSequentialPoints(close, alongAway.loop)]
def getMinimumYByPath(path):
"Get path with overhangs removed or filled in."
minimumYByPath = path[0].y
for point in path:
minimumYByPath = min( minimumYByPath, point.y )
return minimumYByPath
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return OverhangDerivation(elementNode, prefix)
def processElementNode(elementNode):
"Process the xml element."
lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
class AlongAway(object):
"Class to derive the path along the point and away from the point."
def __init__( self, loop, overhangPlaneAngle ):
"Initialize."
self.loop = loop
self.overhangPlaneAngle = overhangPlaneAngle
self.ySupport = - self.overhangPlaneAngle.imag
def __repr__(self):
"Get the string representation of AlongAway."
return '%s' % ( self.overhangPlaneAngle )
def addToBottomPoints(self, point):
"Add point to bottom points and set y to minimumY."
self.bottomPoints.append(point)
point.y = self.minimumY
def getIsClockwisePointSupported(self, point):
"Determine if the point on the clockwise loop is supported."
self.point = point
self.pointIndex = None
self.awayIndexes = []
numberOfIntersectionsBelow = 0
for pointIndex in xrange( len( self.loop ) ):
begin = self.loop[pointIndex]
end = self.loop[ (pointIndex + 1) % len( self.loop ) ]
if begin != point and end != point:
self.awayIndexes.append( pointIndex )
yIntersection = euclidean.getYIntersectionIfExists( begin.dropAxis(), end.dropAxis(), point.x )
if yIntersection != None:
numberOfIntersectionsBelow += ( yIntersection < point.y )
if begin == point:
self.pointIndex = pointIndex
if numberOfIntersectionsBelow % 2 == 0:
return True
if self.pointIndex == None:
return True
if self.getIsPointSupportedBySegment( self.pointIndex - 1 + len( self.loop ) ):
return True
return self.getIsPointSupportedBySegment( self.pointIndex + 1 )
def getIsPointSupportedBySegment( self, endIndex ):
"Determine if the point on the widdershins loop is supported."
endComplex = self.loop[ ( endIndex % len( self.loop ) ) ].dropAxis()
endMinusPointComplex = euclidean.getNormalized( endComplex - self.point.dropAxis() )
return endMinusPointComplex.imag < self.ySupport
def getIsWiddershinsPointSupported(self, point):
"Determine if the point on the widdershins loop is supported."
if point.y <= self.minimumY:
return True
self.point = point
self.pointIndex = None
self.awayIndexes = []
numberOfIntersectionsBelow = 0
for pointIndex in xrange( len( self.loop ) ):
begin = self.loop[pointIndex]
end = self.loop[ (pointIndex + 1) % len( self.loop ) ]
if begin != point and end != point:
self.awayIndexes.append( pointIndex )
yIntersection = euclidean.getYIntersectionIfExists( begin.dropAxis(), end.dropAxis(), point.x )
if yIntersection != None:
numberOfIntersectionsBelow += ( yIntersection < point.y )
if begin == point:
self.pointIndex = pointIndex
if numberOfIntersectionsBelow % 2 == 1:
return True
if self.pointIndex == None:
return True
if self.getIsPointSupportedBySegment( self.pointIndex - 1 + len( self.loop ) ):
return True
return self.getIsPointSupportedBySegment( self.pointIndex + 1 )
class OverhangClockwise(object):
"Class to get the intersection up from the point."
def __init__( self, alongAway ):
"Initialize."
self.alongAway = alongAway
self.halfRiseOverWidth = 0.5 * alongAway.overhangPlaneAngle.imag / alongAway.overhangPlaneAngle.real
self.widthOverRise = alongAway.overhangPlaneAngle.real / alongAway.overhangPlaneAngle.imag
def __repr__(self):
"Get the string representation of OverhangClockwise."
return '%s' % ( self.intersectionPlaneAngle )
def alterLoop( self, unsupportedPointIndexes ):
"Alter alongAway loop."
unsupportedBeginIndex = unsupportedPointIndexes[0]
unsupportedEndIndex = unsupportedPointIndexes[-1]
beginIndex = unsupportedBeginIndex - 1
endIndex = unsupportedEndIndex + 1
begin = self.alongAway.loop[ beginIndex ]
end = self.alongAway.loop[ endIndex ]
truncatedOverhangSpan = self.alongAway.overhangSpan
width = end.x - begin.x
heightDifference = abs( end.y - begin.y )
remainingWidth = width - self.widthOverRise * heightDifference
if remainingWidth <= 0.0:
del self.alongAway.loop[ unsupportedBeginIndex : endIndex ]
return
highest = begin
supportX = begin.x + remainingWidth
if end.y > begin.y:
highest = end
supportX = end.x - remainingWidth
tipY = highest.y + self.halfRiseOverWidth * remainingWidth
highestBetween = - 987654321.0
for unsupportedPointIndex in unsupportedPointIndexes:
highestBetween = max( highestBetween, self.alongAway.loop[ unsupportedPointIndex ].y )
if highestBetween > highest.y:
truncatedOverhangSpan = 0.0
if highestBetween < tipY:
below = tipY - highestBetween
truncatedOverhangSpan = min( self.alongAway.overhangSpan, below / self.halfRiseOverWidth )
truncatedOverhangSpanRadius = 0.5 * truncatedOverhangSpan
if remainingWidth <= truncatedOverhangSpan:
supportPoint = Vector3( supportX, highest.y, highest.z )
self.alongAway.loop[ unsupportedBeginIndex : endIndex ] = [ supportPoint ]
return
midSupportX = 0.5 * ( supportX + highest.x )
if truncatedOverhangSpan <= 0.0:
supportPoint = Vector3( midSupportX, tipY, highest.z )
self.alongAway.loop[ unsupportedBeginIndex : endIndex ] = [ supportPoint ]
return
supportXLeft = midSupportX - truncatedOverhangSpanRadius
supportXRight = midSupportX + truncatedOverhangSpanRadius
supportY = tipY - self.halfRiseOverWidth * truncatedOverhangSpan
supportPoints = [ Vector3( supportXLeft, supportY, highest.z ), Vector3( supportXRight, supportY, highest.z ) ]
self.alongAway.loop[ unsupportedBeginIndex : endIndex ] = supportPoints
class OverhangDerivation(object):
"Class to hold overhang variables."
def __init__(self, elementNode, prefix):
'Set defaults.'
self.overhangRadians = setting.getOverhangRadians(elementNode)
self.overhangInclinationRadians = math.radians(evaluate.getEvaluatedFloat(0.0, elementNode, prefix + 'inclination'))
class OverhangWiddershinsLeft(object):
"Class to get the intersection from the point down to the left."
def __init__( self, alongAway ):
"Initialize."
self.alongAway = alongAway
self.intersectionPlaneAngle = - alongAway.overhangPlaneAngle
self.setRatios()
def __repr__(self):
"Get the string representation of OverhangWiddershins."
return '%s' % ( self.intersectionPlaneAngle )
def alterLoop(self):
"Alter alongAway loop."
insertedPoint = self.alongAway.point.copy()
if self.closestXIntersectionIndex != None:
self.alongAway.loop = self.getIntersectLoop()
intersectionRelativeComplex = self.closestXDistance * self.intersectionPlaneAngle
intersectionPoint = insertedPoint + Vector3( intersectionRelativeComplex.real, intersectionRelativeComplex.imag )
self.alongAway.loop.append( intersectionPoint )
return
if self.closestBottomPoint == None:
return
if self.closestBottomPoint not in self.alongAway.loop:
return
insertedPoint.x = self.bottomX
closestBottomIndex = self.alongAway.loop.index( self.closestBottomPoint )
self.alongAway.addToBottomPoints( insertedPoint )
self.alongAway.loop = self.getBottomLoop( closestBottomIndex, insertedPoint )
self.alongAway.loop.append( insertedPoint )
def getBottomLoop( self, closestBottomIndex, insertedPoint ):
"Get loop around bottom."
endIndex = closestBottomIndex + len( self.alongAway.loop ) + 1
return euclidean.getAroundLoop( self.alongAway.pointIndex, endIndex, self.alongAway.loop )
def getDistance(self):
"Get distance between point and closest intersection or bottom point along line."
self.pointMinusBottomY = self.alongAway.point.y - self.alongAway.minimumY
self.diagonalDistance = self.pointMinusBottomY * self.diagonalRatio
if self.alongAway.pointIndex == None:
return self.getDistanceToBottom()
rotatedLoop = euclidean.getRotatedComplexes( self.intersectionYMirror, euclidean.getComplexPath( self.alongAway.loop ) )
rotatedPointComplex = rotatedLoop[ self.alongAway.pointIndex ]
beginX = rotatedPointComplex.real
endX = beginX + self.diagonalDistance + self.diagonalDistance
xIntersectionIndexList = []
for pointIndex in self.alongAway.awayIndexes:
beginComplex = rotatedLoop[pointIndex]
endComplex = rotatedLoop[ (pointIndex + 1) % len( rotatedLoop ) ]
xIntersection = euclidean.getXIntersectionIfExists( beginComplex, endComplex, rotatedPointComplex.imag )
if xIntersection != None:
if xIntersection >= beginX and xIntersection < endX:
xIntersectionIndexList.append( euclidean.XIntersectionIndex( pointIndex, xIntersection ) )
self.closestXDistance = 987654321.0
self.closestXIntersectionIndex = None
for xIntersectionIndex in xIntersectionIndexList:
xDistance = abs( xIntersectionIndex.x - beginX )
if xDistance < self.closestXDistance:
self.closestXIntersectionIndex = xIntersectionIndex
self.closestXDistance = xDistance
if self.closestXIntersectionIndex != None:
return self.closestXDistance
return self.getDistanceToBottom()
def getDistanceToBottom(self):
"Get distance between point and closest bottom point along line."
self.bottomX = self.alongAway.point.x + self.pointMinusBottomY * self.xRatio
self.closestBottomPoint = None
closestDistanceX = 987654321.0
for point in self.alongAway.bottomPoints:
distanceX = abs( point.x - self.bottomX )
if self.getIsOnside(point.x):
if distanceX < closestDistanceX:
closestDistanceX = distanceX
self.closestBottomPoint = point
return closestDistanceX + self.diagonalDistance
def getIntersectLoop(self):
"Get intersection loop."
endIndex = self.closestXIntersectionIndex.index + len( self.alongAway.loop ) + 1
return euclidean.getAroundLoop( self.alongAway.pointIndex, endIndex, self.alongAway.loop )
def getIsOnside( self, x ):
"Determine if x is on the side along the direction of the intersection line."
return x <= self.alongAway.point.x
def setRatios(self):
"Set ratios."
self.diagonalRatio = 1.0 / abs( self.intersectionPlaneAngle.imag )
self.intersectionYMirror = complex( self.intersectionPlaneAngle.real, - self.intersectionPlaneAngle.imag )
self.xRatio = self.intersectionPlaneAngle.real / abs( self.intersectionPlaneAngle.imag )
class OverhangWiddershinsRight( OverhangWiddershinsLeft ):
"Class to get the intersection from the point down to the right."
def __init__( self, alongAway ):
"Initialize."
self.alongAway = alongAway
self.intersectionPlaneAngle = complex( alongAway.overhangPlaneAngle.real, - alongAway.overhangPlaneAngle.imag )
self.setRatios()
def getBottomLoop( self, closestBottomIndex, insertedPoint ):
"Get loop around bottom."
endIndex = self.alongAway.pointIndex + len( self.alongAway.loop ) + 1
return euclidean.getAroundLoop( closestBottomIndex, endIndex, self.alongAway.loop )
def getIntersectLoop(self):
"Get intersection loop."
beginIndex = self.closestXIntersectionIndex.index + len( self.alongAway.loop ) + 1
endIndex = self.alongAway.pointIndex + len( self.alongAway.loop ) + 1
return euclidean.getAroundLoop( beginIndex, endIndex, self.alongAway.loop )
def getIsOnside( self, x ):
"Determine if x is on the side along the direction of the intersection line."
return x >= self.alongAway.point.x

View File

@ -1,92 +0,0 @@
"""
Add material to support overhang or remove material at the overhang angle.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 40
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get round loop."
if len(loop) < 3:
return [loop]
derivation = RoundDerivation(elementNode, prefix, sideLength)
if derivation.radius == 0.0:
return loop
roundLoop = []
sidesPerRadian = 0.5 / math.pi * evaluate.getSidesMinimumThreeBasedOnPrecision(elementNode, sideLength)
for pointIndex in xrange(len(loop)):
begin = loop[(pointIndex + len(loop) - 1) % len(loop)]
center = loop[pointIndex]
end = loop[(pointIndex + 1) % len(loop)]
roundLoop += getRoundPath(begin, center, close, end, derivation.radius, sidesPerRadian)
return [euclidean.getLoopWithoutCloseSequentialPoints(close, roundLoop)]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return RoundDerivation(elementNode, prefix, sideLength)
def getRoundPath( begin, center, close, end, radius, sidesPerRadian ):
"Get round path."
beginComplex = begin.dropAxis()
centerComplex = center.dropAxis()
endComplex = end.dropAxis()
beginComplexSegmentLength = abs( centerComplex - beginComplex )
endComplexSegmentLength = abs( centerComplex - endComplex )
minimumRadius = lineation.getMinimumRadius( beginComplexSegmentLength, endComplexSegmentLength, radius )
if minimumRadius <= close:
return [ center ]
beginBevel = center + minimumRadius / beginComplexSegmentLength * ( begin - center )
endBevel = center + minimumRadius / endComplexSegmentLength * ( end - center )
beginBevelComplex = beginBevel.dropAxis()
endBevelComplex = endBevel.dropAxis()
midpointComplex = 0.5 * ( beginBevelComplex + endBevelComplex )
if radius < 0.0:
centerComplex = midpointComplex + midpointComplex - centerComplex
midpointMinusCenterComplex = midpointComplex - centerComplex
midpointCenterLength = abs( midpointMinusCenterComplex )
midpointEndLength = abs( midpointComplex - endBevelComplex )
midpointCircleCenterLength = midpointEndLength * midpointEndLength / midpointCenterLength
circleRadius = math.sqrt( midpointCircleCenterLength * midpointCircleCenterLength + midpointEndLength * midpointEndLength )
circleCenterComplex = midpointComplex + midpointMinusCenterComplex * midpointCircleCenterLength / midpointCenterLength
circleCenter = Vector3( circleCenterComplex.real, circleCenterComplex.imag, center.z )
endMinusCircleCenterComplex = endBevelComplex - circleCenterComplex
beginMinusCircleCenter = beginBevel - circleCenter
beginMinusCircleCenterComplex = beginMinusCircleCenter.dropAxis()
angleDifference = euclidean.getAngleDifferenceByComplex( endMinusCircleCenterComplex, beginMinusCircleCenterComplex )
steps = int( math.ceil( abs( angleDifference ) * sidesPerRadian ) )
stepPlaneAngle = euclidean.getWiddershinsUnitPolar( angleDifference / float( steps ) )
deltaZStep = ( end.z - begin.z ) / float( steps )
roundPath = [ beginBevel ]
for step in xrange( 1, steps ):
beginMinusCircleCenterComplex = beginMinusCircleCenterComplex * stepPlaneAngle
arcPointComplex = circleCenterComplex + beginMinusCircleCenterComplex
arcPoint = Vector3( arcPointComplex.real, arcPointComplex.imag, begin.z + deltaZStep * step )
roundPath.append( arcPoint )
return roundPath + [ endBevel ]
def processElementNode(elementNode):
"Process the xml element."
lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
class RoundDerivation(object):
"Class to hold round variables."
def __init__(self, elementNode, prefix, sideLength):
'Set defaults.'
self.radius = lineation.getFloatByPrefixSide(0.0, elementNode, prefix + 'radius', sideLength)

View File

@ -1,164 +0,0 @@
"""
Add material to support overhang or remove material at the overhang angle.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 60
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get segment loop."
if len(loop) < 3:
return [loop]
derivation = SegmentDerivation(elementNode, prefix)
if derivation.path == getSegmentPathDefault():
return [loop]
path = getXNormalizedVector3Path(derivation.path)
if euclidean.getIsWiddershinsByVector3(loop):
path = path[: : -1]
for point in path:
point.x = 1.0 - point.x
if derivation.center == None:
point.y = - point.y
segmentLoop = []
startEnd = StartEnd(elementNode, len(loop), prefix)
for pointIndex in xrange(len(loop)):
if pointIndex >= startEnd.start and pointIndex < startEnd.end:
segmentLoop += getSegmentPath(derivation.center, loop, path, pointIndex)
else:
segmentLoop.append(loop[pointIndex])
return [euclidean.getLoopWithoutCloseSequentialPoints( close, segmentLoop)]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return SegmentDerivation(elementNode, prefix)
def getRadialPath(begin, center, end, path):
"Get radial path."
beginComplex = begin.dropAxis()
endComplex = end.dropAxis()
centerComplex = center.dropAxis()
beginMinusCenterComplex = beginComplex - centerComplex
endMinusCenterComplex = endComplex - centerComplex
beginMinusCenterComplexRadius = abs( beginMinusCenterComplex )
endMinusCenterComplexRadius = abs( endMinusCenterComplex )
if beginMinusCenterComplexRadius == 0.0 or endMinusCenterComplexRadius == 0.0:
return [ begin ]
beginMinusCenterComplex /= beginMinusCenterComplexRadius
endMinusCenterComplex /= endMinusCenterComplexRadius
angleDifference = euclidean.getAngleDifferenceByComplex( endMinusCenterComplex, beginMinusCenterComplex )
radialPath = []
for point in path:
weightEnd = point.x
weightBegin = 1.0 - weightEnd
weightedRadius = beginMinusCenterComplexRadius * weightBegin + endMinusCenterComplexRadius * weightEnd * ( 1.0 + point.y )
radialComplex = weightedRadius * euclidean.getWiddershinsUnitPolar( angleDifference * point.x ) * beginMinusCenterComplex
polygonPoint = center + Vector3( radialComplex.real, radialComplex.imag, point.z )
radialPath.append( polygonPoint )
return radialPath
def getSegmentPath(center, loop, path, pointIndex):
"Get segment path."
centerBegin = loop[pointIndex]
centerEnd = loop[(pointIndex + 1) % len(loop)]
centerEndMinusBegin = centerEnd - centerBegin
if abs( centerEndMinusBegin ) <= 0.0:
return [ centerBegin ]
if center != None:
return getRadialPath(centerBegin, center, centerEnd, path)
begin = loop[(pointIndex + len(loop) - 1) % len(loop)]
end = loop[(pointIndex + 2) % len(loop)]
return getWedgePath(begin, centerBegin, centerEnd, centerEndMinusBegin, end, path)
def getSegmentPathDefault():
"Get segment path default."
return [Vector3(), Vector3(0.0, 1.0)]
def getWedgePath( begin, centerBegin, centerEnd, centerEndMinusBegin, end, path ):
"Get segment path."
beginComplex = begin.dropAxis()
centerBeginComplex = centerBegin.dropAxis()
centerEndComplex = centerEnd.dropAxis()
endComplex = end.dropAxis()
wedgePath = []
centerBeginMinusBeginComplex = euclidean.getNormalized( centerBeginComplex - beginComplex )
centerEndMinusCenterBeginComplexOriginal = centerEndComplex - centerBeginComplex
centerEndMinusCenterBeginComplexLength = abs( centerEndMinusCenterBeginComplexOriginal )
if centerEndMinusCenterBeginComplexLength <= 0.0:
return [ centerBegin ]
centerEndMinusCenterBeginComplex = centerEndMinusCenterBeginComplexOriginal / centerEndMinusCenterBeginComplexLength
endMinusCenterEndComplex = euclidean.getNormalized( endComplex - centerEndComplex )
widdershinsBegin = getWiddershinsAverageByVector3( centerBeginMinusBeginComplex, centerEndMinusCenterBeginComplex )
widdershinsEnd = getWiddershinsAverageByVector3( centerEndMinusCenterBeginComplex, endMinusCenterEndComplex )
for point in path:
weightEnd = point.x
weightBegin = 1.0 - weightEnd
polygonPoint = centerBegin + centerEndMinusBegin * point.x
weightedWiddershins = widdershinsBegin * weightBegin + widdershinsEnd * weightEnd
polygonPoint += weightedWiddershins * point.y * centerEndMinusCenterBeginComplexLength
polygonPoint.z += point.z
wedgePath.append( polygonPoint )
return wedgePath
def getWiddershinsAverageByVector3( centerMinusBeginComplex, endMinusCenterComplex ):
"Get the normalized average of the widdershins vectors."
centerMinusBeginWiddershins = Vector3( - centerMinusBeginComplex.imag, centerMinusBeginComplex.real )
endMinusCenterWiddershins = Vector3( - endMinusCenterComplex.imag, endMinusCenterComplex.real )
return ( centerMinusBeginWiddershins + endMinusCenterWiddershins ).getNormalized()
def getXNormalizedVector3Path(path):
"Get path where the x ranges from 0 to 1."
if len(path) < 1:
return path
minimumX = path[0].x
for point in path[1 :]:
minimumX = min( minimumX, point.x )
for point in path:
point.x -= minimumX
maximumX = path[0].x
for point in path[1 :]:
maximumX = max( maximumX, point.x )
for point in path:
point.x /= maximumX
return path
def processElementNode(elementNode):
"Process the xml element."
lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
class SegmentDerivation(object):
"Class to hold segment variables."
def __init__(self, elementNode, prefix):
'Set defaults.'
self.center = evaluate.getVector3ByPrefix(None, elementNode, prefix + 'center')
self.path = evaluate.getPathByPrefix(elementNode, getSegmentPathDefault(), prefix)
class StartEnd(object):
'Class to get a start through end range.'
def __init__(self, elementNode, modulo, prefix):
"Initialize."
self.start = evaluate.getEvaluatedInt(0, elementNode, prefix + 'start')
self.extent = evaluate.getEvaluatedInt(modulo - self.start, elementNode, prefix + 'extent')
self.end = evaluate.getEvaluatedInt(self.start + self.extent, elementNode, prefix + 'end')
self.revolutions = evaluate.getEvaluatedInt(1, elementNode, prefix + 'revolutions')
if self.revolutions > 1:
self.end += modulo * (self.revolutions - 1)
def __repr__(self):
"Get the string representation of this StartEnd."
return '%s, %s, %s' % (self.start, self.end, self.revolutions)

View File

@ -1,41 +0,0 @@
"""
Add material to support overhang or remove material at the overhang angle.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.vector3 import Vector3
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = -200
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get wedge loop."
derivation = WedgeDerivation(elementNode, prefix)
loop.append(derivation.center)
return [loop]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return WedgeDerivation(elementNode, prefix)
def processElementNode(elementNode):
"Process the xml element."
lineation.processElementNodeByFunction(elementNode, getManipulatedPaths)
class WedgeDerivation(object):
"Class to hold wedge variables."
def __init__(self, elementNode, prefix):
'Set defaults.'
self.center = evaluate.getVector3ByPrefix(Vector3(), elementNode, prefix + 'center')

View File

@ -1,102 +0,0 @@
"""
Boolean geometry bottom.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import boolean_geometry
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 400
def bottomElementNode(derivation, target):
"Bottom target."
xmlObject = target.xmlObject
if xmlObject == None:
print('Warning, bottomTarget in bottom could not get xmlObject for:')
print(target)
print(derivation.elementNode)
return
targetMatrix = matrix.getBranchMatrixSetElementNode(target)
lift = derivation.altitude
transformedPaths = xmlObject.getTransformedPaths()
if len(transformedPaths) > 0:
lift += derivation.getAdditionalPathLift() - euclidean.getBottomByPaths(transformedPaths)
else:
lift -= boolean_geometry.getMinimumZ(xmlObject)
targetMatrix.tetragrid = matrix.getIdentityTetragrid(targetMatrix.tetragrid)
targetMatrix.tetragrid[2][3] += lift
matrix.setElementNodeDictionaryMatrix(target, targetMatrix)
def getManipulatedGeometryOutput(elementNode, geometryOutput, prefix):
'Get bottomed geometryOutput.'
derivation = BottomDerivation(elementNode, prefix)
copyShallow = elementNode.getCopyShallow()
solid.processElementNodeByGeometry(copyShallow, geometryOutput)
targetMatrix = matrix.getBranchMatrixSetElementNode(elementNode)
matrix.setElementNodeDictionaryMatrix(copyShallow, targetMatrix)
minimumZ = boolean_geometry.getMinimumZ(copyShallow.xmlObject)
copyShallow.parentNode.xmlObject.archivableObjects.remove(copyShallow.xmlObject)
lift = derivation.altitude - minimumZ
vertexes = matrix.getVertexes(geometryOutput)
for vertex in vertexes:
vertex.z += lift
return geometryOutput
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
'Get flipped paths.'
if len(loop) < 1:
return [[]]
derivation = BottomDerivation(elementNode, prefix)
targetMatrix = matrix.getBranchMatrixSetElementNode(elementNode)
transformedLoop = matrix.getTransformedVector3s(matrix.getIdentityTetragrid(targetMatrix.tetragrid), loop)
lift = derivation.altitude + derivation.getAdditionalPathLift() - euclidean.getBottomByPath(transformedLoop)
for point in loop:
point.z += lift
return [loop]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return BottomDerivation(elementNode, '')
def processElementNode(elementNode):
"Process the xml element."
processElementNodeByDerivation(None, elementNode)
def processElementNodeByDerivation(derivation, elementNode):
'Process the xml element by derivation.'
if derivation == None:
derivation = BottomDerivation(elementNode, '')
targets = evaluate.getElementNodesByKey(elementNode, 'target')
if len(targets) < 1:
print('Warning, processElementNode in bottom could not get targets for:')
print(elementNode)
return
for target in targets:
bottomElementNode(derivation, target)
class BottomDerivation(object):
"Class to hold bottom variables."
def __init__(self, elementNode, prefix):
'Set defaults.'
self.altitude = evaluate.getEvaluatedFloat(0.0, elementNode, prefix + 'altitude')
self.elementNode = elementNode
self.liftPath = evaluate.getEvaluatedBoolean(True, elementNode, prefix + 'liftPath')
def getAdditionalPathLift(self):
"Get path lift."
return 0.5 * setting.getLayerHeight(self.elementNode) * float(self.liftPath)

View File

@ -1,81 +0,0 @@
"""
Create inset.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import boolean_solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3index import Vector3Index
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import intercircle
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 80
def getManipulatedGeometryOutput(elementNode, geometryOutput, prefix):
'Get inset geometryOutput.'
derivation = InsetDerivation(elementNode, prefix)
if derivation.radius == 0.0:
return geometryOutput
halfLayerHeight = 0.5 * derivation.radius
importRadius = 0.5 * derivation.radius * setting.getImportCoarseness(elementNode)
loopLayers = solid.getLoopLayersSetCopy(elementNode, geometryOutput, importRadius, derivation.radius)
triangleAltitude = math.sqrt(0.75) * derivation.radius
loops = []
vertexes = []
for loopLayerIndex in xrange(1, len(loopLayers), 2):
loopLayer = loopLayers[loopLayerIndex]
loopLayer.loops[0] = intercircle.getLargestInsetLoopFromLoop(loopLayer.loops[0], triangleAltitude)
for loopLayerIndex in xrange(0, len(loopLayers), 2):
loopLayer = loopLayers[loopLayerIndex]
loopLists = [[solid.getLoopOrEmpty(loopLayerIndex - 2, loopLayers)]]
loopLists.append([solid.getLoopOrEmpty(loopLayerIndex - 1, loopLayers)])
loopLists.append([intercircle.getLargestInsetLoopFromLoop(loopLayer.loops[0], derivation.radius)])
if evaluate.getEvaluatedBoolean(True, elementNode, prefix + 'insetTop'):
loopLists.append([solid.getLoopOrEmpty(loopLayerIndex + 1, loopLayers)])
loopLists.append([solid.getLoopOrEmpty(loopLayerIndex + 2, loopLayers)])
largestLoop = euclidean.getLargestLoop(boolean_solid.getLoopsIntersection(importRadius, loopLists))
triangle_mesh.addVector3Loop(largestLoop, loops, vertexes, loopLayer.z)
if evaluate.getEvaluatedBoolean(False, elementNode, prefix + 'addExtraTopLayer') and len(loops) > 0:
topLoop = loops[-1]
vector3Loop = []
loops.append(vector3Loop)
z = topLoop[0].z + derivation.radius
for point in topLoop:
vector3Index = Vector3Index(len(vertexes), point.x, point.y, z)
vector3Loop.append(vector3Index)
vertexes.append(vector3Index)
return triangle_mesh.getMeldedPillarOutput(loops)
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get inset path."
derivation = InsetDerivation(elementNode, prefix)
return intercircle.getInsetLoopsFromVector3Loop(loop, derivation.radius)
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return OutsetDerivation(elementNode, prefix)
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByFunctionPair(elementNode, getManipulatedGeometryOutput, getManipulatedPaths)
class InsetDerivation(object):
"Class to hold inset variables."
def __init__(self, elementNode, prefix):
'Set defaults.'
self.radius = evaluate.getEvaluatedFloat(2.0 * setting.getEdgeWidth(elementNode), elementNode, prefix + 'radius')

View File

@ -1,73 +0,0 @@
"""
Create inset.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities.evaluate_elements import setting
from fabmetheus_utilities.geometry.geometry_utilities import boolean_solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities import euclidean
from fabmetheus_utilities import intercircle
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 80
def getManipulatedGeometryOutput(elementNode, geometryOutput, prefix):
'Get outset geometryOutput.'
derivation = OutsetDerivation(elementNode, prefix)
if derivation.radius == 0.0:
return geometryOutput
halfLayerHeight = 0.5 * derivation.radius
importRadius = 0.5 * derivation.radius * setting.getImportCoarseness(elementNode)
loopLayers = solid.getLoopLayersSetCopy(elementNode, geometryOutput, importRadius, derivation.radius)
if len(loopLayers) == 0:
return triangle_mesh.getMeldedPillarOutput([])
triangleAltitude = math.sqrt(0.75) * derivation.radius
loops = []
vertexes = []
for loopLayerIndex in xrange(1, len(loopLayers), 2):
loopLayer = loopLayers[loopLayerIndex]
loopLayer.loops[0] = intercircle.getLargestInsetLoopFromLoop(loopLayer.loops[0], triangleAltitude)
z = loopLayers[0].z - derivation.radius
for loopIndex in xrange(-2, len(loopLayers) + 2, 2):
loopLists = [[solid.getLoopOrEmpty(loopIndex - 2, loopLayers)]]
loopLists.append([solid.getLoopOrEmpty(loopIndex - 1, loopLayers)])
loopLists.append([intercircle.getLargestInsetLoopFromLoop(solid.getLoopOrEmpty(loopIndex, loopLayers), -derivation.radius)])
loopLists.append([solid.getLoopOrEmpty(loopIndex + 1, loopLayers)])
loopLists.append([solid.getLoopOrEmpty(loopIndex + 2, loopLayers)])
largestLoop = euclidean.getLargestLoop(boolean_solid.getLoopsUnion(importRadius, loopLists))
triangle_mesh.addVector3Loop(largestLoop, loops, vertexes, z)
z += derivation.radius
return triangle_mesh.getMeldedPillarOutput(loops)
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get outset path."
derivation = OutsetDerivation(elementNode, prefix)
return intercircle.getInsetLoopsFromVector3Loop(loop, -derivation.radius)
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return OutsetDerivation(elementNode, prefix)
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByFunctionPair(elementNode, getManipulatedGeometryOutput, getManipulatedPaths)
class OutsetDerivation(object):
"Class to hold outset variables."
def __init__(self, elementNode, prefix):
'Set defaults.'
self.radius = evaluate.getEvaluatedFloat(2.0 * setting.getEdgeWidth(elementNode), elementNode, prefix + 'radius')

View File

@ -1,114 +0,0 @@
"""
Equation for vertexes.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = -100
def equate(point, returnValue):
"Get equation for rectangular."
point.setToVector3(evaluate.getVector3ByDictionaryListValue(returnValue, point))
def equatePoints(elementNode, points, prefix, revolutions):
"Equate the points."
derivation = EquationDerivation(elementNode, prefix)
for equationResult in derivation.equationResults:
for point in points:
returnValue = equationResult.getReturnValue(point, revolutions)
if returnValue == None:
print('Warning, returnValue in alterVertexesByEquation in equation is None for:')
print(point)
print(elementNode)
else:
equationResult.equationFunction(point, returnValue)
def equateX(point, returnValue):
"Get equation for rectangular x."
point.x = returnValue
def equateY(point, returnValue):
"Get equation for rectangular y."
point.y = returnValue
def equateZ(point, returnValue):
"Get equation for rectangular z."
point.z = returnValue
def getManipulatedGeometryOutput(elementNode, geometryOutput, prefix):
"Get equated geometryOutput."
equatePoints(elementNode, matrix.getVertexes(geometryOutput), prefix, None)
return geometryOutput
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
"Get equated paths."
equatePoints(elementNode, loop, prefix, 0.0)
return [loop]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return EquationDerivation(elementNode, prefix)
class EquationDerivation(object):
"Class to hold equation variables."
def __init__(self, elementNode, prefix):
'Set defaults.'
self.equationResults = []
self.addEquationResult(elementNode, equate, prefix)
self.addEquationResult(elementNode, equateX, prefix)
self.addEquationResult(elementNode, equateY, prefix)
self.addEquationResult(elementNode, equateZ, prefix)
def addEquationResult(self, elementNode, equationFunction, prefix):
'Add equation result to equationResults.'
prefixedEquationName = prefix + equationFunction.__name__[ len('equate') : ].replace('Dot', '.').lower()
if prefixedEquationName in elementNode.attributes:
self.equationResults.append(EquationResult(elementNode, equationFunction, prefixedEquationName))
class EquationResult(object):
"Class to get equation results."
def __init__(self, elementNode, equationFunction, key):
"Initialize."
self.distance = 0.0
elementNode.xmlObject = evaluate.getEvaluatorSplitWords(elementNode.attributes[key])
self.equationFunction = equationFunction
self.function = evaluate.Function(elementNode)
self.points = []
def getReturnValue(self, point, revolutions):
"Get return value."
if self.function == None:
return point
self.function.localDictionary['azimuth'] = math.degrees(math.atan2(point.y, point.x))
if len(self.points) > 0:
self.distance += abs(point - self.points[-1])
self.function.localDictionary['distance'] = self.distance
self.function.localDictionary['radius'] = abs(point.dropAxis())
if revolutions != None:
if len( self.points ) > 0:
revolutions += 0.5 / math.pi * euclidean.getAngleAroundZAxisDifference(point, self.points[-1])
self.function.localDictionary['revolutions'] = revolutions
self.function.localDictionary['vertex'] = point
self.function.localDictionary['vertexes'] = self.points
self.function.localDictionary['vertexindex'] = len(self.points)
self.function.localDictionary['x'] = point.x
self.function.localDictionary['y'] = point.y
self.function.localDictionary['z'] = point.z
self.points.append(point)
return self.function.getReturnValueWithoutDeletion()

View File

@ -1,90 +0,0 @@
"""
Add material to support overhang or remove material at the overhang angle.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities.vector3 import Vector3
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 200
# http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=269576
# http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node159.html
# m.a00 = -2 * norm.x * norm.x + 1;
# m.a10 = -2 * norm.y * norm.x;
# m.a20 = -2 * norm.z * norm.x;
# m.a30 = 0;
# m.a01 = -2 * norm.x * norm.y;
# m.a11 = -2 * norm.y * norm.y + 1;
# m.a21 = -2 * norm.z * norm.y;
# m.a31 = 0;
# m.a02 = -2 * norm.x * norm.z;
# m.a12 = -2 * norm.y * norm.z;
# m.a22 = -2 * norm.z * norm.z + 1;
# m.a32 = 0;
# m.a03 = -2 * norm.x * d;
# m.a13 = -2 * norm.y * d;
# m.a23 = -2 * norm.z * d;
# m.a33 = 1;
# normal = unit_vector(normal[:3])
# M = numpy.identity(4)
# M[:3, :3] -= 2.0 * numpy.outer(normal, normal)
# M[:3, 3] = (2.0 * numpy.dot(point[:3], normal)) * normal
# return M
def flipPoints(elementNode, points, prefix):
'Flip the points.'
derivation = FlipDerivation(elementNode, prefix)
for point in points:
point.setToVector3(point - 2.0 * derivation.axis.dot(point - derivation.origin) * derivation.axis)
def getFlippedLoop(elementNode, loop, prefix):
'Get flipped loop.'
flipPoints(elementNode, loop, prefix)
if getShouldReverse(elementNode, prefix):
loop.reverse()
return loop
def getManipulatedGeometryOutput(elementNode, geometryOutput, prefix):
'Get equated geometryOutput.'
flipPoints(elementNode, matrix.getVertexes(geometryOutput), prefix)
return geometryOutput
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
'Get flipped paths.'
return [getFlippedLoop(elementNode, loop, prefix)]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return FlipDerivation(elementNode, prefix)
def getShouldReverse(elementNode, prefix):
'Determine if the loop should be reversed.'
return evaluate.getEvaluatedBoolean(True, elementNode, prefix + 'reverse')
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByFunctionPair(elementNode, getManipulatedGeometryOutput, getManipulatedPaths)
class FlipDerivation(object):
"Class to hold flip variables."
def __init__(self, elementNode, prefix):
'Set defaults.'
self.origin = evaluate.getVector3ByPrefix(Vector3(), elementNode, prefix + 'origin')
self.axis = evaluate.getVector3ByPrefix(Vector3(1.0, 0.0, 0.0), elementNode, prefix + 'axis').getNormalized()

View File

@ -1,46 +0,0 @@
"""
Add material to support overhang or remove material at the overhang angle.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_tools import face
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities.geometry.manipulation_shapes import flip
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
globalExecutionOrder = 200
def getManipulatedGeometryOutput(elementNode, geometryOutput, prefix):
'Get equated geometryOutput.'
flippedGeometryOutput = triangle_mesh.getGeometryOutputCopy(geometryOutput)
flip.flipPoints(elementNode, matrix.getVertexes(flippedGeometryOutput), prefix)
if flip.getShouldReverse(elementNode, prefix):
flippedFaces = face.getFaces(flippedGeometryOutput)
for flippedFace in flippedFaces:
flippedFace.vertexIndexes.reverse()
return {'union' : {'shapes' : [flippedGeometryOutput, geometryOutput]}}
def getManipulatedPaths(close, elementNode, loop, prefix, sideLength):
'Get flipped paths.'
return [loop + flip.getFlippedLoop(elementNode, euclidean.getPathCopy(loop), prefix)]
def getNewDerivation(elementNode, prefix, sideLength):
'Get new derivation.'
return evaluate.EmptyObject()
def processElementNode(elementNode):
'Process the xml element.'
solid.processElementNodeByFunctionPair(elementNode, getManipulatedGeometryOutput, getManipulatedPaths)

View File

@ -1,76 +0,0 @@
"""
Boolean geometry cube.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addCube(elementNode, faces, inradius, vertexes):
'Add cube by inradius.'
square = [
complex(-inradius.x, -inradius.y),
complex(inradius.x, -inradius.y),
complex(inradius.x, inradius.y),
complex(-inradius.x, inradius.y)]
bottomTopSquare = triangle_mesh.getAddIndexedLoops(square, vertexes, [-inradius.z, inradius.z])
triangle_mesh.addPillarByLoops(faces, bottomTopSquare)
def getGeometryOutput(elementNode, inradius):
'Get cube triangle mesh by inradius.'
faces = []
vertexes = []
addCube(elementNode, faces, inradius, vertexes)
return {'trianglemesh' : {'vertex' : vertexes, 'face' : faces}}
def getNewDerivation(elementNode):
'Get new derivation.'
return CubeDerivation(elementNode)
def processElementNode(elementNode):
'Process the xml element.'
evaluate.processArchivable(Cube, elementNode)
class Cube(triangle_mesh.TriangleMesh):
'A cube object.'
def addXMLSection(self, depth, output):
'Add the xml section for this object.'
pass
def createShape(self):
'Create the shape.'
addCube(self.elementNode, self.faces, self.inradius, self.vertexes)
def setToElementNode(self, elementNode):
'Set to elementNode.'
attributes = elementNode.attributes
self.elementNode = elementNode
self.inradius = CubeDerivation(elementNode).inradius
attributes['inradius.x'] = self.inradius.x
attributes['inradius.y'] = self.inradius.y
attributes['inradius.z'] = self.inradius.z
if 'inradius' in attributes:
del attributes['inradius']
self.createShape()
solid.processArchiveRemoveSolid(elementNode, self.getGeometryOutput())
class CubeDerivation(object):
"Class to hold cube variables."
def __init__(self, elementNode):
'Set defaults.'
self.inradius = evaluate.getVector3ByPrefixes(elementNode, ['demisize', 'inradius'], Vector3(1.0, 1.0, 1.0))
self.inradius = evaluate.getVector3ByMultiplierPrefix(elementNode, 2.0, 'size', self.inradius)

View File

@ -1,109 +0,0 @@
"""
Boolean geometry cylinder.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.creation import lineation
from fabmetheus_utilities.geometry.creation import solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities.geometry.solids import cube
from fabmetheus_utilities.geometry.solids import triangle_mesh
from fabmetheus_utilities.vector3 import Vector3
from fabmetheus_utilities import euclidean
import math
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def addCylinder(faces, inradius, sides, topOverBottom, vertexes):
'Add cylinder by inradius.'
polygonBottom = euclidean.getComplexPolygonByComplexRadius(complex(inradius.x, inradius.y), sides)
polygonTop = polygonBottom
if topOverBottom <= 0.0:
polygonTop = [complex()]
elif topOverBottom != 1.0:
polygonTop = euclidean.getComplexPathByMultiplier(topOverBottom, polygonTop)
bottomTopPolygon = [
triangle_mesh.getAddIndexedLoop(polygonBottom, vertexes, -inradius.z),
triangle_mesh.getAddIndexedLoop(polygonTop, vertexes, inradius.z)]
triangle_mesh.addPillarByLoops(faces, bottomTopPolygon)
def addCylinderOutputByEndStart(endZ, inradiusComplex, outputs, sides, start, topOverBottom=1.0):
'Add cylinder triangle mesh by endZ, inradius and start.'
inradius = Vector3(inradiusComplex.real, inradiusComplex.imag, 0.5 * abs(endZ - start.z))
cylinderOutput = getGeometryOutput(inradius, sides, topOverBottom)
vertexes = matrix.getVertexes(cylinderOutput)
if endZ < start.z:
for vertex in vertexes:
vertex.z = -vertex.z
translation = Vector3(start.x, start.y, inradius.z + min(start.z, endZ))
euclidean.translateVector3Path(vertexes, translation)
outputs.append(cylinderOutput)
def getGeometryOutput(inradius, sides, topOverBottom):
'Get cylinder triangle mesh by inradius.'
faces = []
vertexes = []
addCylinder(faces, inradius, sides, topOverBottom, vertexes)
return {'trianglemesh' : {'vertex' : vertexes, 'face' : faces}}
def getNewDerivation(elementNode):
'Get new derivation.'
return CylinderDerivation(elementNode)
def getTopOverBottom(angle, endZ, inradiusComplex, startZ):
'Get topOverBottom by angle in radians, endZ, inradius and start.'
return max(1.0 - abs(endZ - startZ) * math.tan(angle) / lineation.getRadiusAverage(inradiusComplex), 0.0)
def processElementNode(elementNode):
'Process the xml element.'
evaluate.processArchivable(Cylinder, elementNode)
class Cylinder( cube.Cube ):
'A cylinder object.'
def __init__(self):
'Add empty lists.'
cube.Cube.__init__(self)
def createShape(self):
'Create the shape.'
sides = evaluate.getSidesMinimumThreeBasedOnPrecision(self.elementNode, max(self.inradius.x, self.inradius.y))
if self.elementNode.getCascadeBoolean(False, 'radiusAreal'):
radiusArealizedMultiplier = euclidean.getRadiusArealizedMultiplier(sides)
self.inradius.x *= radiusArealizedMultiplier
self.inradius.y *= radiusArealizedMultiplier
addCylinder(self.faces, self.inradius, sides, self.topOverBottom, self.vertexes)
def setToElementNode(self, elementNode):
'Set to elementNode.'
attributes = elementNode.attributes
self.elementNode = elementNode
derivation = CylinderDerivation(elementNode)
self.inradius = derivation.inradius
self.topOverBottom = derivation.topOverBottom
if 'inradius' in attributes:
del attributes['inradius']
attributes['height'] = self.inradius.z + self.inradius.z
attributes['radius.x'] = self.inradius.x
attributes['radius.y'] = self.inradius.y
attributes['topOverBottom'] = self.topOverBottom
self.createShape()
solid.processArchiveRemoveSolid(elementNode, self.getGeometryOutput())
class CylinderDerivation(object):
"Class to hold cylinder variables."
def __init__(self, elementNode):
'Set defaults.'
self.inradius = evaluate.getVector3ByPrefixes(elementNode, ['demisize', 'inradius', 'radius'], Vector3(1.0, 1.0, 1.0))
self.inradius = evaluate.getVector3ByMultiplierPrefixes(elementNode, 2.0, ['diameter', 'size'], self.inradius)
self.inradius.z = 0.5 * evaluate.getEvaluatedFloat(self.inradius.z + self.inradius.z, elementNode, 'height')
self.topOverBottom = evaluate.getEvaluatedFloat(1.0, elementNode, 'topOverBottom')

View File

@ -1,41 +0,0 @@
"""
Boolean geometry difference of solids.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities import boolean_solid
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import group
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def convertElementNode(elementNode, geometryOutput):
"Convert the xml element to a difference xml element."
group.convertContainerElementNode(elementNode, geometryOutput, Difference())
def getNewDerivation(elementNode):
'Get new derivation.'
return evaluate.EmptyObject(elementNode)
def processElementNode(elementNode):
"Process the xml element."
evaluate.processArchivable(Difference, elementNode)
class Difference( boolean_solid.BooleanSolid ):
"A difference object."
def getLoopsFromObjectLoopsList(self, importRadius, visibleObjectLoopsList):
"Get loops from visible object loops list."
return self.getDifference(importRadius, visibleObjectLoopsList)
def getXMLLocalName(self):
"Get xml class name."
return self.__class__.__name__.lower()

View File

@ -1,80 +0,0 @@
"""
Boolean geometry group of solids.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_tools import dictionary
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.geometry_utilities import matrix
from fabmetheus_utilities import euclidean
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Art of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/02/05 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def convertContainerElementNode(elementNode, geometryOutput, xmlObject):
"Convert the xml element to a group xml element."
elementNode.linkObject(xmlObject)
matrix.getBranchMatrixSetElementNode(elementNode)
elementNode.getXMLProcessor().createChildNodes(geometryOutput['shapes'], elementNode)
def convertElementNode(elementNode, geometryOutput):
"Convert the xml element to a group xml element."
convertContainerElementNode(elementNode, geometryOutput, Group())
def getNewDerivation(elementNode):
'Get new derivation.'
return evaluate.EmptyObject(elementNode)
def processElementNode(elementNode):
"Process the xml element."
evaluate.processArchivable(Group, elementNode)
class Group(dictionary.Dictionary):
"A group."
def __init__(self):
"Add empty lists."
dictionary.Dictionary.__init__(self)
self.matrix4X4 = matrix.Matrix()
def addXMLInnerSection(self, depth, output):
"Add xml inner section for this object."
if self.matrix4X4 != None:
self.matrix4X4.addXML(depth, output)
self.addXMLSection(depth, output)
def addXMLSection(self, depth, output):
"Add the xml section for this object."
pass
def getLoops(self, importRadius, z):
"Get loops sliced through shape."
visibleObjects = evaluate.getVisibleObjects(self.archivableObjects)
loops = []
for visibleObject in visibleObjects:
loops += visibleObject.getLoops(importRadius, z)
return loops
def getMatrix4X4(self):
"Get the matrix4X4."
return self.matrix4X4
def getMatrixChainTetragrid(self):
"Get the matrix chain tetragrid."
return matrix.getTetragridTimesOther(self.elementNode.parentNode.xmlObject.getMatrixChainTetragrid(), self.matrix4X4.tetragrid)
def getVisible(self):
"Get visible."
return euclidean.getBooleanFromDictionary(True, self.getAttributes(), 'visible')
def setToElementNode(self, elementNode):
'Set to elementNode.'
self.elementNode = elementNode
elementNode.parentNode.xmlObject.archivableObjects.append(self)
matrix.getBranchMatrixSetElementNode(elementNode)

View File

@ -1,37 +0,0 @@
"""
Boolean geometry intersection of solids.
"""
from __future__ import absolute_import
from fabmetheus_utilities.geometry.geometry_utilities import evaluate
from fabmetheus_utilities.geometry.solids import difference
from fabmetheus_utilities.geometry.solids import group
__author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
__credits__ = 'Nophead <http://hydraraptor.blogspot.com/>\nArt of Illusion <http://www.artofillusion.org/>'
__date__ = '$Date: 2008/21/04 $'
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
def convertElementNode(elementNode, geometryOutput):
"Convert the xml element to an intersection xml element."
group.convertContainerElementNode(elementNode, geometryOutput, Intersection())
def getNewDerivation(elementNode):
'Get new derivation.'
return evaluate.EmptyObject(elementNode)
def processElementNode(elementNode):
"Process the xml element."
evaluate.processArchivable(Intersection, elementNode)
class Intersection(difference.Difference):
"An intersection object."
def getLoopsFromObjectLoopsList(self, importRadius, visibleObjectLoopsList):
"Get loops from visible object loops list."
return self.getIntersection(importRadius, visibleObjectLoopsList)

Some files were not shown because too many files have changed in this diff Show More