mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
330 lines
9.2 KiB
Python
330 lines
9.2 KiB
Python
r"""Utility module for easy manipultions of lookup tables.
|
|
This module is intended for use with by simple.py."""
|
|
#==============================================================================
|
|
#
|
|
# Program: ParaView
|
|
# Module: lookuptable.py
|
|
#
|
|
# Copyright (c) Kitware, Inc.
|
|
# All rights reserved.
|
|
# See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
|
|
#
|
|
# This software is distributed WITHOUT ANY WARRANTY; without even
|
|
# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
# PURPOSE. See the above copyright notice for more information.
|
|
#
|
|
#==============================================================================
|
|
|
|
import paraview.simple
|
|
import servermanager
|
|
import os
|
|
from math import sqrt
|
|
|
|
# -----------------------------------------------------------------------------
|
|
|
|
class _vtkPVLUTData:
|
|
"""
|
|
Internal container for ParaView lookup table data.
|
|
Don't use this directly. Use vtkPVLUTReader.
|
|
"""
|
|
def __init__(self):
|
|
self.Name=""
|
|
self.Space=""
|
|
self.Values=[]
|
|
self.Coords=[]
|
|
|
|
def SetName(self,aName):
|
|
self.Name=aName
|
|
|
|
def GetName(self):
|
|
return self.Name
|
|
|
|
def SetColorSpace(self,aSpace):
|
|
self.Space=aSpace
|
|
|
|
def GetColorSpace(self):
|
|
return self.Space
|
|
|
|
def SetRGBValues(self,aValues):
|
|
self.Values=aValues
|
|
|
|
def GetRGBValues(self):
|
|
return self.Values
|
|
|
|
def SetMapCoordinates(self,aCoords):
|
|
self.Coords=aCoords
|
|
# normalize the coordinates
|
|
# in preparation to map onto
|
|
# an arbitrary scalar range
|
|
nCoords = len(self.Coords)
|
|
minCoord = min(self.Coords)
|
|
maxCoord = max(self.Coords)
|
|
deltaCoord = maxCoord - minCoord
|
|
if (minCoord>=maxCoord):
|
|
print 'ERROR: in coordinate values'
|
|
return
|
|
i=0
|
|
while i<nCoords:
|
|
self.Coords[i] -= minCoord
|
|
self.Coords[i] /= deltaCoord
|
|
i+=1
|
|
return
|
|
|
|
def GetMapCoordinates(self):
|
|
return self.Coords;
|
|
|
|
def PrintSelf(self):
|
|
print self.Name
|
|
print self.Space
|
|
print self.Values
|
|
print self.Coords
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
|
|
class vtkPVLUTReader:
|
|
"""
|
|
Reader and container for ParaView's XML based lookup tables.
|
|
Once lookup tables are loaded you access them by name. When
|
|
accessing you must provide the array instance, which you may
|
|
get from a pvpython 'Source' type object.
|
|
|
|
This reader makes use of ParaView's XML LUT file format with
|
|
one exception - the XML document must be root'ed by an element
|
|
named "ColorMaps". Within the "ColorMaps" element an arbitrary
|
|
number of ParaView's "ColorMap" elements define LUT entries.
|
|
|
|
Usage:
|
|
# at the top of your script
|
|
# create the reader and load LUT's
|
|
lr = lookuptable.vtkPVLUTReader()
|
|
lr.Read('/path/to/luts.xml')
|
|
lr.Print()
|
|
|
|
# after you have a pvpython source object, get
|
|
# one of it's arrays.
|
|
srcObj = GetActiveSource()
|
|
array = srcObj.PointData.GetArray('arrayName')
|
|
|
|
# create a LUT for the array.
|
|
lut = lr.GetLUT(array,'lutName')
|
|
|
|
# set the active array and assign the LUT
|
|
srcObjRep = Show(srcObj)
|
|
srcObjRep.ColorArrayName = 'arrayName'
|
|
srcObjRep.LookupTable = lut
|
|
|
|
# finally render to display the result
|
|
Render()
|
|
|
|
File Format:
|
|
<ColorMaps>
|
|
...
|
|
<ColorMap name="LUTName" space="Lab,RGB,HSV" indexedLookup="true,false">
|
|
<Point x="val" o="val" r="val" g="val" b="val"/>
|
|
...
|
|
<Point x="val" o="val" r="val" g="val" b="val"/>
|
|
<NaN r="val" g="val" b="val"/>
|
|
</ColorMap>
|
|
...
|
|
<ColorMaps>
|
|
...
|
|
</ColorMap>
|
|
...
|
|
</ColorMaps>
|
|
"""
|
|
|
|
def __init__(self,ns=None):
|
|
self.LUTS={}
|
|
self.DefaultLUT=None
|
|
self.Globals=ns
|
|
baseDir=os.path.dirname(paraview.simple.__file__)
|
|
defaultLUTFile=os.path.join(baseDir,'ColorMaps.xml')
|
|
if (os.path.exists(defaultLUTFile)):
|
|
self.Read(defaultLUTFile)
|
|
else:
|
|
print 'WARNING: default LUTs not found at %s'%(defaultLUTFile)
|
|
return
|
|
|
|
def Clear(self):
|
|
"""
|
|
Clear internal data structures.
|
|
"""
|
|
self.LUTS={}
|
|
self.DefaultLUT=None
|
|
return
|
|
|
|
def Read(self, aFileName):
|
|
"""
|
|
Read in the LUT's defined in the named file. Each
|
|
call to read extends the internal list of LUTs.
|
|
"""
|
|
parser=servermanager.vtkPVXMLParser()
|
|
parser.SetFileName(aFileName)
|
|
if (not parser.Parse()):
|
|
print 'ERROR: parsing lut file %s'%(aFileName)
|
|
return
|
|
root=parser.GetRootElement()
|
|
if root.GetName()!='ColorMaps':
|
|
print 'ERROR: parsing LUT file %s'%(aFileName)
|
|
print 'ERROR: root element must be <ColorMaps>'
|
|
return
|
|
nElems=root.GetNumberOfNestedElements()
|
|
i=0
|
|
nFound=0
|
|
while (i<nElems):
|
|
cmapElem=root.GetNestedElement(i)
|
|
if (cmapElem.GetName()=='ColorMap'):
|
|
nFound+=1
|
|
|
|
lut=_vtkPVLUTData()
|
|
lut.SetName(cmapElem.GetAttribute('name'))
|
|
lut.SetColorSpace(cmapElem.GetAttribute('space'))
|
|
|
|
coords=[]
|
|
values=[]
|
|
nRGB=cmapElem.GetNumberOfNestedElements()
|
|
j=0
|
|
while (j<nRGB):
|
|
rgbElem=cmapElem.GetNestedElement(j)
|
|
if (rgbElem.GetName()=='Point'):
|
|
coord=float(rgbElem.GetAttribute('x'))
|
|
coords.append(coord)
|
|
val=[float(rgbElem.GetAttribute('r')),
|
|
float(rgbElem.GetAttribute('g')),
|
|
float(rgbElem.GetAttribute('b'))]
|
|
values.append(val)
|
|
j=j+1
|
|
|
|
lut.SetMapCoordinates(coords)
|
|
lut.SetRGBValues(values)
|
|
#lut.PrintSelf()
|
|
|
|
self.LUTS[lut.GetName()]=lut
|
|
i=i+1
|
|
|
|
if nFound==0:
|
|
print 'ERROR: No ColorMaps were found in %s'%(aFileName)
|
|
else:
|
|
if self.DefaultLUT is None:
|
|
names=self.LUTS.keys()
|
|
if len(names)>0:
|
|
self.DefaultLUT=names[0]
|
|
|
|
return nFound
|
|
|
|
def GetLUT(self,aArray,aLutName,aRangeOveride=[]):
|
|
"""
|
|
Given an array and lookup table name assign the LUT
|
|
to the given array and return the LUT. If aRangeOveride
|
|
is specified then LUT will be mapped through that
|
|
range rather than the array's actual range.
|
|
"""
|
|
try:
|
|
self.LUTS[aLutName]
|
|
except KeyError:
|
|
if self.DefaultLUT is not None:
|
|
print 'ERROR: No LUT named %s using %s'%(aLutName,self.DefaultLUT)
|
|
aLutName = self.DefaultLUT
|
|
else:
|
|
print 'ERROR: No LUT named %s and no default available.'%(aLutName)
|
|
return None
|
|
range = self.__GetRange(aArray,aRangeOveride)
|
|
return self.__GetLookupTableForArray(aArray,
|
|
RGBPoints=self.__MapRGB(aLutName,range),
|
|
ColorSpace=self.__GetColorSpace(aLutName),
|
|
VectorMode='Magnitude',
|
|
ScalarRangeInitialized=1.0)
|
|
|
|
def GetLUTNames(self):
|
|
"""
|
|
Return a list of the currently available LUT's names.
|
|
"""
|
|
return sorted(self.LUTS.iterkeys(),cmp=lambda x,y: cmp(x.lower(), y.lower()))
|
|
|
|
def Print(self):
|
|
"""
|
|
Print the available list of LUT's.
|
|
"""
|
|
names=""
|
|
i=0
|
|
for k in sorted(self.LUTS.iterkeys(),cmp=lambda x,y: cmp(x.lower(), y.lower())):
|
|
lut=self.LUTS[k]
|
|
names+=lut.GetName()
|
|
names+=", "
|
|
if ((i%6)==5):
|
|
names+="\n"
|
|
i+=1
|
|
print names
|
|
return
|
|
# end of public interface
|
|
|
|
def __GetColorSpace(self,aName):
|
|
"""
|
|
Return the color space from the lookup table object.
|
|
"""
|
|
return self.LUTS[aName].GetColorSpace()
|
|
|
|
|
|
def __GetRGB(self,aName):
|
|
"""
|
|
Return the rgb values for the named lut
|
|
"""
|
|
return self.LUTS[aName]
|
|
|
|
def __MapRGB(self,aName,aRange):
|
|
"""
|
|
Map the rgb values onto a scalar range
|
|
results are an array of [x r g b] values
|
|
"""
|
|
colors=self.LUTS[aName].GetRGBValues()
|
|
mapCoords=self.LUTS[aName].GetMapCoordinates()
|
|
nColors=len(colors)
|
|
coord0=float(aRange[0])
|
|
coordDelta=float(aRange[1])-float(aRange[0])
|
|
mappedColors=[]
|
|
i=0
|
|
while(i<nColors):
|
|
x=coord0+coordDelta*mapCoords[i]
|
|
val=[x]+colors[i]
|
|
mappedColors+=val
|
|
i=i+1
|
|
return mappedColors
|
|
|
|
def __GetRange(self,aArray,aRangeOveride):
|
|
"""
|
|
Get the range from an array proxy object or if
|
|
an overide is provided use that.
|
|
"""
|
|
nComps = aArray.GetNumberOfComponents()
|
|
range = [0.0, 1.0]
|
|
if (len(aRangeOveride) == 0):
|
|
if (nComps == 1):
|
|
range = aArray.GetRange()
|
|
else:
|
|
# TODO - this could be larger than the range of the magnitude aArray
|
|
rx = aArray.GetRange(0)
|
|
ry = aArray.GetRange(1)
|
|
rz = aArray.GetRange(2)
|
|
range = [0.0,
|
|
sqrt(rx[1]*rx[1]+ry[1]*ry[1]+rz[1]*rz[1])]
|
|
else:
|
|
range = aRangeOveride
|
|
return range
|
|
|
|
def __GetLookupTableForArray(self,aArray,**kwargs):
|
|
"""
|
|
Set the lookup table for the given array and assign
|
|
the named properties.
|
|
"""
|
|
proxyName='%d.%s.PVLookupTable'%(aArray.GetNumberOfComponents(),aArray.GetName())
|
|
lut = servermanager.ProxyManager().GetProxy('lookup_tables',proxyName)
|
|
if not lut:
|
|
lut = servermanager.rendering.PVLookupTable(ColorSpace="HSV",RGBPoints=[0,0,0,1, 1,1,0,0])
|
|
servermanager.Register(lut, registrationName=proxyName)
|
|
for arg in kwargs.keys():
|
|
if not hasattr(lut, arg):
|
|
raise AttributeError("LUT has no property %s"%(arg))
|
|
setattr(lut,arg,kwargs[arg])
|
|
return lut
|