From 003096808054f3387a732202f6a36370b358134e Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Tue, 25 Jan 2011 11:10:07 -0800 Subject: [PATCH 01/52] Build things for disney version --- Makefile | 13 +++++++++++++ SConstruct | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..a4ccf13a --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +#!/usr/bin/env make +#prefix ?= $(CURDIR)/$(shell uname)-$(shell fa.arch -r)-$(shell uname -m)-optimize +prefix ?= $(CURDIR)/$(shell uname)-$(shell fa.arch -r)-$(shell uname -m) +DESTDIR = + +install: + @echo "Installing $(prefix)" + scons --prefix="$(DESTDIR)$(prefix)" #"$(DESTDIR)$(prefix)" + +clean: + scons -c --prefix="$(DESTDIR)$(prefix)" #"$(DESTDIR)$(prefix)" + +cleanall: clean diff --git a/SConstruct b/SConstruct index dad5c9eb..dfd4f76f 100644 --- a/SConstruct +++ b/SConstruct @@ -60,7 +60,7 @@ if env["mac"]==True: #env.Append(LINKFLAGS=["-m32"]) if env["TYPE"]=="optimize": - env.Append(CXXFLAGS="-fPIC -DNDEBUG -O3 -fno-strict-aliasing -Wall -Werror -Wstrict-aliasing=0 -mfpmath=sse -msse3".split()) + env.Append(CXXFLAGS="-fPIC -DNDEBUG -O3 -fno-strict-aliasing -Wall -Wstrict-aliasing=0 -mfpmath=sse -msse3".split()) if env["TYPE"]=="profile": env.Append(CXXFLAGS="-fPIC -fno-strict-aliasing -DNDEBUG -g -fno-omit-frame-pointer -O3 -Wall -Werror -Wstrict-aliasing=0 -mfpmath=sse -msse3".split()) elif env["TYPE"]=="debug": From a3630282bb015d3dd97a199d8fd9b2789d0896f0 Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Tue, 25 Jan 2011 11:18:13 -0800 Subject: [PATCH 02/52] build prefixes --- Makefile | 1 + src/doc/SConscript | 2 +- src/lib/SConscript | 4 ++-- src/tests/SConscript | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index a4ccf13a..dd7bbc49 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ DESTDIR = install: @echo "Installing $(prefix)" scons --prefix="$(DESTDIR)$(prefix)" #"$(DESTDIR)$(prefix)" + echo "bin\nlib64\ninclude\nshare" > ${DESTDIR}${prefix}/.release.partio clean: scons -c --prefix="$(DESTDIR)$(prefix)" #"$(DESTDIR)$(prefix)" diff --git a/src/doc/SConscript b/src/doc/SConscript index 89e0b7de..839850bc 100644 --- a/src/doc/SConscript +++ b/src/doc/SConscript @@ -35,7 +35,7 @@ Import('env variant_build_abs variant_install_abs GetInstallPath') -docTarget=variant_install_abs+'/doc/Partio' +docTarget=variant_install_abs+'/share/doc/Partio' headers=['#src/lib/Partio.h'] # Build doxygen if Doxyfile or headers change index=env.Command('#src/doc/doc/html/index.html', # only target file known in advance diff --git a/src/lib/SConscript b/src/lib/SConscript index 82d7b029..6ea27280 100644 --- a/src/lib/SConscript +++ b/src/lib/SConscript @@ -60,13 +60,13 @@ foo=Dir(".").abspath+"../../include" env.Install(variant_build_abs+"/include","Partio.h") env.Install(variant_build_abs+"/include","PartioIterator.h") env.Install(variant_build_abs+"/include","PartioAttribute.h") -env.Install(variant_build_abs+"/lib",lib) +env.Install(variant_build_abs+"/lib64",lib) core_targets = [ env.Install(variant_install_abs+"/include","Partio.h"), env.Install(variant_install_abs+"/include","PartioIterator.h"), env.Install(variant_install_abs+"/include","PartioAttribute.h"), - env.Install(variant_install_abs+"/lib",lib) + env.Install(variant_install_abs+"/lib64",lib) ] diff --git a/src/tests/SConscript b/src/tests/SConscript index 5af0d35a..49b10a3a 100644 --- a/src/tests/SConscript +++ b/src/tests/SConscript @@ -49,7 +49,7 @@ for i in range(len(files)): file=files[i] target=targets[i] prog=envtests.Program(target,[file]) - envtests.Install("../../tests",prog) + envtests.Install("../../share/tests",prog) test_targets.append(envtests.Install(variant_install_abs+"/tests",prog)) envtests.Alias('test', test_targets) From 2969884ab9a14147bb3a62fbb0c831af9a61521e Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Tue, 25 Jan 2011 11:19:59 -0800 Subject: [PATCH 03/52] Fix release stuff some more --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dd7bbc49..90fd7f60 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,10 @@ DESTDIR = install: @echo "Installing $(prefix)" scons --prefix="$(DESTDIR)$(prefix)" #"$(DESTDIR)$(prefix)" - echo "bin\nlib64\ninclude\nshare" > ${DESTDIR}${prefix}/.release.partio + echo "bin" > ${DESTDIR}${prefix}/.release.partio + echo "lib64" >> ${DESTDIR}${prefix}/.release.partio + echo "share" >> ${DESTDIR}${prefix}/.release.partio + echo "include" >> ${DESTDIR}${prefix}/.release.partio clean: scons -c --prefix="$(DESTDIR)$(prefix)" #"$(DESTDIR)$(prefix)" From f05927e17d6f52e5cf626c9a37cd4e415e57f204 Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Mon, 7 Feb 2011 10:47:54 -0800 Subject: [PATCH 04/52] more disney specific build fun lib64 --- src/py/SConscript | 6 +++--- src/tests/SConscript | 2 +- src/tools/SConscript | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/py/SConscript b/src/py/SConscript index 307458dd..5f9506c4 100644 --- a/src/py/SConscript +++ b/src/py/SConscript @@ -35,12 +35,12 @@ import sys python_ver = sys.version[:3] python_inc = 'include/python%s' % python_ver -python_mod = 'lib/python%s/site-packages' % python_ver +python_mod = 'lib64/python%s/site-packages' % python_ver Import('env variant_build_abs variant_install_abs') envpy=env.Clone(CPPPATH=[variant_build_abs+"/include"] - ,LIBPATH="%s/lib"%variant_build_abs + ,LIBPATH="%s/lib64"%variant_build_abs ,LIBS=["partio"]) @@ -50,7 +50,7 @@ pythonDir="/usr" envpy.Append(CXXFLAGS=["-Wno-format"]) envpy.Append(CPPPATH=[pythonDir+"/include/python%s" % python_ver ], - LIBPATH=["%s/lib"%variant_build_abs], + LIBPATH=["%s/lib64"%variant_build_abs], LIBS=["partio"]) envpy.Append(SWIGFLAGS=['-c++','-python','-Wall']) diff --git a/src/tests/SConscript b/src/tests/SConscript index 49b10a3a..c026db71 100644 --- a/src/tests/SConscript +++ b/src/tests/SConscript @@ -34,7 +34,7 @@ import os Import('env variant_build_abs variant_install_abs') envtests=env.Clone(CPPPATH=[variant_build_abs+"/include"] - ,LIBPATH=["%s/lib"%variant_build_abs] + ,LIBPATH=["%s/lib64"%variant_build_abs] ,LIBS=["partio","z"]) # Find all .cpp's and make them into programs with same names as cpp diff --git a/src/tools/SConscript b/src/tools/SConscript index a1c1bd5f..49db3be7 100644 --- a/src/tools/SConscript +++ b/src/tools/SConscript @@ -34,7 +34,7 @@ import os Import('env variant_build_abs variant_install_abs') envtools=env.Clone(CPPPATH=[variant_build_abs+"/include"] - ,LIBPATH="%s/lib"%variant_build_abs + ,LIBPATH="%s/lib64"%variant_build_abs ,LIBS=["partio","z"]) # Find all .cpp's and make them into programs with same names as cpp From 60d7be2565ebc7b116b2f0a9010b6d8dd771517d Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Wed, 9 Mar 2011 15:41:46 -0800 Subject: [PATCH 05/52] adding stuff --- .workonrc.products | 1 + 1 file changed, 1 insertion(+) create mode 100644 .workonrc.products diff --git a/.workonrc.products b/.workonrc.products new file mode 100644 index 00000000..68440a06 --- /dev/null +++ b/.workonrc.products @@ -0,0 +1 @@ +partio From a1da5942e30aa89255ace4ec56774cf3b39b65c3 Mon Sep 17 00:00:00 2001 From: Mark McLaughlin Date: Wed, 25 Jan 2012 15:50:23 -0800 Subject: [PATCH 06/52] Added support for CXX and CXXFLAGS defined in the environment. Signed-off-by: Mark McLaughlin --- Makefile | 4 +++- SConstruct | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 90fd7f60..4535d516 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,12 @@ #prefix ?= $(CURDIR)/$(shell uname)-$(shell fa.arch -r)-$(shell uname -m)-optimize prefix ?= $(CURDIR)/$(shell uname)-$(shell fa.arch -r)-$(shell uname -m) DESTDIR = +CXX ?= g++ +CXXFLAGS ?= install: @echo "Installing $(prefix)" - scons --prefix="$(DESTDIR)$(prefix)" #"$(DESTDIR)$(prefix)" + scons --prefix="$(DESTDIR)$(prefix)" CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) #"$(DESTDIR)$(prefix)" echo "bin" > ${DESTDIR}${prefix}/.release.partio echo "lib64" >> ${DESTDIR}${prefix}/.release.partio echo "share" >> ${DESTDIR}${prefix}/.release.partio diff --git a/SConstruct b/SConstruct index dfd4f76f..42f07eee 100644 --- a/SConstruct +++ b/SConstruct @@ -5,6 +5,7 @@ def kernel_version(): return os.popen("uname -r").read().strip().split('-')[0] default_cxx="g++" +default_cxxflags="" options=Variables("SConstruct.options") @@ -14,6 +15,7 @@ arch = platform.machine() options.AddVariables( ('CXX','C++ compiler',default_cxx), + ('CXXFLAGS','C++ compiler flags',default_cxxflags), ('mac','Is a mac', uos == 'Darwin'), EnumVariable("TYPE", "Type of build (e.g. optimize,debug)", @@ -60,9 +62,9 @@ if env["mac"]==True: #env.Append(LINKFLAGS=["-m32"]) if env["TYPE"]=="optimize": - env.Append(CXXFLAGS="-fPIC -DNDEBUG -O3 -fno-strict-aliasing -Wall -Wstrict-aliasing=0 -mfpmath=sse -msse3".split()) + env.Append(CXXFLAGS=" -fPIC -DNDEBUG -O3 -fno-strict-aliasing -Wall -Wstrict-aliasing=0 -mfpmath=sse -msse3".split()) if env["TYPE"]=="profile": - env.Append(CXXFLAGS="-fPIC -fno-strict-aliasing -DNDEBUG -g -fno-omit-frame-pointer -O3 -Wall -Werror -Wstrict-aliasing=0 -mfpmath=sse -msse3".split()) + env.Append(CXXFLAGS=" -fPIC -fno-strict-aliasing -DNDEBUG -g -fno-omit-frame-pointer -O3 -Wall -Werror -Wstrict-aliasing=0 -mfpmath=sse -msse3".split()) elif env["TYPE"]=="debug": env.Append(CXXFLAGS=" -fPIC -g -Wall -Werror -Wstrict-aliasing=0") From 80481d21c3b189cccb7cd12fa5c8aca6245df3a0 Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Tue, 21 Feb 2012 11:18:32 -0800 Subject: [PATCH 07/52] add .itbl and .atbl as synonymns for bgeo for instance table --- src/lib/io/ParticleIO.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/io/ParticleIO.cpp b/src/lib/io/ParticleIO.cpp index 2ca08c07..caa22f94 100644 --- a/src/lib/io/ParticleIO.cpp +++ b/src/lib/io/ParticleIO.cpp @@ -56,6 +56,8 @@ readers() data["pdb64"]=readPDB64; data["pda"]=readPDA; data["ptc"]=readPTC; + data["itbl"]=readBGEO; + data["atbl"]=readBGEO; } return data; } @@ -73,6 +75,8 @@ writers() data["pdb64"]=writePDB64; data["pda"]=writePDA; data["ptc"]=writePTC; + data["itbl"]=writeBGEO; + data["atbl"]=writeBGEO; } return data; } From 579b3e3066acf08bd91cfb81863c9d198544ee4d Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Fri, 20 Apr 2012 10:15:11 -0700 Subject: [PATCH 08/52] Support hclassic and bhclassic --- src/lib/io/ParticleIO.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/io/ParticleIO.cpp b/src/lib/io/ParticleIO.cpp index caa22f94..9c7164af 100644 --- a/src/lib/io/ParticleIO.cpp +++ b/src/lib/io/ParticleIO.cpp @@ -50,7 +50,9 @@ readers() static bool initialized=false; if(!initialized){ data["bgeo"]=readBGEO; + data["bhclassic"]=readBGEO; data["geo"]=readGEO; + data["hclassic"]=readGEO; data["pdb"]=readPDB; data["pdb32"]=readPDB32; data["pdb64"]=readPDB64; From 680db11cd70858f17771ed458f69281e2dd2ccdc Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Tue, 22 May 2012 13:31:20 -0700 Subject: [PATCH 09/52] Fixes bug where empty particle set will crash on findNPoints() and also add ptf support Fixes Bug #25741 Fixes Bug #25742 --- src/lib/core/KdTree.h | 9 ++++++--- src/lib/io/ParticleIO.cpp | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/lib/core/KdTree.h b/src/lib/core/KdTree.h index b4d50cc1..be012d9e 100644 --- a/src/lib/core/KdTree.h +++ b/src/lib/core/KdTree.h @@ -34,6 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #ifndef KdTree_h #define KdTree_h +#include namespace Partio { @@ -284,8 +285,10 @@ void KdTree::setPoints(const float* p, int n) } else _bbox.clear(); // assign sequential ids - _ids.reserve(n); - while ((int)_ids.size() < n) _ids.push_back(_ids.size()); + _ids.resize(n); + __gnu_cxx::iota(_ids.begin(), _ids.end(), 0); +// _ids.reserve(n); +// while ((int)_ids.size() < n) _ids.push_back(_ids.size()); _sorted = 0; } @@ -348,7 +351,7 @@ int KdTree::findNPoints(uint64_t *result, float *distanceSquared, float *fina { float radius_squared=maxRadius*maxRadius; - if (!size() || !_sorted || nPoints<1) return radius_squared; + if (!size() || !_sorted || nPoints<1) return 0; NearestQuery query(result,distanceSquared,p,nPoints,radius_squared); findNPoints(query,0,size(),0); diff --git a/src/lib/io/ParticleIO.cpp b/src/lib/io/ParticleIO.cpp index 9c7164af..bb50dc02 100644 --- a/src/lib/io/ParticleIO.cpp +++ b/src/lib/io/ParticleIO.cpp @@ -58,6 +58,7 @@ readers() data["pdb64"]=readPDB64; data["pda"]=readPDA; data["ptc"]=readPTC; + data["ptf"]=readPTC; data["itbl"]=readBGEO; data["atbl"]=readBGEO; } @@ -77,6 +78,7 @@ writers() data["pdb64"]=writePDB64; data["pda"]=writePDA; data["ptc"]=writePTC; + data["ptf"]=writePTC; data["itbl"]=writeBGEO; data["atbl"]=writeBGEO; } From 21ebb69fbb60e2321154670a00638f8f78fcd9be Mon Sep 17 00:00:00 2001 From: Mark McLaughlin Date: Thu, 28 Feb 2013 10:55:32 -0800 Subject: [PATCH 10/52] Updated scons scripts to put tests in tests/partio directory. Signed-off-by: Mark McLaughlin --- Makefile | 12 ++++++------ src/doc/SConscript | 2 +- src/tests/SConscript | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 4535d516..84b72f64 100644 --- a/Makefile +++ b/Makefile @@ -7,13 +7,13 @@ CXXFLAGS ?= install: @echo "Installing $(prefix)" - scons --prefix="$(DESTDIR)$(prefix)" CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) #"$(DESTDIR)$(prefix)" - echo "bin" > ${DESTDIR}${prefix}/.release.partio - echo "lib64" >> ${DESTDIR}${prefix}/.release.partio - echo "share" >> ${DESTDIR}${prefix}/.release.partio - echo "include" >> ${DESTDIR}${prefix}/.release.partio + scons --prefix="$(DESTDIR)$(prefix)" CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) + #echo "bin" > ${DESTDIR}${prefix}/.release.partio + #echo "lib64" >> ${DESTDIR}${prefix}/.release.partio + #echo "share" >> ${DESTDIR}${prefix}/.release.partio + #echo "include" >> ${DESTDIR}${prefix}/.release.partio clean: - scons -c --prefix="$(DESTDIR)$(prefix)" #"$(DESTDIR)$(prefix)" + scons -c --prefix="$(DESTDIR)$(prefix)" cleanall: clean diff --git a/src/doc/SConscript b/src/doc/SConscript index 0154e898..223cfc3a 100644 --- a/src/doc/SConscript +++ b/src/doc/SConscript @@ -35,7 +35,7 @@ Import('env variant_build_abs variant_install_abs GetInstallPath') -docTarget=variant_install_abs+'/share/doc/Partio' +docTarget=variant_install_abs+'/share/doc/partio' headers=['#src/lib/Partio.h'] foo=env.Command("#src/doc/Doxyfile", ["#src/doc/Doxyfile.in"]+headers, diff --git a/src/tests/SConscript b/src/tests/SConscript index c026db71..2383e6cf 100644 --- a/src/tests/SConscript +++ b/src/tests/SConscript @@ -49,7 +49,7 @@ for i in range(len(files)): file=files[i] target=targets[i] prog=envtests.Program(target,[file]) - envtests.Install("../../share/tests",prog) - test_targets.append(envtests.Install(variant_install_abs+"/tests",prog)) + envtests.Install("../../share/tests/partio",prog) + test_targets.append(envtests.Install(variant_install_abs+"/tests/partio",prog)) envtests.Alias('test', test_targets) From 0f4612273aa56311711cf2e6d13bc0ea8f910a82 Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Fri, 1 Mar 2013 14:36:07 -0800 Subject: [PATCH 11/52] build: tests go in share/test/partio --- src/tests/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/SConscript b/src/tests/SConscript index 2383e6cf..38a8def3 100644 --- a/src/tests/SConscript +++ b/src/tests/SConscript @@ -49,7 +49,7 @@ for i in range(len(files)): file=files[i] target=targets[i] prog=envtests.Program(target,[file]) - envtests.Install("../../share/tests/partio",prog) + envtests.Install("../../share/test/partio",prog) test_targets.append(envtests.Install(variant_install_abs+"/tests/partio",prog)) envtests.Alias('test', test_targets) From 994ec9fd7ff0e18f776c1f2db041d8d7e195a146 Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Mon, 24 Jun 2013 15:13:00 -0700 Subject: [PATCH 12/52] Fix destructor warning in python interface --- src/py/partio.i | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/py/partio.i b/src/py/partio.i index 75429676..042f9334 100644 --- a/src/py/partio.i +++ b/src/py/partio.i @@ -40,6 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. %{ #include +#include namespace Partio{ typedef uint64_t ParticleIndex; } @@ -154,6 +155,13 @@ class ParticlesData:public ParticlesInfo }; +%rename(ParticleIteratorFalse) ParticleIterator; +%rename(ParticleIteratorTrue) ParticleIterator; +class ParticleIterator +{}; +class ParticleIterator +{}; + %unrefobject ParticlesDataMutable "$this->release();" %feature("autodoc"); %feature("docstring","A writer for a set of particles."); From 1db858b5c79c346e95c7b8e776890901be576981 Mon Sep 17 00:00:00 2001 From: Mark McLaughlin Date: Thu, 10 Oct 2013 16:37:17 -0700 Subject: [PATCH 13/52] Updated for Maya 2014 Python 2.7. Signed-off-by: Mark McLaughlin --- src/py/SConscript | 3 +-- src/py/example/circle.py | 2 +- src/py/example/listAttr.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/py/SConscript b/src/py/SConscript index 5f9506c4..ab612524 100644 --- a/src/py/SConscript +++ b/src/py/SConscript @@ -44,8 +44,7 @@ envpy=env.Clone(CPPPATH=[variant_build_abs+"/include"] ,LIBS=["partio"]) -pythonDir="/usr" -#pythonDir=os.environ["RP_python2"] +pythonDir=sys.prefix envpy.Append(CXXFLAGS=["-Wno-format"]) envpy.Append(CPPPATH=[pythonDir+"/include/python%s" % python_ver diff --git a/src/py/example/circle.py b/src/py/example/circle.py index 7ff06db3..986c0378 100644 --- a/src/py/example/circle.py +++ b/src/py/example/circle.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # PARTIO SOFTWARE # Copyright 2010 Disney Enterprises, Inc. All rights reserved diff --git a/src/py/example/listAttr.py b/src/py/example/listAttr.py index 4d4cc4b1..f21e5279 100644 --- a/src/py/example/listAttr.py +++ b/src/py/example/listAttr.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # PARTIO SOFTWARE # Copyright 2010 Disney Enterprises, Inc. All rights reserved From 271f4b4a3dcb2feccf0489a70c768b54749a0b4f Mon Sep 17 00:00:00 2001 From: Lawrence Chai Date: Wed, 12 Mar 2014 18:05:09 -0700 Subject: [PATCH 14/52] install partio.i --- src/py/SConscript | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/py/SConscript b/src/py/SConscript index ab612524..bfb7b680 100644 --- a/src/py/SConscript +++ b/src/py/SConscript @@ -64,7 +64,8 @@ dp1=envpy.InstallAs(variant_install_abs+"/%s/_partio.so" % python_mod,lib) dp2=envpy.InstallAs(variant_install_abs+"/%s/partio.py" % python_mod,"partio.py") envpy.Depends(dp1,dp2) -envpy.Alias('python', [dp1,dp2]) +dp3=envpy.Install(variant_install_abs+"/share/swig","partio.i") +envpy.Alias('python', [dp1,dp2,dp3]) # Find all .cpp's and make them into programs with same names as cpp #filter={"partview.cpp":0} # don't compile this, it requires better env From c7027073a52f620f51c1207a9f091134a4deebd1 Mon Sep 17 00:00:00 2001 From: Lawrence Chai Date: Wed, 2 Apr 2014 13:14:49 -0700 Subject: [PATCH 15/52] fixed indexed string error reporting --- src/lib/io/BGEO.cpp | 8 +++++--- src/lib/io/GEO.cpp | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/lib/io/BGEO.cpp b/src/lib/io/BGEO.cpp index 23154d25..98b6fa7d 100644 --- a/src/lib/io/BGEO.cpp +++ b/src/lib/io/BGEO.cpp @@ -142,9 +142,11 @@ ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly) char* indexName=new char[indexNameLength+1];; input->read(indexName,indexNameLength); indexName[indexNameLength]=0; - int id=simple->registerIndexedStr(attribute,indexName); - if(id != ii){ - std::cerr<<"Partio: error on read, expected registeerIndexStr to return index "<registerIndexedStr(attribute,indexName); + if(id != ii){ + std::cerr<<"Partio: error on read, expected registerIndexStr to return index "<>indexName; indexName=scanString(*input); //std::cerr<<"Partio: index "<registerIndexedStr(attribute,indexName.c_str()); - if(id != j){ - cerr<<"Partio: error on read, expected registeerIndexStr to return index "<registerIndexedStr(attribute,indexName.c_str()); + if(id != j){ + cerr<<"Partio: error on read, expected registerIndexStr to return index "< Date: Mon, 9 Jun 2014 16:43:01 -0700 Subject: [PATCH 16/52] added verbose option --- src/lib/Partio.h | 6 +++--- src/lib/core/ParticleCaching.cpp | 4 ++-- src/lib/io/BGEO.cpp | 4 ++-- src/lib/io/BIN.cpp | 4 ++-- src/lib/io/GEO.cpp | 4 ++-- src/lib/io/MC.cpp | 4 ++-- src/lib/io/PDA.cpp | 4 ++-- src/lib/io/PDB.cpp | 20 ++++++++++---------- src/lib/io/PDC.cpp | 4 ++-- src/lib/io/PRT.cpp | 4 ++-- src/lib/io/PTC.cpp | 4 ++-- src/lib/io/PTS.cpp | 4 ++-- src/lib/io/ParticleIO.cpp | 10 +++++----- src/lib/io/readers.h | 24 ++++++++++++------------ 14 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/lib/Partio.h b/src/lib/Partio.h index b715835f..a25d5eb9 100644 --- a/src/lib/Partio.h +++ b/src/lib/Partio.h @@ -231,11 +231,11 @@ ParticlesDataMutable* createInterleave(); //! Provides read/write access to a particle set stored in a file //! freed with p->release() -ParticlesDataMutable* read(const char* filename); +ParticlesDataMutable* read(const char* filename,const bool verbose=true); //! Provides read access to a particle headers (number of particles //! and attribute information, much cheapeer -ParticlesInfo* readHeaders(const char* filename); +ParticlesInfo* readHeaders(const char* filename,const bool verbose=true); //! Provides access to a particle set stored in a file //! if filename ends with .gz or forceCompressed is true, the file is compressed. @@ -249,7 +249,7 @@ void write(const char* filename,const ParticlesData&,const bool forceCompressed= p->release(); (will not be deleted if others are also holding). If you want to do finding neighbors give true to sort */ -ParticlesData* readCached(const char* filename,const bool sort); +ParticlesData* readCached(const char* filename,const bool sort,const bool verbose=true); //! Begin accessing data in a cached file /*! diff --git a/src/lib/core/ParticleCaching.cpp b/src/lib/core/ParticleCaching.cpp index a9ff324d..2a23d117 100644 --- a/src/lib/core/ParticleCaching.cpp +++ b/src/lib/core/ParticleCaching.cpp @@ -49,7 +49,7 @@ namespace std::map cachedParticlesCount; std::map cachedParticles; -ParticlesData* readCached(const char* filename,const bool sort) +ParticlesData* readCached(const char* filename,const bool sort,const bool verbose) { mutex.lock(); std::map::iterator i=cachedParticles.find(filename); @@ -59,7 +59,7 @@ ParticlesData* readCached(const char* filename,const bool sort) p=i->second; cachedParticlesCount[p]++; }else{ - ParticlesDataMutable* p_rw=read(filename); + ParticlesDataMutable* p_rw=read(filename,verbose); if(p_rw){ if(sort) p_rw->sort(); p=p_rw; diff --git a/src/lib/io/BGEO.cpp b/src/lib/io/BGEO.cpp index 98b6fa7d..f1c413c8 100644 --- a/src/lib/io/BGEO.cpp +++ b/src/lib/io/BGEO.cpp @@ -55,11 +55,11 @@ void writeHoudiniStr(ostream& ostream,const string& s) } -ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly) +ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,const bool verbose) { auto_ptr input(Gzip_In(filename,ios::in|ios::binary)); if(!*input){ - cerr<<"Partio: Unable to open file "< input(new ifstream(filename,ios::in|ios::binary)); if(!*input){ - cerr << "Partio: Unable to open file " << filename << endl; + if(verbose) cerr << "Partio: Unable to open file " << filename << endl; return 0; } diff --git a/src/lib/io/GEO.cpp b/src/lib/io/GEO.cpp index ec238c1e..2c734658 100644 --- a/src/lib/io/GEO.cpp +++ b/src/lib/io/GEO.cpp @@ -107,11 +107,11 @@ string scanString(istream& input) return string(buf); } -ParticlesDataMutable* readGEO(const char* filename,const bool headersOnly) +ParticlesDataMutable* readGEO(const char* filename,const bool headersOnly,const bool verbose) { auto_ptr input(Gzip_In(filename,ios::in)); if(!*input){ - cerr<<"Partio: Can't open particle data file: "< input(Gzip_In(filename,std::ios::in|std::ios::binary)); if(!*input){ - std::cerr << "Partio: Unable to open file " << filename << std::endl; + if(verbose) std::cerr << "Partio: Unable to open file " << filename << std::endl; return 0; } diff --git a/src/lib/io/PDA.cpp b/src/lib/io/PDA.cpp index 13dff2d5..4e917998 100644 --- a/src/lib/io/PDA.cpp +++ b/src/lib/io/PDA.cpp @@ -49,11 +49,11 @@ using namespace std; // TODO: convert this to use iterators like the rest of the readers/writers -ParticlesDataMutable* readPDA(const char* filename,const bool headersOnly) +ParticlesDataMutable* readPDA(const char* filename,const bool headersOnly,const bool verbose) { auto_ptr input(Gzip_In(filename,ios::in|ios::binary)); if(!*input){ - cerr<<"Partio: Can't open particle data file: "< ParticlesDataMutable* readPDBHelper(const char* filename,const bool headersOnly) +template ParticlesDataMutable* readPDBHelper(const char* filename,const bool headersOnly,const bool verbose) { auto_ptr input(Gzip_In(filename,ios::in|ios::binary)); if(!*input){ - cerr<<"Partio: Unable to open file "<(filename,headersOnly);} +ParticlesDataMutable* readPDB32(const char* filename,const bool headersOnly,const bool verbose) +{return readPDBHelper<32>(filename,headersOnly,verbose);} -ParticlesDataMutable* readPDB64(const char* filename,const bool headersOnly) -{return readPDBHelper<64>(filename,headersOnly);} +ParticlesDataMutable* readPDB64(const char* filename,const bool headersOnly,const bool verbose) +{return readPDBHelper<64>(filename,headersOnly,verbose);} bool writePDB32(const char* filename,const ParticlesData& p,const bool compressed) {return writePDBHelper<32>(filename,p,compressed);} @@ -263,11 +263,11 @@ bool writePDB32(const char* filename,const ParticlesData& p,const bool compresse bool writePDB64(const char* filename,const ParticlesData& p,const bool compressed) {return writePDBHelper<64>(filename,p,compressed);} -ParticlesDataMutable* readPDB(const char* filename,const bool headersOnly) +ParticlesDataMutable* readPDB(const char* filename,const bool headersOnly,const bool verbose) { auto_ptr input(Gzip_In(filename,ios::in|ios::binary)); if(!*input){ - cerr<<"Partio: Unable to open file "<read((char*)&channelIOHeader,sizeof(channelIOHeader)); //cout<<"we got channel io as "< 5 || channelIOHeader.type < 0 || (channelIOHeader.swap != 1 && channelIOHeader.swap != 0)){ - return readPDBHelper<32>(filename,headersOnly); + return readPDBHelper<32>(filename,headersOnly,verbose); }else{ - return readPDBHelper<64>(filename,headersOnly); + return readPDBHelper<64>(filename,headersOnly,verbose); } } diff --git a/src/lib/io/PDC.cpp b/src/lib/io/PDC.cpp index 60951817..eab0b76a 100644 --- a/src/lib/io/PDC.cpp +++ b/src/lib/io/PDC.cpp @@ -74,11 +74,11 @@ string readName(istream& input){ return result; } -ParticlesDataMutable* readPDC(const char* filename, const bool headersOnly){ +ParticlesDataMutable* readPDC(const char* filename, const bool headersOnly,const bool verbose){ auto_ptr input(Gzip_In(filename,std::ios::in|std::ios::binary)); if(!*input){ - std::cerr << "Partio: Unable to open file " << filename << std::endl; + if(verbose) std::cerr << "Partio: Unable to open file " << filename << std::endl; return 0; } diff --git a/src/lib/io/PRT.cpp b/src/lib/io/PRT.cpp index 13b435ad..4d16b19a 100644 --- a/src/lib/io/PRT.cpp +++ b/src/lib/io/PRT.cpp @@ -140,11 +140,11 @@ static bool write_buffer(std::ostream& os, z_stream& z, char* out_buf, void* p, -ParticlesDataMutable* readPRT(const char* filename,const bool headersOnly) +ParticlesDataMutable* readPRT(const char* filename,const bool headersOnly,const bool verbose) { std::auto_ptr input(new std::ifstream(filename,std::ios::in|std::ios::binary)); if (!*input) { - std::cerr<<"Partio: Unable to open file "< input(Gzip_In(filename,ios::in|ios::binary)); if(!*input){ - cerr<<"Partio: Unable to open file "< input(Gzip_In(filename,ios::in|ios::binary)); if (!*input) { - cerr<<"Partio: Can't open particle data file: "<second)(c_filename,false); + return (*i->second)(c_filename,false,verbose); } ParticlesInfo* -readHeaders(const char* c_filename) +readHeaders(const char* c_filename,bool verbose) { string filename(c_filename); string extension; @@ -157,7 +157,7 @@ readHeaders(const char* c_filename) cerr<<"Partio: No reader defined for extension "<second)(c_filename,true); + return (*i->second)(c_filename,true,verbose); } void diff --git a/src/lib/io/readers.h b/src/lib/io/readers.h index 69e11be2..a91a2f14 100644 --- a/src/lib/io/readers.h +++ b/src/lib/io/readers.h @@ -36,18 +36,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. #define _READERS_h_ namespace Partio{ -ParticlesDataMutable* readBGEO( const char* filename,const bool headersOnly); -ParticlesDataMutable* readGEO( const char* filename,const bool headersOnly); -ParticlesDataMutable* readPDB( const char* filename,const bool headersOnly); -ParticlesDataMutable* readPDB32(const char* filename,const bool headersOnly); -ParticlesDataMutable* readPDB64(const char* filename,const bool headersOnly); -ParticlesDataMutable* readPDA( const char* filename,const bool headersOnly); -ParticlesDataMutable* readMC( const char* filename,const bool headersOnly); -ParticlesDataMutable* readPTC( const char* filename,const bool headersOnly); -ParticlesDataMutable* readPDC( const char* filename,const bool headersOnly); -ParticlesDataMutable* readPRT( const char* filename,const bool headersOnly); -ParticlesDataMutable* readBIN( const char* filename,const bool headersOnly); -ParticlesDataMutable* readPTS( const char* filename,const bool headersOnly); +ParticlesDataMutable* readBGEO( const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readGEO( const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readPDB( const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readPDB32(const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readPDB64(const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readPDA( const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readMC( const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readPTC( const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readPDC( const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readPRT( const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readBIN( const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readPTS( const char* filename,const bool headersOnly,const bool verbose); bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed); bool writeGEO(const char* filename,const ParticlesData& p,const bool compressed); From bbca94d1ab36cd6321b7bdb3301f82ac69318eb6 Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Fri, 20 Jun 2014 19:15:24 -0700 Subject: [PATCH 17/52] Add setIndexedStr() api call to speed scene baking --- src/lib/Partio.h | 3 +++ src/lib/core/ParticleHeaders.cpp | 5 +++++ src/lib/core/ParticleHeaders.h | 1 + src/lib/core/ParticleSimple.cpp | 7 +++++++ src/lib/core/ParticleSimple.h | 1 + src/lib/core/ParticleSimpleInterleave.cpp | 8 ++++++++ src/lib/core/ParticleSimpleInterleave.h | 1 + src/py/partio.i | 4 ++++ 8 files changed, 30 insertions(+) diff --git a/src/lib/Partio.h b/src/lib/Partio.h index a25d5eb9..0957de9b 100644 --- a/src/lib/Partio.h +++ b/src/lib/Partio.h @@ -194,6 +194,9 @@ class ParticlesDataMutable:public ParticlesData /// Returns a token for the given string. This allows efficient storage of string data virtual int registerIndexedStr(const ParticleAttribute& attribute,const char* str)=0; + /// Returns a token for the given string. This allows efficient storage of string data + virtual void setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str)=0; + //! Preprocess the data for finding nearest neighbors by sorting into a //! KD-Tree. Note: all particle pointers are invalid after this call. virtual void sort()=0; diff --git a/src/lib/core/ParticleHeaders.cpp b/src/lib/core/ParticleHeaders.cpp index 4d4f3f10..80d2112f 100644 --- a/src/lib/core/ParticleHeaders.cpp +++ b/src/lib/core/ParticleHeaders.cpp @@ -188,3 +188,8 @@ dataAsFloat(const ParticleAttribute& attribute,const int indexCount, assert(false); } + +void ParticleHeaders:: +setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str){ + assert(false); +} diff --git a/src/lib/core/ParticleHeaders.h b/src/lib/core/ParticleHeaders.h index 0f0abe13..8feba7dd 100644 --- a/src/lib/core/ParticleHeaders.h +++ b/src/lib/core/ParticleHeaders.h @@ -53,6 +53,7 @@ class ParticleHeaders:public ParticlesDataMutable int registerIndexedStr(const ParticleAttribute& attribute,const char* str); int lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const; + void setIndexedStr(const ParticleAttribute& attribute,int indexedStrHandle,const char* str); const std::vector& indexedStrs(const ParticleAttribute& attr) const; virtual void dataAsFloat(const ParticleAttribute& attribute,const int indexCount, diff --git a/src/lib/core/ParticleSimple.cpp b/src/lib/core/ParticleSimple.cpp index 9c678ab1..78a2ac46 100644 --- a/src/lib/core/ParticleSimple.cpp +++ b/src/lib/core/ParticleSimple.cpp @@ -342,3 +342,10 @@ indexedStrs(const ParticleAttribute& attr) const return table.strings; } +void ParticlesSimple::setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str){ + IndexedStrTable& table=attributeIndexedStrs[attribute.attributeIndex]; + if(indexedStringToken >= table.strings.size() || indexedStringToken < 0) return; + table.stringToIndex.erase(table.stringToIndex.find(table.strings[indexedStringToken])); + table.strings[indexedStringToken] = str; + table.stringToIndex[str]=indexedStringToken; +} diff --git a/src/lib/core/ParticleSimple.h b/src/lib/core/ParticleSimple.h index 94a0f526..7199945c 100644 --- a/src/lib/core/ParticleSimple.h +++ b/src/lib/core/ParticleSimple.h @@ -63,6 +63,7 @@ class ParticlesSimple:public ParticlesDataMutable, void dataAsFloat(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,float* values) const; int registerIndexedStr(const ParticleAttribute& attribute,const char* str); + void setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str); int lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const; const std::vector& indexedStrs(const ParticleAttribute& attr) const; void sort(); diff --git a/src/lib/core/ParticleSimpleInterleave.cpp b/src/lib/core/ParticleSimpleInterleave.cpp index 605d344f..f6819c87 100644 --- a/src/lib/core/ParticleSimpleInterleave.cpp +++ b/src/lib/core/ParticleSimpleInterleave.cpp @@ -342,3 +342,11 @@ indexedStrs(const ParticleAttribute& attr) const return table.strings; } + +void ParticlesSimpleInterleave::setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str){ + IndexedStrTable& table=attributeIndexedStrs[attribute.attributeIndex]; + if(indexedStringToken >= table.strings.size() || indexedStringToken < 0) return; + table.stringToIndex.erase(table.stringToIndex.find(table.strings[indexedStringToken])); + table.strings[indexedStringToken] = str; + table.stringToIndex[str]=indexedStringToken; +} diff --git a/src/lib/core/ParticleSimpleInterleave.h b/src/lib/core/ParticleSimpleInterleave.h index f05329f1..2cede150 100644 --- a/src/lib/core/ParticleSimpleInterleave.h +++ b/src/lib/core/ParticleSimpleInterleave.h @@ -66,6 +66,7 @@ class ParticlesSimpleInterleave:public ParticlesDataMutable, virtual void dataAsFloat(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,float* values) const; int registerIndexedStr(const ParticleAttribute& attribute,const char* str); + void setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str); int lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const; const std::vector& indexedStrs(const ParticleAttribute& attr) const; diff --git a/src/py/partio.i b/src/py/partio.i index 042f9334..73d38fc1 100644 --- a/src/py/partio.i +++ b/src/py/partio.i @@ -173,6 +173,10 @@ public: %feature("docstring","Registers a string in the particular attribute"); virtual int registerIndexedStr(const ParticleAttribute& attribute,const char* str)=0; + %feature("autodoc"); + %feature("docstring","Changes a given index's associated string (for all particles that use this index too)"); + virtual void setIndexedStr(const ParticleAttribute& attribute,int particleAttributeHandle,const char* str)=0; + %feature("autodoc"); %feature("docstring","Prepares data for N nearest neighbor searches using the\n" From 1ee0215dd3a4621dff51eab7e3c02063778806a1 Mon Sep 17 00:00:00 2001 From: Lawrence Chai Date: Fri, 20 Feb 2015 18:57:32 -0800 Subject: [PATCH 18/52] added fixed attribute support jira: FXSOFT-232 partio global attribute support --- src/lib/Partio.h | 28 +- src/lib/PartioAttribute.h | 4 + src/lib/SConscript | 3 + src/lib/core/ParticleHeaders.cpp | 73 +++++ src/lib/core/ParticleHeaders.h | 12 +- src/lib/core/ParticleSimple.cpp | 93 ++++++- src/lib/core/ParticleSimple.h | 13 + src/lib/core/ParticleSimpleInterleave.cpp | 106 ++++++- src/lib/core/ParticleSimpleInterleave.h | 13 + src/lib/io/BGEO.cpp | 323 ++++++++++++++++------ src/lib/io/ParticleIO.cpp | 2 + src/py/partio.i | 125 +++++++++ src/tools/partinfo.cpp | 39 ++- 13 files changed, 740 insertions(+), 94 deletions(-) diff --git a/src/lib/Partio.h b/src/lib/Partio.h index 0957de9b..6c79c8b8 100644 --- a/src/lib/Partio.h +++ b/src/lib/Partio.h @@ -74,16 +74,19 @@ class ParticlesInfo virtual void release() const=0; //! Number of particles in the structure. - virtual int numAttributes() const=0; + virtual int numParticles() const=0; //! Number of per-particle attributes. - virtual int numParticles() const=0; + virtual int numAttributes() const=0; + virtual int numFixedAttributes() const=0; //! Lookup an attribute by name and store a handle to the attribute. virtual bool attributeInfo(const char* attributeName,ParticleAttribute& attribute) const=0; + virtual bool fixedAttributeInfo(const char* attributeName,FixedAttribute& attribute) const=0; //! Lookup an attribute by index and store a handle to the attribute. virtual bool attributeInfo(const int attributeInfo,ParticleAttribute& attribute) const=0; + virtual bool fixedAttributeInfo(const int attributeInfo,FixedAttribute& attribute) const=0; }; // Particle Data Interface @@ -117,11 +120,19 @@ class ParticlesData:public ParticlesInfo return static_cast(dataInternal(attribute,particleIndex)); } + template inline const T* fixedData(const FixedAttribute& attribute) const + { + // TODO: add type checking + return static_cast(fixedDataInternal(attribute)); + } + /// All indexed strings for an attribute virtual const std::vector& indexedStrs(const ParticleAttribute& attr) const=0; + virtual const std::vector& fixedIndexedStrs(const FixedAttribute& attr) const=0; /// Looks up the index for a given string for a given attribute, returns -1 if not found virtual int lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const=0; + virtual int lookupFixedIndexedStr(const FixedAttribute& attribute,const char* str) const=0; //! Fill the user supplied values array with data corresponding to the given //! list of particles. Specify whether or not your indices are sorted. Attributes @@ -163,6 +174,7 @@ class ParticlesData:public ParticlesInfo private: virtual void* dataInternal(const ParticleAttribute& attribute,const ParticleIndex particleIndex) const=0; + virtual void* fixedDataInternal(const FixedAttribute& attribute) const=0; virtual void dataInternalMultiple(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,char* values) const=0; }; @@ -191,11 +203,19 @@ class ParticlesDataMutable:public ParticlesData return static_cast(dataInternal(attribute,particleIndex)); } + template inline T* fixedDataWrite(const FixedAttribute& attribute) const + { + // TODO: add type checking + return static_cast(fixedDataInternal(attribute)); + } + /// Returns a token for the given string. This allows efficient storage of string data virtual int registerIndexedStr(const ParticleAttribute& attribute,const char* str)=0; + virtual int registerFixedIndexedStr(const FixedAttribute& attribute,const char* str)=0; /// Returns a token for the given string. This allows efficient storage of string data virtual void setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str)=0; + virtual void setFixedIndexedStr(const FixedAttribute& attribute,int indexedStringToken,const char* str)=0; //! Preprocess the data for finding nearest neighbors by sorting into a //! KD-Tree. Note: all particle pointers are invalid after this call. @@ -205,6 +225,9 @@ class ParticlesDataMutable:public ParticlesData virtual ParticleAttribute addAttribute(const char* attribute,ParticleAttributeType type, const int count)=0; + virtual FixedAttribute addFixedAttribute(const char* attribute,ParticleAttributeType type, + const int count)=0; + //! Add a particle to the particle set. Returns the offset to the particle virtual ParticleIndex addParticle()=0; @@ -225,6 +248,7 @@ class ParticlesDataMutable:public ParticlesData private: virtual void* dataInternal(const ParticleAttribute& attribute,const ParticleIndex particleIndex) const=0; + virtual void* fixedDataInternal(const FixedAttribute& attribute) const=0; }; //! Provides an empty particle instance, freed with p->release() diff --git a/src/lib/PartioAttribute.h b/src/lib/PartioAttribute.h index 2026c878..f6a5cde2 100644 --- a/src/lib/PartioAttribute.h +++ b/src/lib/PartioAttribute.h @@ -112,5 +112,9 @@ class ParticleAttribute //! for example for a PTC file to read and write this could be "color" or "point" // std::string comment; }; + +class FixedAttribute : public ParticleAttribute +{ +}; } #endif diff --git a/src/lib/SConscript b/src/lib/SConscript index 6ea27280..8007fcd7 100644 --- a/src/lib/SConscript +++ b/src/lib/SConscript @@ -54,18 +54,21 @@ def cppFiles(basePath): files=cppFiles(os.path.join(dir,"core"))+cppFiles(os.path.join(dir,"io")) +sharedlib=env.SharedLibrary("partio",files) lib=env.Library("partio",files) foo=Dir(".").abspath+"../../include" env.Install(variant_build_abs+"/include","Partio.h") env.Install(variant_build_abs+"/include","PartioIterator.h") env.Install(variant_build_abs+"/include","PartioAttribute.h") +env.Install(variant_build_abs+"/lib64",sharedlib) env.Install(variant_build_abs+"/lib64",lib) core_targets = [ env.Install(variant_install_abs+"/include","Partio.h"), env.Install(variant_install_abs+"/include","PartioIterator.h"), env.Install(variant_install_abs+"/include","PartioAttribute.h"), + env.Install(variant_install_abs+"/lib64",sharedlib), env.Install(variant_install_abs+"/lib64",lib) ] diff --git a/src/lib/core/ParticleHeaders.cpp b/src/lib/core/ParticleHeaders.cpp index 80d2112f..005b1a6c 100644 --- a/src/lib/core/ParticleHeaders.cpp +++ b/src/lib/core/ParticleHeaders.cpp @@ -68,6 +68,12 @@ numAttributes() const return attributes.size(); } +int ParticleHeaders:: +numFixedAttributes() const +{ + return fixedAttributes.size(); +} + bool ParticleHeaders:: attributeInfo(const int attributeIndex,ParticleAttribute& attribute) const { @@ -76,6 +82,14 @@ attributeInfo(const int attributeIndex,ParticleAttribute& attribute) const return true; } +bool ParticleHeaders:: +fixedAttributeInfo(const int attributeIndex,FixedAttribute& attribute) const +{ + if(attributeIndex<0 || attributeIndex>=(int)fixedAttributes.size()) return false; + attribute=fixedAttributes[attributeIndex]; + return true; +} + bool ParticleHeaders:: attributeInfo(const char* attributeName,ParticleAttribute& attribute) const { @@ -87,6 +101,17 @@ attributeInfo(const char* attributeName,ParticleAttribute& attribute) const return false; } +bool ParticleHeaders:: +fixedAttributeInfo(const char* attributeName,FixedAttribute& attribute) const +{ + std::map::const_iterator it=nameToFixedAttribute.find(attributeName); + if(it!=nameToFixedAttribute.end()){ + attribute=fixedAttributes[it->second]; + return true; + } + return false; +} + void ParticleHeaders:: sort() { @@ -101,6 +126,13 @@ registerIndexedStr(const ParticleAttribute& attribute,const char* str) return -1; } +int ParticleHeaders:: +registerFixedIndexedStr(const FixedAttribute& attribute,const char* str) +{ + assert(false); + return -1; +} + int ParticleHeaders:: lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const { @@ -108,6 +140,13 @@ lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const return -1; } +int ParticleHeaders:: +lookupFixedIndexedStr(const FixedAttribute& attribute,const char* str) const +{ + assert(false); + return -1; +} + const std::vector& ParticleHeaders:: indexedStrs(const ParticleAttribute& attr) const { @@ -116,6 +155,14 @@ indexedStrs(const ParticleAttribute& attr) const return dummy; } +const std::vector& ParticleHeaders:: +fixedIndexedStrs(const FixedAttribute& attr) const +{ + static std::vector dummy; + assert(false); + return dummy; +} + void ParticleHeaders:: findPoints(const float bboxMin[3],const float bboxMax[3],std::vector& points) const { @@ -152,6 +199,20 @@ addAttribute(const char* attribute,ParticleAttributeType type,const int count) return attr; } +FixedAttribute ParticleHeaders:: +addFixedAttribute(const char* attribute,ParticleAttributeType type,const int count) +{ + // TODO: check if attribute already exists and if so what data type + FixedAttribute attr; + attr.name=attribute; + attr.type=type; + attr.attributeIndex=fixedAttributes.size(); // all arrays separate so we don't use this here! + attr.count=count; + fixedAttributes.push_back(attr); + nameToFixedAttribute[attribute]=fixedAttributes.size()-1; + return attr; +} + ParticleIndex ParticleHeaders:: addParticle() { @@ -174,6 +235,13 @@ dataInternal(const ParticleAttribute& attribute,const ParticleIndex particleInde return 0; } +void* ParticleHeaders:: +fixedDataInternal(const FixedAttribute& attribute) const +{ + assert(false); + return 0; +} + void ParticleHeaders:: dataInternalMultiple(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,char* values) const @@ -193,3 +261,8 @@ void ParticleHeaders:: setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str){ assert(false); } + +void ParticleHeaders:: +setFixedIndexedStr(const FixedAttribute& attribute,int indexedStringToken,const char* str){ + assert(false); +} diff --git a/src/lib/core/ParticleHeaders.h b/src/lib/core/ParticleHeaders.h index 8feba7dd..15136142 100644 --- a/src/lib/core/ParticleHeaders.h +++ b/src/lib/core/ParticleHeaders.h @@ -47,14 +47,21 @@ class ParticleHeaders:public ParticlesDataMutable virtual ~ParticleHeaders(); int numAttributes() const; + int numFixedAttributes() const; int numParticles() const; bool attributeInfo(const char* attributeName,ParticleAttribute& attribute) const; + bool fixedAttributeInfo(const char* attributeName,FixedAttribute& attribute) const; bool attributeInfo(const int attributeInfo,ParticleAttribute& attribute) const; + bool fixedAttributeInfo(const int attributeInfo,FixedAttribute& attribute) const; int registerIndexedStr(const ParticleAttribute& attribute,const char* str); + int registerFixedIndexedStr(const FixedAttribute& attribute,const char* str); int lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const; + int lookupFixedIndexedStr(const FixedAttribute& attribute,const char* str) const; void setIndexedStr(const ParticleAttribute& attribute,int indexedStrHandle,const char* str); + void setFixedIndexedStr(const FixedAttribute& attribute,int indexedStrHandle,const char* str); const std::vector& indexedStrs(const ParticleAttribute& attr) const; + const std::vector& fixedIndexedStrs(const FixedAttribute& attr) const; virtual void dataAsFloat(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,float* values) const; @@ -68,6 +75,7 @@ class ParticleHeaders:public ParticlesDataMutable ParticleIndex *points, float *pointDistancesSquared, float *finalRadius2) const; ParticleAttribute addAttribute(const char* attribute,ParticleAttributeType type,const int count); + FixedAttribute addFixedAttribute(const char* attribute,ParticleAttributeType type,const int count); ParticleIndex addParticle(); iterator addParticles(const int count); @@ -79,6 +87,7 @@ class ParticleHeaders:public ParticlesDataMutable private: void* dataInternal(const ParticleAttribute& attribute,const ParticleIndex particleIndex) const; + void* fixedDataInternal(const FixedAttribute& attribute) const; void dataInternalMultiple(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,char* values) const; @@ -86,7 +95,8 @@ class ParticleHeaders:public ParticlesDataMutable int particleCount; std::vector attributes; std::map nameToAttribute; - + std::vector fixedAttributes; + std::map nameToFixedAttribute; }; } #endif diff --git a/src/lib/core/ParticleSimple.cpp b/src/lib/core/ParticleSimple.cpp index 78a2ac46..b2879a2b 100644 --- a/src/lib/core/ParticleSimple.cpp +++ b/src/lib/core/ParticleSimple.cpp @@ -80,6 +80,12 @@ numAttributes() const return attributes.size(); } +int ParticlesSimple:: +numFixedAttributes() const +{ + return fixedAttributes.size(); +} + bool ParticlesSimple:: attributeInfo(const int attributeIndex,ParticleAttribute& attribute) const { @@ -88,6 +94,14 @@ attributeInfo(const int attributeIndex,ParticleAttribute& attribute) const return true; } +bool ParticlesSimple:: +fixedAttributeInfo(const int attributeIndex,FixedAttribute& attribute) const +{ + if(attributeIndex<0 || attributeIndex>=(int)fixedAttributes.size()) return false; + attribute=fixedAttributes[attributeIndex]; + return true; +} + bool ParticlesSimple:: attributeInfo(const char* attributeName,ParticleAttribute& attribute) const { @@ -99,6 +113,16 @@ attributeInfo(const char* attributeName,ParticleAttribute& attribute) const return false; } +bool ParticlesSimple:: +fixedAttributeInfo(const char* attributeName,FixedAttribute& attribute) const +{ + std::map::const_iterator it=nameToFixedAttribute.find(attributeName); + if(it!=nameToFixedAttribute.end()){ + attribute=fixedAttributes[it->second]; + return true; + } + return false; +} void ParticlesSimple:: sort() @@ -208,6 +232,30 @@ addAttribute(const char* attribute,ParticleAttributeType type,const int count) return attr; } +FixedAttribute ParticlesSimple:: +addFixedAttribute(const char* attribute,ParticleAttributeType type,const int count) +{ + if(nameToFixedAttribute.find(attribute) != nameToFixedAttribute.end()){ + std::cerr<<"Partio: addFixedAttribute failed because attr '"<=0 && attribute.attributeIndex<(int)fixedAttributes.size()); + return fixedAttributeData[attribute.attributeIndex]; +} + void ParticlesSimple:: dataInternalMultiple(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,char* values) const @@ -326,6 +381,18 @@ registerIndexedStr(const ParticleAttribute& attribute,const char* str) return newIndex; } +int ParticlesSimple:: +registerFixedIndexedStr(const FixedAttribute& attribute,const char* str) +{ + IndexedStrTable& table=fixedAttributeIndexedStrs[attribute.attributeIndex]; + std::map::const_iterator it=table.stringToIndex.find(str); + if(it!=table.stringToIndex.end()) return it->second; + int newIndex=table.strings.size(); + table.strings.push_back(str); + table.stringToIndex[str]=newIndex; + return newIndex; +} + int ParticlesSimple:: lookupIndexedStr(Partio::ParticleAttribute const &attribute, char const *str) const { @@ -335,6 +402,15 @@ lookupIndexedStr(Partio::ParticleAttribute const &attribute, char const *str) co return -1; } +int ParticlesSimple:: +lookupFixedIndexedStr(Partio::FixedAttribute const &attribute, char const *str) const +{ + const IndexedStrTable& table=fixedAttributeIndexedStrs[attribute.attributeIndex]; + std::map::const_iterator it=table.stringToIndex.find(str); + if(it!=table.stringToIndex.end()) return it->second; + return -1; +} + const std::vector& ParticlesSimple:: indexedStrs(const ParticleAttribute& attr) const { @@ -342,9 +418,24 @@ indexedStrs(const ParticleAttribute& attr) const return table.strings; } +const std::vector& ParticlesSimple:: +fixedIndexedStrs(const FixedAttribute& attr) const +{ + const IndexedStrTable& table=fixedAttributeIndexedStrs[attr.attributeIndex]; + return table.strings; +} + void ParticlesSimple::setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str){ IndexedStrTable& table=attributeIndexedStrs[attribute.attributeIndex]; - if(indexedStringToken >= table.strings.size() || indexedStringToken < 0) return; + if(indexedStringToken >= int(table.strings.size()) || indexedStringToken < 0) return; + table.stringToIndex.erase(table.stringToIndex.find(table.strings[indexedStringToken])); + table.strings[indexedStringToken] = str; + table.stringToIndex[str]=indexedStringToken; +} + +void ParticlesSimple::setFixedIndexedStr(const FixedAttribute& attribute,int indexedStringToken,const char* str){ + IndexedStrTable& table=fixedAttributeIndexedStrs[attribute.attributeIndex]; + if(indexedStringToken >= int(table.strings.size()) || indexedStringToken < 0) return; table.stringToIndex.erase(table.stringToIndex.find(table.strings[indexedStringToken])); table.strings[indexedStringToken] = str; table.stringToIndex[str]=indexedStringToken; diff --git a/src/lib/core/ParticleSimple.h b/src/lib/core/ParticleSimple.h index 7199945c..8be99b82 100644 --- a/src/lib/core/ParticleSimple.h +++ b/src/lib/core/ParticleSimple.h @@ -57,15 +57,22 @@ class ParticlesSimple:public ParticlesDataMutable, ParticlesSimple(); int numAttributes() const; + int numFixedAttributes() const; int numParticles() const; bool attributeInfo(const char* attributeName,ParticleAttribute& attribute) const; + bool fixedAttributeInfo(const char* attributeName,FixedAttribute& attribute) const; bool attributeInfo(const int attributeInfo,ParticleAttribute& attribute) const; + bool fixedAttributeInfo(const int attributeInfo,FixedAttribute& attribute) const; void dataAsFloat(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,float* values) const; int registerIndexedStr(const ParticleAttribute& attribute,const char* str); + int registerFixedIndexedStr(const FixedAttribute& attribute,const char* str); void setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str); + void setFixedIndexedStr(const FixedAttribute& attribute,int indexedStringToken,const char* str); int lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const; + int lookupFixedIndexedStr(const FixedAttribute& attribute,const char* str) const; const std::vector& indexedStrs(const ParticleAttribute& attr) const; + const std::vector& fixedIndexedStrs(const FixedAttribute& attr) const; void sort(); void findPoints(const float bboxMin[3],const float bboxMax[3],std::vector& points) const; float findNPoints(const float center[3],int nPoints,const float maxRadius, @@ -74,6 +81,7 @@ class ParticlesSimple:public ParticlesDataMutable, ParticleIndex *points, float *pointDistancesSquared, float *finalRadius2) const; ParticleAttribute addAttribute(const char* attribute,ParticleAttributeType type,const int count); + FixedAttribute addFixedAttribute(const char* attribute,ParticleAttributeType type,const int count); ParticleIndex addParticle(); iterator addParticles(const int count); @@ -86,6 +94,7 @@ class ParticlesSimple:public ParticlesDataMutable, void setupAccessor(Partio::ParticleIterator& iterator,ParticleAccessor& accessor) const; private: void* dataInternal(const ParticleAttribute& attribute,const ParticleIndex particleIndex) const; + void* fixedDataInternal(const FixedAttribute& attribute) const; void dataInternalMultiple(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,char* values) const; @@ -102,6 +111,10 @@ class ParticlesSimple:public ParticlesDataMutable, std::vector attributes; std::vector attributeStrides; std::map nameToAttribute; + std::vector fixedAttributeData; // Inside is data of appropriate type + std::vector fixedAttributeIndexedStrs; + std::vector fixedAttributes; + std::map nameToFixedAttribute; PartioMutex kdtree_mutex; KdTree<3>* kdtree; diff --git a/src/lib/core/ParticleSimpleInterleave.cpp b/src/lib/core/ParticleSimpleInterleave.cpp index f6819c87..29b15d6c 100644 --- a/src/lib/core/ParticleSimpleInterleave.cpp +++ b/src/lib/core/ParticleSimpleInterleave.cpp @@ -80,6 +80,11 @@ numAttributes() const return attributes.size(); } +int ParticlesSimpleInterleave:: +numFixedAttributes() const +{ + return fixedAttributes.size(); +} bool ParticlesSimpleInterleave:: attributeInfo(const int attributeIndex,ParticleAttribute& attribute) const @@ -89,6 +94,14 @@ attributeInfo(const int attributeIndex,ParticleAttribute& attribute) const return true; } +bool ParticlesSimpleInterleave:: +fixedAttributeInfo(const int attributeIndex,FixedAttribute& attribute) const +{ + if(attributeIndex<0 || attributeIndex>=(int)fixedAttributes.size()) return false; + attribute=fixedAttributes[attributeIndex]; + return true; +} + bool ParticlesSimpleInterleave:: attributeInfo(const char* attributeName,ParticleAttribute& attribute) const { @@ -100,6 +113,17 @@ attributeInfo(const char* attributeName,ParticleAttribute& attribute) const return false; } +bool ParticlesSimpleInterleave:: +fixedAttributeInfo(const char* attributeName,FixedAttribute& attribute) const +{ + std::map::const_iterator it=nameToFixedAttribute.find(attributeName); + if(it!=nameToFixedAttribute.end()){ + attribute=fixedAttributes[it->second]; + return true; + } + return false; +} + void ParticlesSimpleInterleave:: sort() { @@ -210,6 +234,44 @@ addAttribute(const char* attribute,ParticleAttributeType type,const int count) return attr; } +FixedAttribute ParticlesSimpleInterleave:: +addFixedAttribute(const char* attribute,ParticleAttributeType type,const int count) +{ + //std::cerr<< "AddAttribute interleave" << std::endl; + if(nameToFixedAttribute.find(attribute) != nameToFixedAttribute.end()){ + std::cerr<<"Partio: addFixedAttribute failed because attr '"<::const_iterator it=table.stringToIndex.find(str); + if(it!=table.stringToIndex.end()) return it->second; + int newIndex=table.strings.size(); + table.strings.push_back(str); + table.stringToIndex[str]=newIndex; + return newIndex; +} + int ParticlesSimpleInterleave:: lookupIndexedStr(Partio::ParticleAttribute const &attribute, char const *str) const { @@ -335,6 +415,15 @@ lookupIndexedStr(Partio::ParticleAttribute const &attribute, char const *str) co return -1; } +int ParticlesSimpleInterleave:: +lookupFixedIndexedStr(Partio::FixedAttribute const &attribute, char const *str) const +{ + const IndexedStrTable& table=fixedAttributeIndexedStrs[attribute.attributeIndex]; + std::map::const_iterator it=table.stringToIndex.find(str); + if(it!=table.stringToIndex.end()) return it->second; + return -1; +} + const std::vector& ParticlesSimpleInterleave:: indexedStrs(const ParticleAttribute& attr) const { @@ -342,10 +431,25 @@ indexedStrs(const ParticleAttribute& attr) const return table.strings; } +const std::vector& ParticlesSimpleInterleave:: +fixedIndexedStrs(const FixedAttribute& attr) const +{ + const IndexedStrTable& table=fixedAttributeIndexedStrs[attr.attributeIndex]; + return table.strings; +} + void ParticlesSimpleInterleave::setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str){ IndexedStrTable& table=attributeIndexedStrs[attribute.attributeIndex]; - if(indexedStringToken >= table.strings.size() || indexedStringToken < 0) return; + if(indexedStringToken >= int(table.strings.size()) || indexedStringToken < 0) return; + table.stringToIndex.erase(table.stringToIndex.find(table.strings[indexedStringToken])); + table.strings[indexedStringToken] = str; + table.stringToIndex[str]=indexedStringToken; +} + +void ParticlesSimpleInterleave::setFixedIndexedStr(const FixedAttribute& attribute,int indexedStringToken,const char* str){ + IndexedStrTable& table=fixedAttributeIndexedStrs[attribute.attributeIndex]; + if(indexedStringToken >= int(table.strings.size()) || indexedStringToken < 0) return; table.stringToIndex.erase(table.stringToIndex.find(table.strings[indexedStringToken])); table.strings[indexedStringToken] = str; table.stringToIndex[str]=indexedStringToken; diff --git a/src/lib/core/ParticleSimpleInterleave.h b/src/lib/core/ParticleSimpleInterleave.h index 2cede150..2bcdc0ca 100644 --- a/src/lib/core/ParticleSimpleInterleave.h +++ b/src/lib/core/ParticleSimpleInterleave.h @@ -59,16 +59,23 @@ class ParticlesSimpleInterleave:public ParticlesDataMutable, ParticlesSimpleInterleave(); int numAttributes() const; + int numFixedAttributes() const; int numParticles() const; bool attributeInfo(const char* attributeName,ParticleAttribute& attribute) const; + bool fixedAttributeInfo(const char* attributeName,FixedAttribute& attribute) const; bool attributeInfo(const int attributeInfo,ParticleAttribute& attribute) const; + bool fixedAttributeInfo(const int attributeInfo,FixedAttribute& attribute) const; virtual void dataAsFloat(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,float* values) const; int registerIndexedStr(const ParticleAttribute& attribute,const char* str); + int registerFixedIndexedStr(const FixedAttribute& attribute,const char* str); void setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str); + void setFixedIndexedStr(const FixedAttribute& attribute,int indexedStringToken,const char* str); int lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const; + int lookupFixedIndexedStr(const FixedAttribute& attribute,const char* str) const; const std::vector& indexedStrs(const ParticleAttribute& attr) const; + const std::vector& fixedIndexedStrs(const FixedAttribute& attr) const; void sort(); void findPoints(const float bboxMin[3],const float bboxMax[3],std::vector& points) const; @@ -78,6 +85,7 @@ class ParticlesSimpleInterleave:public ParticlesDataMutable, ParticleIndex *points, float *pointDistancesSquared, float *finalRadius2) const; ParticleAttribute addAttribute(const char* attribute,ParticleAttributeType type,const int count); + FixedAttribute addFixedAttribute(const char* attribute,ParticleAttributeType type,const int count); ParticleIndex addParticle(); iterator addParticles(const int count); @@ -90,6 +98,7 @@ class ParticlesSimpleInterleave:public ParticlesDataMutable, void setupAccessor(Partio::ParticleIterator& iterator,ParticleAccessor& accessor) const; private: void* dataInternal(const ParticleAttribute& attribute,const ParticleIndex particleIndex) const; + void* fixedDataInternal(const FixedAttribute& attribute) const; void dataInternalMultiple(const ParticleAttribute& attribute,const int indexCount, const ParticleIndex* particleIndices,const bool sorted,char* values) const; @@ -106,6 +115,10 @@ class ParticlesSimpleInterleave:public ParticlesDataMutable, std::vector attributeOffsets; // Inside is data of appropriate type std::vector attributes; std::map nameToAttribute; + std::vector fixedAttributeIndexedStrs; + std::vector fixedAttributeOffsets; // Inside is data of appropriate type + std::vector fixedAttributes; + std::map nameToFixedAttribute; PartioMutex kdtree_mutex; KdTree<3>* kdtree; diff --git a/src/lib/io/BGEO.cpp b/src/lib/io/BGEO.cpp index f1c413c8..e2996b5b 100644 --- a/src/lib/io/BGEO.cpp +++ b/src/lib/io/BGEO.cpp @@ -43,6 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. #include #include +#include + namespace Partio { @@ -55,59 +57,12 @@ void writeHoudiniStr(ostream& ostream,const string& s) } -ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,const bool verbose) +bool getAttributes(int& particleSize, vector& attrOffsets, vector& attrHandles, vector& accessors, int nAttrib, istream* input, ParticlesDataMutable* simple, bool headersOnly) { - auto_ptr input(Gzip_In(filename,ios::in|ios::binary)); - if(!*input){ - if(verbose) cerr<<"Partio: Unable to open file "<(*input,magic,versionChar,version,nPoints,nPrims,nPointGroups); - read(*input,nPrimGroups,nPointAttrib,nVertexAttrib,nPrimAttrib,nAttrib); - - - // Check header magic and version - const int bgeo_magic=((((('B'<<8)|'g')<<8)|'e')<<8)|'o'; - if(magic!=bgeo_magic){ - cerr<<"Partio: Magic number '"<addParticles(nPoints); - - - // Read attribute definitions - int particleSize=4; // Size in # of 32 bit primitives - vector attrOffsets; // offsets in # of 32 bit offsets - vector attrHandles; - vector accessors; attrOffsets.push_back(0); // pull values from byte offset attrHandles.push_back(simple->addAttribute("position",VECTOR,3)); // we always have one accessors.push_back(ParticleAccessor(attrHandles[0])); - - for(int i=0;i(*input,nameLength); char* name=new char[nameLength+1]; @@ -165,31 +120,185 @@ ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,const delete[] name; } - if(headersOnly) return simple; // escape before we try to edit data + return true; +} - // Read the points - int *buffer=new int[particleSize]; +bool getFixedAttributes(int& particleSize, vector& attrOffsets, vector& attrHandles, int nAttrib, istream* input, ParticlesDataMutable* simple, bool headersOnly) +{ + for(int i=0;i(*input,nameLength); + char* name=new char[nameLength+1]; + input->read(name,nameLength);name[nameLength]=0; +#if 0 + if (!strcmp(name,"varmap")) { + delete [] name; + unsigned short a; + int b; + int c; + read(*input,a,b,c); + for (int i=0; i(*input,d); + char* crap=new char[d+1]; + input->read(crap,d);crap[d]=0; + std::cerr << a << " " << b << " " << c << " " << d << " " << crap << std::endl; + delete [] crap; + } + continue; + } +#endif + unsigned short size; + int houdiniType; + read(*input,size,houdiniType); + if(houdiniType==0 || houdiniType==1 || houdiniType==5){ + // read default values. don't do anything with them + for(int i=0;iread((char*)&defaultValue,sizeof(int)); + } + ParticleAttributeType type=NONE; + if(houdiniType==0) type=FLOAT; + else if(houdiniType==1) type=INT; + else if(houdiniType==5) type=VECTOR; + attrHandles.push_back(simple->addFixedAttribute(name,type,size)); + attrOffsets.push_back(particleSize); + particleSize+=size; + }else if(houdiniType==4){ + FixedAttribute fixedAttribute=simple->addFixedAttribute(name,INDEXEDSTR,size); + attrHandles.push_back(fixedAttribute); + attrOffsets.push_back(particleSize); + int numIndices=0; + read(*input,numIndices); + for(int ii=0;ii(*input,indexNameLength); + char* indexName=new char[indexNameLength+1];; + input->read(indexName,indexNameLength); + indexName[indexNameLength]=0; + if (!headersOnly) { + int id=simple->registerFixedIndexedStr(fixedAttribute,indexName); + if(id != ii){ + std::cerr<<"Partio: error on read, expected registerIndexStr to return index "<release(); + return 0; + }else{ + cerr<<"Partio: unknown attribute "<release(); + return 0; + } + delete[] name; + } - // make iterator and register accessors - ParticlesDataMutable::iterator iterator=simple->begin(); - for(size_t i=0;iend();iterator!=end;++iterator){ - //for(int i=0;iread((char*)buffer,particleSize*sizeof(int)); - for(unsigned int attrIndex=0;attrIndex(iterator); - for(int k=0;k input(Gzip_In(filename,ios::in|ios::binary)); + if(!*input){ + if(verbose) cerr<<"Partio: Unable to open file "<(*input,magic,versionChar,version,nPoints,nPrims,nPointGroups); + read(*input,nPrimGroups,nPointAttrib,nVertexAttrib,nPrimAttrib,nAttrib); + + + // Check header magic and version + const int bgeo_magic=((((('B'<<8)|'g')<<8)|'e')<<8)|'o'; + if(magic!=bgeo_magic){ + cerr<<"Partio: Magic number '"<addParticles(nPoints); + + + // Read attribute definitions + int particleSize=4; // Size in # of 32 bit primitives + vector attrOffsets; // offsets in # of 32 bit offsets + vector attrHandles; + vector accessors; + getAttributes(particleSize, attrOffsets, attrHandles, accessors, nPointAttrib, input.get(), simple, headersOnly); + + if(headersOnly) { + input->seekg(nPoints*particleSize*sizeof(int),input->cur); + } else { + // Read the points + int *buffer=new int[particleSize]; + + // make iterator and register accessors + ParticlesDataMutable::iterator iterator=simple->begin(); + for(size_t i=0;iend();iterator!=end;++iterator){ + input->read((char*)buffer,particleSize*sizeof(int)); + for(unsigned int attrIndex=0;attrIndex(iterator); + for(int k=0;k fixedAttrOffsets; // offsets in # of 32 bit offsets + vector fixedAttrHandles; + getFixedAttributes(particleSize, fixedAttrOffsets, fixedAttrHandles, nAttrib, input.get(), simple, headersOnly); + + if (headersOnly) return simple; + + // Read the points + int *fixedBuffer=new int[particleSize]; + input->read((char*)fixedBuffer,particleSize*sizeof(int)); + for(unsigned int attrIndex=0;attrIndexfixedDataWrite(fixedAttrHandles[attrIndex])[k]=fixedBuffer[fixedAttrOffsets[attrIndex]+k]; + } + } + delete [] fixedBuffer; // return the populated simpleParticle return simple; @@ -211,13 +320,13 @@ bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed char versionChar='V'; int version=5; int nPoints=p.numParticles(); - int nPrims=1; + int nPrims=0; int nPointGroups=0; int nPrimGroups=0; int nPointAttrib=p.numAttributes()-1; int nVertexAttrib=0; - int nPrimAttrib=1; - int nAttrib=0; + int nPrimAttrib=0; + int nAttrib=p.numFixedAttributes(); write(*output,magic,versionChar,version,nPoints,nPrims,nPointGroups); write(*output,nPrimGroups,nPointAttrib,nVertexAttrib,nPrimAttrib,nAttrib); @@ -285,7 +394,7 @@ bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed buffer[attrOffsets[attrIndex]+k]=data[k]; BIGEND::swap(buffer[attrOffsets[attrIndex]+k]); } - } + } // set homogeneous coordinate float *w=(float*)&buffer[3]; *w=1.; @@ -294,21 +403,61 @@ bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed } delete [] buffer; - // Write primitive attribs - writeHoudiniStr(*output,"generator"); - write(*output,(short)0x1); // count 1 - write(*output,(int)0x4); // type 4 index - write(*output,(int)0x1); // type 4 index - writeHoudiniStr(*output,"papi"); - - // Write the primitive - write(*output,(int)0x8000); - write(*output,(int)nPoints); - if(nPoints>(int)1<<16) - for(int i=0;i(*output,(int)i); - else - for(int i=0;i(*output,(unsigned short)i); - write(*output,(int)0); + vector fixedHandles; + vector fixedAttrOffsets; + particleSize=0; + for(int i=0;i& indexTable=p.fixedIndexedStrs(attr); + int numIndexes=indexTable.size(); + write(*output,size,houdiniType,numIndexes); + for(int ii=0;ii(*output,size,houdiniType); + for(int i=0;i(*output,defaultValue); + } + } + fixedAttrOffsets.push_back(particleSize); + particleSize+=attr.count; + + fixedHandles.push_back(attr); + } + + int *fixedBuffer=new int[particleSize]; + + for(unsigned int attrIndex=0;attrIndex(fixedHandles[attrIndex])[k]; + BIGEND::swap(fixedBuffer[fixedAttrOffsets[attrIndex]+k]); + } + } + output->write((char*)fixedBuffer,particleSize*sizeof(int)); + + delete [] fixedBuffer; // Write extra write(*output,(char)0x00); diff --git a/src/lib/io/ParticleIO.cpp b/src/lib/io/ParticleIO.cpp index 1e155b35..0554a27f 100644 --- a/src/lib/io/ParticleIO.cpp +++ b/src/lib/io/ParticleIO.cpp @@ -85,7 +85,9 @@ writers() if(!initialized){ initializationMutex.lock(); data["bgeo"]=writeBGEO; + data["bhclassic"]=writeBGEO; data["geo"]=writeGEO; + data["hclassic"]=writeGEO; data["pdb"]=writePDB; data["pdb32"]=writePDB32; data["pdb64"]=writePDB64; diff --git a/src/py/partio.i b/src/py/partio.i index 73d38fc1..1290b56e 100644 --- a/src/py/partio.i +++ b/src/py/partio.i @@ -139,6 +139,10 @@ public: %feature("autodoc"); %feature("docstring","Returns the number of particles in the set"); virtual int numAttributes() const=0; + + %feature("autodoc"); + %feature("docstring","Returns the number of fixed attributes"); + virtual int numFixedAttributes() const=0; }; @@ -153,6 +157,9 @@ class ParticlesData:public ParticlesInfo %feature("docstring","Looks up a given indexed string given the index, returns -1 if not found"); int lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const=0; + %feature("autodoc"); + %feature("docstring","Looks up a given fixed indexed string given the index, returns -1 if not found"); + int lookupFixedIndexedStr(const FixedAttribute& attribute,const char* str) const=0; }; %rename(ParticleIteratorFalse) ParticleIterator; @@ -173,10 +180,17 @@ public: %feature("docstring","Registers a string in the particular attribute"); virtual int registerIndexedStr(const ParticleAttribute& attribute,const char* str)=0; + %feature("autodoc"); + %feature("docstring","Registers a string in the particular fixed attribute"); + virtual int registerFixedIndexedStr(const FixedAttribute& attribute,const char* str)=0; + %feature("autodoc"); %feature("docstring","Changes a given index's associated string (for all particles that use this index too)"); virtual void setIndexedStr(const ParticleAttribute& attribute,int particleAttributeHandle,const char* str)=0; + %feature("autodoc"); + %feature("docstring","Changes a given fixed index's associated string"); + virtual void setFixedIndexedStr(const FixedAttribute& attribute,int particleAttributeHandle,const char* str)=0; %feature("autodoc"); %feature("docstring","Prepares data for N nearest neighbor searches using the\n" @@ -189,6 +203,12 @@ public: virtual ParticleAttribute addAttribute(const char* attribute,ParticleAttributeType type, const int count)=0; + %feature("autodoc"); + %feature("docstring","Adds a new fixed attribute of given name, type and count. If type is\n" + "partio.VECTOR, then count must be 3"); + virtual FixedAttribute addFixedAttribute(const char* attribute,ParticleAttributeType type, + const int count)=0; + %feature("autodoc"); %feature("docstring","Adds a new particle and returns the index"); virtual ParticleIndex addParticle()=0; @@ -266,6 +286,24 @@ public: return tuple; } + %feature("autodoc"); + %feature("docstring","Gets fixed attribute data"); + PyObject* get(const FixedAttribute& attr) + { + PyObject* tuple=PyTuple_New(attr.count); + if(attr.type==Partio::INT || attr.type==Partio::INDEXEDSTR){ + const int* p=$self->fixedData(attr); + for(int k=0;kfixedData(attr); + for(int k=0;k& indexes=self->fixedIndexedStrs(attr); + PyObject* list=PyList_New(indexes.size()); + for(size_t k=0;kfixedDataWrite(attr); + for(int i=0;ifixedDataWrite(attr); + for(int i=0;ifixedAttributeInfo(name,a); + if(valid) return new FixedAttribute(a); + else return 0; + } + %feature("autodoc"); %feature("docstring","Returns the attribute handle by index"); %newobject attributeInfo; @@ -363,6 +473,21 @@ public: if(valid) return new ParticleAttribute(a); else return 0; } + + %feature("autodoc"); + %feature("docstring","Returns the fixed attribute handle by index"); + %newobject attributeInfo; + FixedAttribute* fixedAttributeInfo(const int index) + { + if(index<0 || index>=$self->numFixedAttributes()){ + PyErr_SetString(PyExc_IndexError,"Invalid attribute index"); + return NULL; + } + FixedAttribute a; + bool valid=$self->fixedAttributeInfo(index,a); + if(valid) return new FixedAttribute(a); + else return 0; + } } %feature("autodoc"); diff --git a/src/tools/partinfo.cpp b/src/tools/partinfo.cpp index 6a96722e..5cd8a893 100644 --- a/src/tools/partinfo.cpp +++ b/src/tools/partinfo.cpp @@ -79,7 +79,10 @@ int main(int argc,char *argv[]) for(int ii=0;iidata(attr,particleIndex)[ii]; - std::cout<<" "<indexedStrs(attr)[val]<<"'"; + std::cout<<" "<indexedStrs(attr).size();index++){ + std::cout<indexedStrs(attr)[index]<<"'"; + } }else if(attr.type==Partio::INT) std::cout<<" "<data(attr,particleIndex)[ii]; else std::cout<<" "<data(attr,particleIndex)[ii]; } @@ -89,8 +92,40 @@ int main(int argc,char *argv[]) } } + numAttr=p->numFixedAttributes(); + if (numAttr) { + std::cout<<"---------------------------"<fixedAttributeInfo(i,attr); + std::cout<fixedAttributeInfo(i,attr); + std::cout<fixedData(attr)[ii]; + std::cout<<" "<fixedIndexedStrs(attr).size();index++){ + std::cout<fixedIndexedStrs(attr)[index]<<"'"; + } + }else if(attr.type==Partio::INT) std::cout<<" "<fixedData(attr)[ii]; + else std::cout<<" "<fixedData(attr)[ii]; + } + std::cout<release(); } - + return 0; } From 136b3f65dd04e53c447dab20d1b7baf2b765c8a5 Mon Sep 17 00:00:00 2001 From: Lawrence Chai Date: Mon, 23 Feb 2015 16:51:04 -0800 Subject: [PATCH 19/52] addressed code review comments --- src/lib/Partio.h | 10 ++ src/lib/PartioAttribute.h | 27 ++++- src/lib/core/ParticleSimple.cpp | 1 + src/lib/core/ParticleSimpleInterleave.cpp | 11 +- src/lib/core/ParticleSimpleInterleave.h | 1 + src/lib/io/BGEO.cpp | 123 ++++++---------------- src/tools/partinfo.cpp | 8 +- 7 files changed, 82 insertions(+), 99 deletions(-) diff --git a/src/lib/Partio.h b/src/lib/Partio.h index 6c79c8b8..2f9f2faf 100644 --- a/src/lib/Partio.h +++ b/src/lib/Partio.h @@ -78,14 +78,17 @@ class ParticlesInfo //! Number of per-particle attributes. virtual int numAttributes() const=0; + //! Number of fixed attributes. virtual int numFixedAttributes() const=0; //! Lookup an attribute by name and store a handle to the attribute. virtual bool attributeInfo(const char* attributeName,ParticleAttribute& attribute) const=0; + //! Lookup an attribute by name and store a handle to the attribute. virtual bool fixedAttributeInfo(const char* attributeName,FixedAttribute& attribute) const=0; //! Lookup an attribute by index and store a handle to the attribute. virtual bool attributeInfo(const int attributeInfo,ParticleAttribute& attribute) const=0; + //! Lookup an attribute by index and store a handle to the attribute. virtual bool fixedAttributeInfo(const int attributeInfo,FixedAttribute& attribute) const=0; }; @@ -128,10 +131,12 @@ class ParticlesData:public ParticlesInfo /// All indexed strings for an attribute virtual const std::vector& indexedStrs(const ParticleAttribute& attr) const=0; + /// All indexed strings for an attribute virtual const std::vector& fixedIndexedStrs(const FixedAttribute& attr) const=0; /// Looks up the index for a given string for a given attribute, returns -1 if not found virtual int lookupIndexedStr(const ParticleAttribute& attribute,const char* str) const=0; + /// Looks up the index for a given string for a given attribute, returns -1 if not found virtual int lookupFixedIndexedStr(const FixedAttribute& attribute,const char* str) const=0; //! Fill the user supplied values array with data corresponding to the given @@ -203,6 +208,8 @@ class ParticlesDataMutable:public ParticlesData return static_cast(dataInternal(attribute,particleIndex)); } + //! Get a pointer to the data corresponding to the attribute given by the + //! fixed attribute handle. template inline T* fixedDataWrite(const FixedAttribute& attribute) const { // TODO: add type checking @@ -211,10 +218,12 @@ class ParticlesDataMutable:public ParticlesData /// Returns a token for the given string. This allows efficient storage of string data virtual int registerIndexedStr(const ParticleAttribute& attribute,const char* str)=0; + /// Returns a token for the given string. This allows efficient storage of string data virtual int registerFixedIndexedStr(const FixedAttribute& attribute,const char* str)=0; /// Returns a token for the given string. This allows efficient storage of string data virtual void setIndexedStr(const ParticleAttribute& attribute,int indexedStringToken,const char* str)=0; + /// Returns a token for the given string. This allows efficient storage of string data virtual void setFixedIndexedStr(const FixedAttribute& attribute,int indexedStringToken,const char* str)=0; //! Preprocess the data for finding nearest neighbors by sorting into a @@ -225,6 +234,7 @@ class ParticlesDataMutable:public ParticlesData virtual ParticleAttribute addAttribute(const char* attribute,ParticleAttributeType type, const int count)=0; + //! Adds a fixed attribute with the provided name, type and count virtual FixedAttribute addFixedAttribute(const char* attribute,ParticleAttributeType type, const int count)=0; diff --git a/src/lib/PartioAttribute.h b/src/lib/PartioAttribute.h index f6a5cde2..d11daa66 100644 --- a/src/lib/PartioAttribute.h +++ b/src/lib/PartioAttribute.h @@ -90,7 +90,7 @@ std::string TypeName(ParticleAttributeType attrType); //! Particle Collection Interface /*! This class provides a handle and description of an attribute. This includes - what type the primitive is, how many instances of the primitive there, name of + what type the primitive is, the number of entries, the name of the attribute and an index which speeds lookups of data */ class ParticleAttribute @@ -113,8 +113,31 @@ class ParticleAttribute // std::string comment; }; -class FixedAttribute : public ParticleAttribute +// Fixed Attribute Specifier +//! Fixed Attribute Interface +/*! + This class provides a handle and description of an attribute. This includes + what type the primitive is, the number of entries, the name of + the attribute and an index which speeds lookups of data +*/ +class FixedAttribute { +public: + //! Type of attribute + ParticleAttributeType type; + + //! Number of entries, should be 3 if type is VECTOR + int count; + + //! Name of attribute + std::string name; + + //! Internal method of fast access, user should not use or change + int attributeIndex; + + //! Comment used by various data/readers for extra attribute information + //! for example for a PTC file to read and write this could be "color" or "point" + // std::string comment; }; } #endif diff --git a/src/lib/core/ParticleSimple.cpp b/src/lib/core/ParticleSimple.cpp index b2879a2b..c34a8ad6 100644 --- a/src/lib/core/ParticleSimple.cpp +++ b/src/lib/core/ParticleSimple.cpp @@ -59,6 +59,7 @@ ParticlesSimple:: ~ParticlesSimple() { for(unsigned int i=0;i stringToIndex; // TODO: this should be a hash table unordered_map diff --git a/src/lib/io/BGEO.cpp b/src/lib/io/BGEO.cpp index e2996b5b..1d7cb775 100644 --- a/src/lib/io/BGEO.cpp +++ b/src/lib/io/BGEO.cpp @@ -56,98 +56,39 @@ void writeHoudiniStr(ostream& ostream,const string& s) ostream.write(s.c_str(),s.size()); } - -bool getAttributes(int& particleSize, vector& attrOffsets, vector& attrHandles, vector& accessors, int nAttrib, istream* input, ParticlesDataMutable* simple, bool headersOnly) +template +struct Helper { - attrOffsets.push_back(0); // pull values from byte offset - attrHandles.push_back(simple->addAttribute("position",VECTOR,3)); // we always have one - accessors.push_back(ParticleAccessor(attrHandles[0])); - for(int i=0;i(*input,nameLength); - char* name=new char[nameLength+1]; - input->read(name,nameLength);name[nameLength]=0; - unsigned short size; - int houdiniType; - read(*input,size,houdiniType); - if(houdiniType==0 || houdiniType==1 || houdiniType==5){ - // read default values. don't do anything with them - for(int i=0;iread((char*)&defaultValue,sizeof(int)); - } - ParticleAttributeType type=NONE; - if(houdiniType==0) type=FLOAT; - else if(houdiniType==1) type=INT; - else if(houdiniType==5) type=VECTOR; - attrHandles.push_back(simple->addAttribute(name,type,size)); - accessors.push_back(ParticleAccessor(attrHandles.back())); - attrOffsets.push_back(particleSize); - particleSize+=size; - }else if(houdiniType==4){ - ParticleAttribute attribute=simple->addAttribute(name,INDEXEDSTR,size); - attrHandles.push_back(attribute); - accessors.push_back(ParticleAccessor(attrHandles.back())); - attrOffsets.push_back(particleSize); - int numIndices=0; - read(*input,numIndices); - for(int ii=0;ii(*input,indexNameLength); - char* indexName=new char[indexNameLength+1];; - input->read(indexName,indexNameLength); - indexName[indexNameLength]=0; - if (!headersOnly) { - int id=simple->registerIndexedStr(attribute,indexName); - if(id != ii){ - std::cerr<<"Partio: error on read, expected registerIndexStr to return index "<release(); - return 0; - }else{ - cerr<<"Partio: unknown attribute "<release(); - return 0; - } - delete[] name; - } + T addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size); + int registerIndexedStr(const T& attribute,const char* str); +}; +template<> +struct Helper +{ + ParticleAttribute addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size) {return simple->addAttribute(name,type,size);} + int registerIndexedStr(ParticlesDataMutable* simple, const ParticleAttribute& attribute,const char* str) {return simple->registerIndexedStr(attribute,str);} +}; +template<> +struct Helper +{ + FixedAttribute addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size) {return simple->addFixedAttribute(name,type,size);} + int registerIndexedStr(ParticlesDataMutable* simple, const FixedAttribute& attribute,const char* str) {return simple->registerFixedIndexedStr(attribute,str);} +}; - return true; -} +struct FixedDummyAccessor{ + template + FixedDummyAccessor(const T& /*attr*/){} +}; -bool getFixedAttributes(int& particleSize, vector& attrOffsets, vector& attrHandles, int nAttrib, istream* input, ParticlesDataMutable* simple, bool headersOnly) +template +bool getAttributes(int& particleSize, vector& attrOffsets, vector& attrHandles, vector& accessors, int nAttrib, istream* input, ParticlesDataMutable* simple, bool headersOnly) { + Helper helper; for(int i=0;i(*input,nameLength); char* name=new char[nameLength+1]; input->read(name,nameLength);name[nameLength]=0; -#if 0 - if (!strcmp(name,"varmap")) { - delete [] name; - unsigned short a; - int b; - int c; - read(*input,a,b,c); - for (int i=0; i(*input,d); - char* crap=new char[d+1]; - input->read(crap,d);crap[d]=0; - std::cerr << a << " " << b << " " << c << " " << d << " " << crap << std::endl; - delete [] crap; - } - continue; - } -#endif unsigned short size; int houdiniType; read(*input,size,houdiniType); @@ -161,12 +102,14 @@ bool getFixedAttributes(int& particleSize, vector& attrOffsets, vectoraddFixedAttribute(name,type,size)); + attrHandles.push_back(helper.addAttribute(simple,name,type,size)); + accessors.push_back(TAccessor(attrHandles.back())); attrOffsets.push_back(particleSize); particleSize+=size; }else if(houdiniType==4){ - FixedAttribute fixedAttribute=simple->addFixedAttribute(name,INDEXEDSTR,size); - attrHandles.push_back(fixedAttribute); + TAttribute attribute=helper.addAttribute(simple,name,INDEXEDSTR,size); + attrHandles.push_back(attribute); + accessors.push_back(TAccessor(attrHandles.back())); attrOffsets.push_back(particleSize); int numIndices=0; read(*input,numIndices); @@ -177,7 +120,7 @@ bool getFixedAttributes(int& particleSize, vector& attrOffsets, vectorread(indexName,indexNameLength); indexName[indexNameLength]=0; if (!headersOnly) { - int id=simple->registerFixedIndexedStr(fixedAttribute,indexName); + int id=helper.registerIndexedStr(simple,attribute,indexName); if(id != ii){ std::cerr<<"Partio: error on read, expected registerIndexStr to return index "< attrOffsets; // offsets in # of 32 bit offsets vector attrHandles; vector accessors; + attrOffsets.push_back(0); // pull values from byte offset + attrHandles.push_back(simple->addAttribute("position",VECTOR,3)); // we always have one + accessors.push_back(ParticleAccessor(attrHandles[0])); getAttributes(particleSize, attrOffsets, attrHandles, accessors, nPointAttrib, input.get(), simple, headersOnly); if(headersOnly) { @@ -282,7 +228,8 @@ ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,const particleSize=0; vector fixedAttrOffsets; // offsets in # of 32 bit offsets vector fixedAttrHandles; - getFixedAttributes(particleSize, fixedAttrOffsets, fixedAttrHandles, nAttrib, input.get(), simple, headersOnly); + vector fixedAccessors; + getAttributes(particleSize, fixedAttrOffsets, fixedAttrHandles, fixedAccessors, nAttrib, input.get(), simple, headersOnly); if (headersOnly) return simple; diff --git a/src/tools/partinfo.cpp b/src/tools/partinfo.cpp index 5cd8a893..a24305f2 100644 --- a/src/tools/partinfo.cpp +++ b/src/tools/partinfo.cpp @@ -92,13 +92,13 @@ int main(int argc,char *argv[]) } } - numAttr=p->numFixedAttributes(); - if (numAttr) { + int numFixedAttr=p->numFixedAttributes(); + if (numFixedAttr) { std::cout<<"---------------------------"<fixedAttributeInfo(i,attr); std::cout<fixedAttributeInfo(i,attr); std::cout< Date: Tue, 3 Mar 2015 19:03:59 -0800 Subject: [PATCH 20/52] Fix python api by avoiding overloading --- src/py/example/circle.py | 3 ++- src/py/partio.i | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/py/example/circle.py b/src/py/example/circle.py index 986c0378..80eef214 100644 --- a/src/py/example/circle.py +++ b/src/py/example/circle.py @@ -59,8 +59,9 @@ p.set(color,i,(t/2./math.pi,1-(t/2./math.pi),0)) p.set(radius,i,(.02,)) p.set(normal,i,(0,1,0)) + foo=p.get(position,i) t+=dt # Write to a point cloud -papi.write("spiral.ptc",p) +partio.write("spiral.ptc",p) diff --git a/src/py/partio.i b/src/py/partio.i index 1290b56e..c5ebeca7 100644 --- a/src/py/partio.i +++ b/src/py/partio.i @@ -288,7 +288,7 @@ public: %feature("autodoc"); %feature("docstring","Gets fixed attribute data"); - PyObject* get(const FixedAttribute& attr) + PyObject* getFixed(const FixedAttribute& attr) { PyObject* tuple=PyTuple_New(attr.count); if(attr.type==Partio::INT || attr.type==Partio::INDEXEDSTR){ @@ -384,7 +384,7 @@ public: %feature("autodoc"); %feature("docstring","Sets data on a given fixed attribute.\n" "Data must be specified as tuple."); - PyObject* set(const FixedAttribute& attr,PyObject* tuple) + PyObject* setFixed(const FixedAttribute& attr,PyObject* tuple) { if(!PySequence_Check(tuple)){ PyErr_SetString(PyExc_TypeError,"Expecting a sequence"); From 0d197b7a163edb04c8477a345f4199109b5d0bd0 Mon Sep 17 00:00:00 2001 From: Lawrence Chai Date: Tue, 3 Mar 2015 15:26:59 -0800 Subject: [PATCH 21/52] skip primitive attributes --- src/lib/io/BGEO.cpp | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/lib/io/BGEO.cpp b/src/lib/io/BGEO.cpp index 1d7cb775..09dc9116 100644 --- a/src/lib/io/BGEO.cpp +++ b/src/lib/io/BGEO.cpp @@ -75,9 +75,16 @@ struct Helper int registerIndexedStr(ParticlesDataMutable* simple, const FixedAttribute& attribute,const char* str) {return simple->registerFixedIndexedStr(attribute,str);} }; -struct FixedDummyAccessor{ +class DummyAttribute {}; +template<> +struct Helper +{ + DummyAttribute addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size) { return DummyAttribute(); } + int registerIndexedStr(ParticlesDataMutable* simple, const DummyAttribute& attribute,const char* str) { return 0; } +}; +struct DummyAccessor{ template - FixedDummyAccessor(const T& /*attr*/){} + DummyAccessor(const T& /*attr*/){} }; template @@ -145,6 +152,31 @@ bool getAttributes(int& particleSize, vector& attrOffsets, vector primAttrOffsets; // offsets in # of 32 bit offsets + vector primAttrHandles; + vector primAccessors; + getAttributes(particleSize, primAttrOffsets, primAttrHandles, primAccessors, nPrimAttrib, input, 0, true); + + for(int i=0;i(*input,primType); + if(primType==0x00008000) { + int size; + read(*input,size); + input->seekg(size*sizeof(unsigned short),input->cur); + input->seekg(particleSize*sizeof(int),input->cur); + } else { + std::cerr << "Partio: Unrecognized Primitive Type: " << std::hex << primType << std::endl; + return false; + } + } + return true; +} + ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,const bool verbose) { auto_ptr input(Gzip_In(filename,ios::in|ios::binary)); @@ -225,10 +257,12 @@ ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,const delete [] buffer; } + if (!skipPrimitives(nPrims, nPrimAttrib, input.get())) return simple; + particleSize=0; vector fixedAttrOffsets; // offsets in # of 32 bit offsets vector fixedAttrHandles; - vector fixedAccessors; + vector fixedAccessors; getAttributes(particleSize, fixedAttrOffsets, fixedAttrHandles, fixedAccessors, nAttrib, input.get(), simple, headersOnly); if (headersOnly) return simple; From 83dc30230c3c70c1abaede8254ae263291449ae4 Mon Sep 17 00:00:00 2001 From: Lawrence Chai Date: Tue, 3 Mar 2015 16:57:05 -0800 Subject: [PATCH 22/52] address comments --- src/lib/io/BGEO.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lib/io/BGEO.cpp b/src/lib/io/BGEO.cpp index 09dc9116..9536fac7 100644 --- a/src/lib/io/BGEO.cpp +++ b/src/lib/io/BGEO.cpp @@ -153,7 +153,7 @@ bool getAttributes(int& particleSize, vector& attrOffsets, vector primAttrOffsets; // offsets in # of 32 bit offsets @@ -167,10 +167,13 @@ bool skipPrimitives(int nPrims, int nPrimAttrib, istream* input) if(primType==0x00008000) { int size; read(*input,size); - input->seekg(size*sizeof(unsigned short),input->cur); + if(nPoints>(int)1<<16) + input->seekg(size*sizeof(int),input->cur); + else + input->seekg(size*sizeof(unsigned short),input->cur); input->seekg(particleSize*sizeof(int),input->cur); } else { - std::cerr << "Partio: Unrecognized Primitive Type: " << std::hex << primType << std::endl; + std::cerr << "Partio: Unrecognized Primitive Type: 0x" << std::hex << primType << " - Cannot process detail attributes" << std::endl; return false; } } @@ -257,7 +260,7 @@ ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,const delete [] buffer; } - if (!skipPrimitives(nPrims, nPrimAttrib, input.get())) return simple; + if (!skipPrimitives(nPoints, nPrims, nPrimAttrib, input.get())) return simple; particleSize=0; vector fixedAttrOffsets; // offsets in # of 32 bit offsets From 9f48495ddbaba9a07f32dafaed92dfcf71f712ad Mon Sep 17 00:00:00 2001 From: Lawrence Chai Date: Tue, 3 Mar 2015 22:31:55 -0800 Subject: [PATCH 23/52] address comments --- src/lib/io/BGEO.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/io/BGEO.cpp b/src/lib/io/BGEO.cpp index 9536fac7..8116a4c4 100644 --- a/src/lib/io/BGEO.cpp +++ b/src/lib/io/BGEO.cpp @@ -167,7 +167,7 @@ bool skipPrimitives(int nPoints, int nPrims, int nPrimAttrib, istream* input) if(primType==0x00008000) { int size; read(*input,size); - if(nPoints>(int)1<<16) + if(nPoints>=(int)1<<16) input->seekg(size*sizeof(int),input->cur); else input->seekg(size*sizeof(unsigned short),input->cur); From 2db8e36eb5adee01350a031d2300a297ba5696f1 Mon Sep 17 00:00:00 2001 From: Lawrence Chai Date: Wed, 6 May 2015 15:53:06 -0700 Subject: [PATCH 24/52] support gzip files with detail attributes jira: FXSOFT-635 bgeo causes dlight to crash when being loaded in aurora --- src/lib/io/BGEO.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/lib/io/BGEO.cpp b/src/lib/io/BGEO.cpp index 8116a4c4..02fb6b8f 100644 --- a/src/lib/io/BGEO.cpp +++ b/src/lib/io/BGEO.cpp @@ -152,6 +152,18 @@ bool getAttributes(int& particleSize, vector& attrOffsets, vector0) { + int toRead=std::min(numChars,bufferSize); + input->read(buffer,toRead); + numChars-=toRead; + } +} + // ignore primitive attributes, only know about Particle Systems currently bool skipPrimitives(int nPoints, int nPrims, int nPrimAttrib, istream* input) { @@ -168,10 +180,10 @@ bool skipPrimitives(int nPoints, int nPrims, int nPrimAttrib, istream* input) int size; read(*input,size); if(nPoints>=(int)1<<16) - input->seekg(size*sizeof(int),input->cur); + skip(input,size*sizeof(int)); else - input->seekg(size*sizeof(unsigned short),input->cur); - input->seekg(particleSize*sizeof(int),input->cur); + skip(input,size*sizeof(unsigned short)); + skip(input,particleSize*sizeof(int)); } else { std::cerr << "Partio: Unrecognized Primitive Type: 0x" << std::hex << primType << " - Cannot process detail attributes" << std::endl; return false; @@ -234,7 +246,7 @@ ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,const getAttributes(particleSize, attrOffsets, attrHandles, accessors, nPointAttrib, input.get(), simple, headersOnly); if(headersOnly) { - input->seekg(nPoints*particleSize*sizeof(int),input->cur); + skip(input.get(),nPoints*particleSize*sizeof(int)); } else { // Read the points int *buffer=new int[particleSize]; From 483741a9e8743756e2632bff1daa6fb6da493322 Mon Sep 17 00:00:00 2001 From: Andrew Selle Date: Sat, 13 Jun 2015 21:28:53 -0700 Subject: [PATCH 25/52] Rework verbosity to allow message to be returned through ostream - Python bindings now have Verbose variants of read that allow capturing the message - BGEO gives a better error when a new bgeo is attempted to be used. JIRA: FXSOFT-447 --- src/lib/Partio.h | 8 +++--- src/lib/core/ParticleCaching.cpp | 2 +- src/lib/io/BGEO.cpp | 49 ++++++++++++++++++-------------- src/lib/io/BIN.cpp | 10 +++---- src/lib/io/GEO.cpp | 15 +++++----- src/lib/io/MC.cpp | 8 +++--- src/lib/io/PDA.cpp | 6 ++-- src/lib/io/PDB.cpp | 43 ++++++++++++++-------------- src/lib/io/PDC.cpp | 10 +++---- src/lib/io/PRT.cpp | 36 +++++++++++------------ src/lib/io/PTC.cpp | 25 ++++++++-------- src/lib/io/PTS.cpp | 4 +-- src/lib/io/ParticleIO.cpp | 34 +++++++++++----------- src/lib/io/RIB.cpp | 6 ++-- src/lib/io/readers.h | 46 +++++++++++++++--------------- src/py/partio.i | 41 ++++++++++++++++++++++++-- 16 files changed, 191 insertions(+), 152 deletions(-) diff --git a/src/lib/Partio.h b/src/lib/Partio.h index 2f9f2faf..4ade10b9 100644 --- a/src/lib/Partio.h +++ b/src/lib/Partio.h @@ -268,15 +268,15 @@ ParticlesDataMutable* createInterleave(); //! Provides read/write access to a particle set stored in a file //! freed with p->release() -ParticlesDataMutable* read(const char* filename,const bool verbose=true); +ParticlesDataMutable* read(const char* filename,const bool verbose=true,std::ostream& errorStream=std::cerr); //! Provides read access to a particle headers (number of particles //! and attribute information, much cheapeer -ParticlesInfo* readHeaders(const char* filename,const bool verbose=true); +ParticlesInfo* readHeaders(const char* filename,const bool verbose=true,std::ostream& errorStream=std::cerr); //! Provides access to a particle set stored in a file //! if filename ends with .gz or forceCompressed is true, the file is compressed. -void write(const char* filename,const ParticlesData&,const bool forceCompressed=false); +void write(const char* filename,const ParticlesData&,const bool forceCompressed=false,bool verbose=true,std::ostream& errorStream=std::cerr); //! Cached (only one copy) read only way to read a particle file @@ -286,7 +286,7 @@ void write(const char* filename,const ParticlesData&,const bool forceCompressed= p->release(); (will not be deleted if others are also holding). If you want to do finding neighbors give true to sort */ -ParticlesData* readCached(const char* filename,const bool sort,const bool verbose=true); +ParticlesData* readCached(const char* filename,const bool sort,const bool verbose=true,std::ostream& errorStream=std::cerr); //! Begin accessing data in a cached file /*! diff --git a/src/lib/core/ParticleCaching.cpp b/src/lib/core/ParticleCaching.cpp index 2a23d117..54862736 100644 --- a/src/lib/core/ParticleCaching.cpp +++ b/src/lib/core/ParticleCaching.cpp @@ -49,7 +49,7 @@ namespace std::map cachedParticlesCount; std::map cachedParticles; -ParticlesData* readCached(const char* filename,const bool sort,const bool verbose) +ParticlesData* readCached(const char* filename,const bool sort,const bool verbose,std::ostream& error) { mutex.lock(); std::map::iterator i=cachedParticles.find(filename); diff --git a/src/lib/io/BGEO.cpp b/src/lib/io/BGEO.cpp index 02fb6b8f..2725d5be 100644 --- a/src/lib/io/BGEO.cpp +++ b/src/lib/io/BGEO.cpp @@ -88,7 +88,7 @@ struct DummyAccessor{ }; template -bool getAttributes(int& particleSize, vector& attrOffsets, vector& attrHandles, vector& accessors, int nAttrib, istream* input, ParticlesDataMutable* simple, bool headersOnly) +bool getAttributes(int& particleSize, vector& attrOffsets, vector& attrHandles, vector& accessors, int nAttrib, istream* input, ParticlesDataMutable* simple, bool headersOnly, std::ostream* errorStream) { Helper helper; for(int i=0;i& attrOffsets, vectorrelease(); return 0; }else{ - cerr<<"Partio: unknown attribute "<release(); return 0; @@ -165,13 +165,13 @@ void skip(istream *input, int numChars) } // ignore primitive attributes, only know about Particle Systems currently -bool skipPrimitives(int nPoints, int nPrims, int nPrimAttrib, istream* input) +bool skipPrimitives(int nPoints, int nPrims, int nPrimAttrib, istream* input,std::ostream* errorStream) { int particleSize=0; vector primAttrOffsets; // offsets in # of 32 bit offsets vector primAttrHandles; vector primAccessors; - getAttributes(particleSize, primAttrOffsets, primAttrHandles, primAccessors, nPrimAttrib, input, 0, true); + getAttributes(particleSize, primAttrOffsets, primAttrHandles, primAccessors, nPrimAttrib, input, 0, true, errorStream); for(int i=0;i input(Gzip_In(filename,ios::in|ios::binary)); if(!*input){ - if(verbose) cerr<<"Partio: Unable to open file "<(*input,magic,versionChar,version,nPoints,nPrims,nPointGroups); + read(*input,magic[0],magic[1],magic[2],magic[3]); + read(*input,versionChar,version,nPoints,nPrims,nPointGroups); read(*input,nPrimGroups,nPointAttrib,nVertexAttrib,nPrimAttrib,nAttrib); // Check header magic and version - const int bgeo_magic=((((('B'<<8)|'g')<<8)|'e')<<8)|'o'; - if(magic!=bgeo_magic){ - cerr<<"Partio: Magic number '"<addAttribute("position",VECTOR,3)); // we always have one accessors.push_back(ParticleAccessor(attrHandles[0])); - getAttributes(particleSize, attrOffsets, attrHandles, accessors, nPointAttrib, input.get(), simple, headersOnly); + getAttributes(particleSize, attrOffsets, attrHandles, accessors, nPointAttrib, input.get(), simple, headersOnly, errorStream); if(headersOnly) { skip(input.get(),nPoints*particleSize*sizeof(int)); @@ -272,13 +279,13 @@ ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,const delete [] buffer; } - if (!skipPrimitives(nPoints, nPrims, nPrimAttrib, input.get())) return simple; + if (!skipPrimitives(nPoints, nPrims, nPrimAttrib, input.get(),errorStream)) return simple; particleSize=0; vector fixedAttrOffsets; // offsets in # of 32 bit offsets vector fixedAttrHandles; vector fixedAccessors; - getAttributes(particleSize, fixedAttrOffsets, fixedAttrHandles, fixedAccessors, nAttrib, input.get(), simple, headersOnly); + getAttributes(particleSize, fixedAttrOffsets, fixedAttrHandles, fixedAccessors, nAttrib, input.get(), simple, headersOnly, errorStream); if (headersOnly) return simple; @@ -300,7 +307,7 @@ ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,const return simple; } -bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed) +bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) { auto_ptr output( compressed ? @@ -308,7 +315,7 @@ bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed :new ofstream(filename,ios::out|ios::binary)); if(!*output){ - cerr<<"Partio Unable to open file "< input(new ifstream(filename,ios::in|ios::binary)); if(!*input){ - if(verbose) cerr << "Partio: Unable to open file " << filename << endl; + if(errorStream) *errorStream << "Partio: Unable to open file " << filename << endl; return 0; } @@ -87,7 +87,7 @@ ParticlesDataMutable* readBIN(const char* filename, const bool headersOnly,const input->read((char*)&header, sizeof(header)); if(BIN_MAGIC != header.verificationCode){ - cerr << "Partio: Magic number '" << hex<< header.verificationCode << "' of '" << filename << "' doesn't match BIN magic '" << BIN_MAGIC << "'" << endl; + if(errorStream) *errorStream<< "Partio: Magic number '" << hex<< header.verificationCode << "' of '" << filename << "' doesn't match BIN magic '" << BIN_MAGIC << "'" << endl; return 0; } @@ -219,14 +219,14 @@ ParticlesDataMutable* readBIN(const char* filename, const bool headersOnly,const return simple; } -bool writeBIN(const char* filename,const ParticlesData& p,const bool /*compressed*/) +bool writeBIN(const char* filename,const ParticlesData& p,const bool /*compressed*/,std::ostream* errorStream) { auto_ptr output( new ofstream(filename,ios::out|ios::binary)); if (!*output) { - cerr<<"Partio Unable to open file "< input(Gzip_In(filename,ios::in)); if(!*input){ - if(verbose) cerr<<"Partio: Can't open particle data file: "<> attrName >> nvals >> attrType; if(attrType=="index"){ - cerr<<"Partio: attr '"<>nIndices; ParticleAttribute attribute=simple->addAttribute(attrName.c_str(),INDEXEDSTR,1); @@ -154,11 +154,10 @@ ParticlesDataMutable* readGEO(const char* filename,const bool headersOnly,const string indexName; //*input>>indexName; indexName=scanString(*input); - //std::cerr<<"Partio: index "<registerIndexedStr(attribute,indexName.c_str()); if(id != j){ - cerr<<"Partio: error on read, expected registerIndexStr to return index "<addAttribute(attrName.c_str(),type,nvals)); @@ -236,7 +235,7 @@ void writeType(ostream& output,const ParticlesData& p,const ParticleAttribute& a } } -bool writeGEO(const char* filename,const ParticlesData& p,const bool compressed) +bool writeGEO(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) { auto_ptr output( compressed ? @@ -288,7 +287,7 @@ bool writeGEO(const char* filename,const ParticlesData& p,const bool compressed) *output< input(Gzip_In(filename,std::ios::in|std::ios::binary)); if(!*input){ - if(verbose) std::cerr << "Partio: Unable to open file " << filename << std::endl; + if(errorStream) *errorStream << "Partio: Unable to open file " << filename << std::endl; return 0; } int magic; read(*input, magic); if(MC_MAGIC != magic){ - std::cerr << "Partio: Magic number '" << magic << "' of '" << filename << "' doesn't match mc magic '" << MC_MAGIC << "'" << std::endl; + if(errorStream) *errorStream << "Partio: Magic number '" << magic << "' of '" << filename << "' doesn't match mc magic '" << MC_MAGIC << "'" << std::endl; return 0; } @@ -205,7 +205,7 @@ ParticlesDataMutable* readMC(const char* filename, const bool headersOnly,const else { input->seekg((int)input->tellg() + attrHeader.blocksize); - std::cerr << "Partio: Attribute '" << attrHeader.name << " " << attrHeader.type << "' cannot map type" << std::endl; + if(errorStream) *errorStream << "Partio: Attribute '" << attrHeader.name << " " << attrHeader.type << "' cannot map type" << std::endl; } } simple->addParticles(numParticles); diff --git a/src/lib/io/PDA.cpp b/src/lib/io/PDA.cpp index 4e917998..74678fb5 100644 --- a/src/lib/io/PDA.cpp +++ b/src/lib/io/PDA.cpp @@ -49,11 +49,11 @@ using namespace std; // TODO: convert this to use iterators like the rest of the readers/writers -ParticlesDataMutable* readPDA(const char* filename,const bool headersOnly,const bool verbose) +ParticlesDataMutable* readPDA(const char* filename,const bool headersOnly,std::ostream* errorStream) { auto_ptr input(Gzip_In(filename,ios::in|ios::binary)); if(!*input){ - if(verbose) cerr<<"Partio: Can't open particle data file: "< output( compressed ? diff --git a/src/lib/io/PDB.cpp b/src/lib/io/PDB.cpp index 0646d12e..ea6ba84e 100644 --- a/src/lib/io/PDB.cpp +++ b/src/lib/io/PDB.cpp @@ -73,7 +73,6 @@ template<> struct PDB_POLICY<64> string GetString(istream& input,bool& error) { - //cerr<<"enter"< ParticlesDataMutable* readPDBHelper(const char* filename,const bool headersOnly,const bool verbose) +template ParticlesDataMutable* readPDBHelper(const char* filename,const bool headersOnly,std::ostream* errorStream) { auto_ptr input(Gzip_In(filename,ios::in|ios::binary)); if(!*input){ - if(verbose) cerr<<"Partio: Unable to open file "< ParticlesDataMutable* readPDBHelper(const char* filename,cons input->read((char*)&header,sizeof(typename PDB_POLICY::HEADER)); if(header.magic != PDB_MAGIC){ - cerr<<"Partio: failed to get PDB magic"< ParticlesDataMutable* readPDBHelper(const char* filename,cons input->read(buf,min(toSkip,1024)); toSkip-=1024; } - cerr<<"Partio: Attribute '"<addAttribute(name.c_str(),type,count); @@ -173,7 +172,7 @@ template ParticlesDataMutable* readPDBHelper(const char* filename,cons } template -bool writePDBHelper(const char* filename,const ParticlesData& p,const bool compressed) +bool writePDBHelper(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) { auto_ptr output( compressed ? @@ -181,7 +180,7 @@ bool writePDBHelper(const char* filename,const ParticlesData& p,const bool compr :new ofstream(filename,ios::out|ios::binary)); if(!*output){ - cerr<<"Partio Unable to open file "<(filename,headersOnly,verbose);} +ParticlesDataMutable* readPDB32(const char* filename,const bool headersOnly,std::ostream* errorStream) +{return readPDBHelper<32>(filename,headersOnly,errorStream);} -ParticlesDataMutable* readPDB64(const char* filename,const bool headersOnly,const bool verbose) -{return readPDBHelper<64>(filename,headersOnly,verbose);} +ParticlesDataMutable* readPDB64(const char* filename,const bool headersOnly,std::ostream* errorStream) +{return readPDBHelper<64>(filename,headersOnly,errorStream);} -bool writePDB32(const char* filename,const ParticlesData& p,const bool compressed) -{return writePDBHelper<32>(filename,p,compressed);} +bool writePDB32(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) +{return writePDBHelper<32>(filename,p,compressed,errorStream);} -bool writePDB64(const char* filename,const ParticlesData& p,const bool compressed) -{return writePDBHelper<64>(filename,p,compressed);} +bool writePDB64(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) +{return writePDBHelper<64>(filename,p,compressed,errorStream);} -ParticlesDataMutable* readPDB(const char* filename,const bool headersOnly,const bool verbose) +ParticlesDataMutable* readPDB(const char* filename,const bool headersOnly,std::ostream* errorStream) { auto_ptr input(Gzip_In(filename,ios::in|ios::binary)); if(!*input){ - if(verbose) cerr<<"Partio: Unable to open file "<::HEADER header; input->read((char*)&header,sizeof(header)); if(header.magic != PDB_MAGIC){ - cerr<<"Partio: failed to get PDB magic"<read((char*)&channelIOHeader,sizeof(channelIOHeader)); //cout<<"we got channel io as "< 5 || channelIOHeader.type < 0 || (channelIOHeader.swap != 1 && channelIOHeader.swap != 0)){ - return readPDBHelper<32>(filename,headersOnly,verbose); + return readPDBHelper<32>(filename,headersOnly,errorStream); }else{ - return readPDBHelper<64>(filename,headersOnly,verbose); + return readPDBHelper<64>(filename,headersOnly,errorStream); } } -bool writePDB(const char* filename,const ParticlesData& p,const bool compressed) -{return writePDBHelper<32>(filename,p,compressed);} +bool writePDB(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) +{return writePDBHelper<32>(filename,p,compressed,errorStream);} } diff --git a/src/lib/io/PDC.cpp b/src/lib/io/PDC.cpp index eab0b76a..63b51be7 100644 --- a/src/lib/io/PDC.cpp +++ b/src/lib/io/PDC.cpp @@ -74,18 +74,18 @@ string readName(istream& input){ return result; } -ParticlesDataMutable* readPDC(const char* filename, const bool headersOnly,const bool verbose){ +ParticlesDataMutable* readPDC(const char* filename, const bool headersOnly,std::ostream* errorStream){ auto_ptr input(Gzip_In(filename,std::ios::in|std::ios::binary)); if(!*input){ - if(verbose) std::cerr << "Partio: Unable to open file " << filename << std::endl; + if(errorStream) *errorStream << "Partio: Unable to open file " << filename << std::endl; return 0; } PDC_HEADER header; input->read((char*)&header, sizeof(header)); if(PDC_MAGIC != header.magic){ - std::cerr << "Partio: Magic number '" << header.magic << "' of '" << filename << "' doesn't match pdc magic '" << PDC_MAGIC << "'" << std::endl; + if(errorStream) *errorStream << "Partio: Magic number '" << header.magic << "' of '" << filename << "' doesn't match pdc magic '" << PDC_MAGIC << "'" << std::endl; return 0; } @@ -127,14 +127,14 @@ ParticlesDataMutable* readPDC(const char* filename, const bool headersOnly,const return simple; } -bool writePDC(const char* filename,const ParticlesData& p,const bool compressed){ +bool writePDC(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream){ auto_ptr output( compressed ? Gzip_Out(filename,ios::out|ios::binary) :new std::ofstream(filename,ios::out|ios::binary)); if(!*output){ - cerr << "Partio Unable to open file " << filename << endl; + if(errorStream) *errorStream << "Partio Unable to open file " << filename << endl; return false; } diff --git a/src/lib/io/PRT.cpp b/src/lib/io/PRT.cpp index 4d16b19a..a3d6e351 100644 --- a/src/lib/io/PRT.cpp +++ b/src/lib/io/PRT.cpp @@ -95,7 +95,7 @@ static f_ui half2float[65536] = { }; #endif -static bool read_buffer(std::istream& is, z_stream& z, char* in_buf, void* p, size_t size) { +static bool read_buffer(std::istream& is, z_stream& z, char* in_buf, void* p, size_t size, std::ostream* errorStream) { z.next_out=(Bytef*)p; z.avail_out=(uInt)size; @@ -105,7 +105,7 @@ static bool read_buffer(std::istream& is, z_stream& z, char* in_buf, void* p, si z.next_in = (Bytef*)in_buf; is.read((char*)z.next_in, OUT_BUFSIZE); if (is.bad()) { - std::cerr<<"read error "< input(new std::ifstream(filename,std::ios::in|std::ios::binary)); if (!*input) { - if(verbose) std::cerr<<"Partio: Unable to open file "<read((char*)&header,sizeof(FileHeadder)); if (memcmp(header.magic, magic, sizeof(magic))) { - std::cerr<<"Partio: failed to get PRT magic"<numParticles();particleIndex++) { // Read the particle from the file, and decompress it into a single particle-sized buffer. - read_buffer(*input, z, (char*)in_buf, prt_buf, particleSize); + read_buffer(*input, z, (char*)in_buf, prt_buf, particleSize, errorStream); for (unsigned int attrIndex=0;attrIndex(attrs[attrIndex],particleIndex); - if (!write_buffer(*output, z, (char*)out_buf, (void*)data, sizeof(int)*attrs[attrIndex].count, false)) + if (!write_buffer(*output, z, (char*)out_buf, (void*)data, sizeof(int)*attrs[attrIndex].count, false, errorStream)) return false; } else if (attrs[attrIndex].type==Partio::FLOAT || attrs[attrIndex].type==Partio::VECTOR) { const float* data=p.data(attrs[attrIndex],particleIndex); - if (!write_buffer(*output, z, (char*)out_buf, (void*)data, sizeof(int)*attrs[attrIndex].count, false)) + if (!write_buffer(*output, z, (char*)out_buf, (void*)data, sizeof(int)*attrs[attrIndex].count, false, errorStream)) return false; } } } - write_buffer(*output, z, (char*)out_buf, 0, 0, true); + write_buffer(*output, z, (char*)out_buf, 0, 0, true, errorStream); if (deflateEnd( &z ) != Z_OK) { - std::cerr<<"Zlib deflateEnd error"< input(Gzip_In(filename,ios::in|ios::binary)); if(!*input){ - if(verbose) cerr<<"Partio: Unable to open file "<(*input,magic); if(ptc_magic!=magic){ - cerr<<"Partio: Magic number '"<(*input,version); if(version>2){ - cerr<<"Partio: ptc reader only supports version 2 or less"<release(); return 0; } @@ -181,7 +181,7 @@ ParticlesDataMutable* readPTC(const char* filename,const bool headersOnly,const parsedSize+=dataSize; } if(dataSize!=parsedSize){ - cerr<<"Partio: error with PTC, computed dataSize ("<release(); return 0; @@ -233,7 +233,7 @@ ParticlesDataMutable* readPTC(const char* filename,const bool headersOnly,const return simple; } -bool writePTC(const char* filename,const ParticlesData& p,const bool compressed) +bool writePTC(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) { //ofstream output(filename,ios::out|ios::binary); @@ -243,7 +243,7 @@ bool writePTC(const char* filename,const ParticlesData& p,const bool compressed) :new ofstream(filename,ios::out|ios::binary)); if(!*output){ - cerr<<"Partio Unable to open file "<(*output,nVars,dataSize); for(unsigned int i=0;i input(Gzip_In(filename,ios::in|ios::binary)); if (!*input) { - if(verbose) cerr<<"Partio: Can't open particle data file: "<::iterator i=readers().find(extension); if(i==readers().end()){ - cerr<<"Partio: No reader defined for extension "<second)(c_filename,false,verbose); + return (*i->second)(c_filename,false,verbose ? &errorStream : 0); } ParticlesInfo* -readHeaders(const char* c_filename,bool verbose) +readHeaders(const char* c_filename,bool verbose,std::ostream& errorStream) { string filename(c_filename); string extension; bool endsWithGz; - if(!extensionIgnoringGz(filename,extension,endsWithGz)) return 0; + if(!extensionIgnoringGz(filename,extension,endsWithGz,errorStream)) return 0; map::iterator i=readers().find(extension); if(i==readers().end()){ - cerr<<"Partio: No reader defined for extension "<second)(c_filename,true,verbose); + return (*i->second)(c_filename,true,verbose ? &errorStream : 0); } void -write(const char* c_filename,const ParticlesData& particles,const bool forceCompressed) +write(const char* c_filename,const ParticlesData& particles,const bool forceCompressed,bool verbose,std::ostream& errorStream) { string filename(c_filename); string extension; bool endsWithGz; - if(!extensionIgnoringGz(filename,extension,endsWithGz)) return; + if(!extensionIgnoringGz(filename,extension,endsWithGz,errorStream)) return; map::iterator i=writers().find(extension); if(i==writers().end()){ - cerr<<"Partio: No writer defined for extension "<second)(c_filename,particles,forceCompressed || endsWithGz); + (*i->second)(c_filename,particles,forceCompressed || endsWithGz,verbose ? &errorStream : 0); } } // namespace Partio diff --git a/src/lib/io/RIB.cpp b/src/lib/io/RIB.cpp index a646e44d..3225a6a2 100644 --- a/src/lib/io/RIB.cpp +++ b/src/lib/io/RIB.cpp @@ -36,7 +36,7 @@ namespace Partio using namespace std; -bool writeRIB(const char* filename, const ParticlesData& p, const bool compressed) +bool writeRIB(const char* filename, const ParticlesData& p, const bool compressed,std::ostream* errorStream) { auto_ptr output( compressed ? Gzip_Out(filename, ios::out | ios::binary) @@ -49,12 +49,12 @@ bool writeRIB(const char* filename, const ParticlesData& p, const bool compresse if (!foundP) { - cerr << "Partio: failed to find attr 'position' or 'P' for RIB output" << endl; + if(errorStream) *errorStream << "Partio: failed to find attr 'position' or 'P' for RIB output" << endl; return false; } if (!foundWidth) - cerr << "Partio: failed to find attr 'width','radius', or 'radiusPP' for RIB output, using constantwidth = 1" << endl; + if(errorStream) *errorStream << "Partio: failed to find attr 'width','radius', or 'radiusPP' for RIB output, using constantwidth = 1" << endl; *output << "version 3.04" << endl; diff --git a/src/lib/io/readers.h b/src/lib/io/readers.h index a91a2f14..0e8d60d1 100644 --- a/src/lib/io/readers.h +++ b/src/lib/io/readers.h @@ -36,30 +36,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. #define _READERS_h_ namespace Partio{ -ParticlesDataMutable* readBGEO( const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readGEO( const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readPDB( const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readPDB32(const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readPDB64(const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readPDA( const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readMC( const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readPTC( const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readPDC( const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readPRT( const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readBIN( const char* filename,const bool headersOnly,const bool verbose); -ParticlesDataMutable* readPTS( const char* filename,const bool headersOnly,const bool verbose); +ParticlesDataMutable* readBGEO( const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readGEO( const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readPDB( const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readPDB32(const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readPDB64(const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readPDA( const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readMC( const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readPTC( const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readPDC( const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readPRT( const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readBIN( const char* filename,const bool headersOnly,std::ostream* errorStream); +ParticlesDataMutable* readPTS( const char* filename,const bool headersOnly,std::ostream* errorStream); -bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed); -bool writeGEO(const char* filename,const ParticlesData& p,const bool compressed); -bool writePDB(const char* filename,const ParticlesData& p,const bool compressed); -bool writePDB32(const char* filename,const ParticlesData& p,const bool compressed); -bool writePDB64(const char* filename,const ParticlesData& p,const bool compressed); -bool writePDA(const char* filename,const ParticlesData& p,const bool compressed); -bool writePTC(const char* filename,const ParticlesData& p,const bool compressed); -bool writeRIB(const char* filename,const ParticlesData& p,const bool compressed); -bool writePDC(const char* filename,const ParticlesData& p,const bool compressed); -bool writePRT(const char* filename,const ParticlesData& p,const bool compressed); -bool writeBIN(const char* filename,const ParticlesData& p,const bool compressed); +bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); +bool writeGEO(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); +bool writePDB(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); +bool writePDB32(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); +bool writePDB64(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); +bool writePDA(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); +bool writePTC(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); +bool writeRIB(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); +bool writePDC(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); +bool writePRT(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); +bool writeBIN(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream); } #endif diff --git a/src/py/partio.i b/src/py/partio.i index c5ebeca7..90d795e6 100644 --- a/src/py/partio.i +++ b/src/py/partio.i @@ -37,10 +37,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. %module partio %include "std_string.i" - %{ #include #include +#include namespace Partio{ typedef uint64_t ParticleIndex; } @@ -498,12 +498,47 @@ ParticlesDataMutable* create(); %feature("autodoc"); %feature("docstring","Reads a particle set from disk"); %newobject read; -ParticlesDataMutable* read(const char* filename); +ParticlesDataMutable* read(const char* filename,bool verbose=true,std::ostream& error=std::cerr); + +%inline %{ + template PyObject* readHelper(T* ptr,std::stringstream& ss){ + PyObject* tuple=PyTuple_New(2); + PyObject* instance = SWIG_NewPointerObj(SWIG_as_voidptr(ptr), SWIGTYPE_p_ParticlesDataMutable, SWIG_POINTER_OWN); + PyTuple_SetItem(tuple,0,instance); + PyTuple_SetItem(tuple,1,PyString_FromString(ss.str().c_str())); + return tuple; + } +%} +%feature("docstring","Reads a particle set from disk and returns the tuple particleObject,errorMsg"); +%inline %{ + PyObject* readVerbose(const char* filename){ + std::stringstream ss; + ParticlesDataMutable* ptr=read(filename,true,ss); + return readHelper(ptr,ss); + } +%} +%feature("docstring","Reads the header/attribute information from disk and returns the tuple particleObject,errorMsg"); +%inline %{ + PyObject* readHeadersVerbose(const char* filename){ + std::stringstream ss; + ParticlesInfo* ptr=readHeaders(filename,true,ss); + return readHelper(ptr,ss); + } +%} +%feature("docstring","Reads the header/attribute information from disk and returns the tuple particleObject,errorMsg"); +%inline %{ + PyObject* readCachedVerbose(const char* filename,bool sort){ + std::stringstream ss; + ParticlesData* ptr=readCached(filename,sort,true,ss); + return readHelper(ptr,ss); + } +%} + %feature("autodoc"); %feature("docstring","Reads a particle set headers from disk"); %newobject readHeaders; -ParticlesInfo* readHeaders(const char* filename); +ParticlesInfo* readHeaders(const char* filename,bool verbose=true,std::ostream& error=std::cerr); %feature("autodoc"); %feature("docstring","Writes a particle set to disk"); From 6c8c1a8b1a3f4fdd0848240e98754753b98fe880 Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Thu, 30 Jul 2015 15:38:02 -0700 Subject: [PATCH 26/52] Makefile: use the correct prefix --- Makefile | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 84b72f64..363fd61e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ #!/usr/bin/env make -#prefix ?= $(CURDIR)/$(shell uname)-$(shell fa.arch -r)-$(shell uname -m)-optimize -prefix ?= $(CURDIR)/$(shell uname)-$(shell fa.arch -r)-$(shell uname -m) +FLAVOR ?= optimize +prefix ?= $(CURDIR)/$(shell uname)-$(shell fa.arch -r)-$(shell uname -m)-$(FLAVOR) DESTDIR = CXX ?= g++ CXXFLAGS ?= @@ -8,10 +8,6 @@ CXXFLAGS ?= install: @echo "Installing $(prefix)" scons --prefix="$(DESTDIR)$(prefix)" CXX=$(CXX) CXXFLAGS=$(CXXFLAGS) - #echo "bin" > ${DESTDIR}${prefix}/.release.partio - #echo "lib64" >> ${DESTDIR}${prefix}/.release.partio - #echo "share" >> ${DESTDIR}${prefix}/.release.partio - #echo "include" >> ${DESTDIR}${prefix}/.release.partio clean: scons -c --prefix="$(DESTDIR)$(prefix)" From b52bd175110cd59aedcde9d52559edc73cb6c3c1 Mon Sep 17 00:00:00 2001 From: Lawrence Chai Date: Fri, 8 Jan 2016 14:00:23 -0800 Subject: [PATCH 27/52] instructions for updating repo from github --- UPDATE | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 UPDATE diff --git a/UPDATE b/UPDATE new file mode 100644 index 00000000..97d57931 --- /dev/null +++ b/UPDATE @@ -0,0 +1,6 @@ +1. fetch github-wdas/master +2. reset master from github-wdas master +3. push master to origin/master (origin/master should be identical to github-wdas/master at this point) +4. merge master into disney +5. push disney to origin/disney (do this without creating code review branch: + git push origin disney:disney) From 3df3da49eb2ff0c00f3c54e3f5f31fdb51ea5bb9 Mon Sep 17 00:00:00 2001 From: Lawrence Chai Date: Mon, 25 Jan 2016 13:35:52 -0800 Subject: [PATCH 28/52] install _partio jira: FXSOFT-807 Errors in stage rendering dealing with partio --- src/py/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/py/CMakeLists.txt b/src/py/CMakeLists.txt index 73afd6b2..872b3579 100644 --- a/src/py/CMakeLists.txt +++ b/src/py/CMakeLists.txt @@ -62,9 +62,10 @@ SET_SOURCE_FILES_PROPERTIES(partio.i PROPERTIES CPLUSPLUS ON) SET_SOURCE_FILES_PROPERTIES(partio.i PROPERTIES SWIG_FLAGS "-includeall") LINK_DIRECTORIES(${SEEXPR_LINK_PATH}) SWIG_ADD_MODULE(partio python partio.i) -SWIG_LINK_LIBRARIES(partio ${PYTHON_LIBRARIES} ${ZLIB_LIBRARY} partio ${SEEXPR_LIBS}) +SWIG_LINK_LIBRARIES(partio ${PYTHON_LIBRARIES} ${ZLIB_LIBRARY} partio partioSe ${SEEXPR_LIBS}) SET(PYTHON_DEST "${CMAKE_INSTALL_LIBDIR}/python${PYTHON_VERSION}/site-packages" ) +INSTALL(TARGETS _partio DESTINATION ${PYTHON_DEST}) INSTALL(FILES ${CMAKE_BINARY_DIR}/${outdir}/py/partio.py DESTINATION ${PYTHON_DEST}) INSTALL(FILES partio.i DESTINATION share/swig) From a48cbbd0e08e62ee86a5b11a87df36836ab4d7cd Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Tue, 18 Apr 2017 13:36:28 -0700 Subject: [PATCH 29/52] python: allow access to fixed attribute info --- src/py/partio.i | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/py/partio.i b/src/py/partio.i index aa8658b2..7b029758 100644 --- a/src/py/partio.i +++ b/src/py/partio.i @@ -83,6 +83,23 @@ public: //int attributeIndex; }; +%feature("docstring","A handle for operating on fixed attribbutes of a particle set"); +class FixedAttribute +{ +public: + %feature("docstring","Type of the particle data (VECTOR,INT,FLOAT)"); + ParticleAttributeType type; + + %feature("docstring","Number of primitives (int's or float's)"); + int count; + + %feature("docstring","Attribute name"); + std::string name; + + // internal use + //int attributeIndex; +}; + %typemap(in) uint64_t { $1 = (uint64_t) PyLong_AsLong($input); @@ -451,7 +468,7 @@ public: %feature("autodoc"); %feature("docstring","Searches for and returns the attribute handle for a named fixed attribute"); - %newobject attributeInfo; + %newobject fixedAttributeInfo; FixedAttribute* fixedAttributeInfo(const char* name) { FixedAttribute a; @@ -477,7 +494,7 @@ public: %feature("autodoc"); %feature("docstring","Returns the fixed attribute handle by index"); - %newobject attributeInfo; + %newobject fixedAttributeInfo; FixedAttribute* fixedAttributeInfo(const int index) { if(index<0 || index>=$self->numFixedAttributes()){ From 371b14713eb8f3973432237a0def1a04f9a8eee5 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Fri, 27 Apr 2018 15:57:53 -0700 Subject: [PATCH 30/52] Update example to actually work --- src/py/example/listAttr.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/py/example/listAttr.py b/src/py/example/listAttr.py index f21e5279..054fa32f 100644 --- a/src/py/example/listAttr.py +++ b/src/py/example/listAttr.py @@ -34,7 +34,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. import sys -import papi +import partio if __name__=="__main__": filename=None @@ -45,13 +45,13 @@ sys.exit(1) # read particle name - p=papi.read(filename) + p=partio.read(filename) for i in range(p.numAttributes()): attr=p.attributeInfo(i) typeStr="NONE" - if attr.type==papi.VECTOR: typeStr="VECTOR" - if attr.type==papi.FLOAT: typeStr="FLOAT" - if attr.type==papi.INT: typeStr="INT" + if attr.type==partio.VECTOR: typeStr="VECTOR" + if attr.type==partio.FLOAT: typeStr="FLOAT" + if attr.type==partio.INT: typeStr="INT" print "%10s[%d] %-30s "%(typeStr,attr.count,attr.name) From 93030071297e9edd1db4570e34e4827632822b72 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Fri, 27 Apr 2018 15:58:19 -0700 Subject: [PATCH 31/52] partedit - A spreadsheet for editing partio data --- CMakeLists.txt | 2 + src/tools/CMakeLists.txt | 2 + src/tools/partedit.py | 790 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 794 insertions(+) create mode 100644 src/tools/partedit.py diff --git a/CMakeLists.txt b/CMakeLists.txt index fdab4181..66b24034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,8 @@ IF(NOT CMAKE_BUILD_TYPE) "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) ENDIF(NOT CMAKE_BUILD_TYPE) +find_package(dcmake REQUIRED) +wdas_setup() ## Set install location IF (NOT DEFINED CMAKE_INSTALL_PREFIX) diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 3856f754..520b6e00 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -53,4 +53,6 @@ target_link_libraries(partconv ${PARTIO_LIBRARIES}) ADD_EXECUTABLE(partattr partattr.cpp) target_link_libraries(partattr ${PARTIO_LIBRARIES}) +install(PROGRAMS partedit.py DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME partedit) + install(TARGETS partattr partconv partinfo DESTINATION bin) diff --git a/src/tools/partedit.py b/src/tools/partedit.py new file mode 100644 index 00000000..c01cc12c --- /dev/null +++ b/src/tools/partedit.py @@ -0,0 +1,790 @@ +#!/usr/bin/env python + +""" +An interactive spreadsheet for viewing, editing, and saving +partio (bgeo) files. + +Usage: + % partedit [FLAGS] [bgeoFile] + +Supported FLAGS: + -h/--help: Print this help message + +""" + +# TODO: +# Tooltips on column headers with attribute info +# Support for indexed strings +# Tighten up whitespace usage (smaller font? popup matrix?) +# Hook into aurora gui + +__copyright__ = """ +CONFIDENTIAL INFORMATION: This software is the confidential and +proprietary information of Walt Disney Animation Studios ("WDAS"). +This software may not be used, disclosed, reproduced or distributed +for any purpose without prior written authorization and license +from WDAS. Reproduction of any section of this software must +include this legend and all copyright notices. +Copyright Disney Enterprises, Inc. All rights reserved. +""" + +import os, sys, math +import partio + +# pylint:disable=E0611,E0401 +from Qt.QtGui import QKeySequence, QIcon, QIntValidator, QDoubleValidator +from Qt.QtWidgets import QShortcut, QApplication, QMainWindow, \ + QPushButton, QTableWidget, QLabel, QWidget, QVBoxLayout, QHeaderView,\ + QHBoxLayout, QLineEdit, QFileDialog, QFrame, QDialog, QFormLayout, \ + QComboBox, QCheckBox, QTableWidgetItem +from Qt.QtCore import Qt, QSize, QObject#, pyqtSignal +from PyQt5.QtCore import pyqtSignal + +#------------------------------------------------------------------------------ +def copy(srcData): + """ Creates a copy of the given partio data set """ + + dstData = partio.create() + srcAttrs = [] + dstAttrs = [] + for anum in range(srcData.numAttributes()): + attr = srcData.attributeInfo(anum) + srcAttrs.append(attr) + dstAttrs.append(dstData.addAttribute(attr.name, attr.type, attr.count)) + dstData.addParticles(srcData.numParticles()) + for pnum in range(srcData.numParticles()): + for anum, srcAttr in enumerate(srcAttrs): + dstData.set(dstAttrs[anum], pnum, srcData.get(srcAttr, pnum)) + return dstData + +#------------------------------------------------------------------------------ +#------------------------------------------------------------------------------ +class ParticleData(QObject): + """ UI Controller class for partio data """ + + particleAdded = pyqtSignal(int) + attributeAdded = pyqtSignal(str) + dataReset = pyqtSignal() + dirtied = pyqtSignal(bool) + + def __init__(self): + QObject.__init__(self) + self.setData(partio.create()) + self.filename = None + self.dirty = False + + #-------------------------------------------------------------------------- + def setDirty(self, dirty): + """ Stores the dirty state of the data """ + + if dirty != self.dirty: + self.dirty = dirty + self.dirtied.emit(dirty) + + #-------------------------------------------------------------------------- + def setData(self, data): + """ Sets the data, linking class methods to partio methods and + notifying all observers that the data set has changed. + """ + self.data = data + self.originalData = copy(data) + self.facade() + self.dataReset.emit() + + #-------------------------------------------------------------------------- + def facade(self): + """ Facades methods through to data """ + + self.get = self.data.get + self.numAttributes = self.data.numAttributes + self.numParticles = self.data.numParticles + self.attributeInfo = self.data.attributeInfo + + #-------------------------------------------------------------------------- + def set(self, *args): + """ Sets a value on the partio data, marking dirty. """ + + self.setDirty(True) + self.data.set(*args) + + #-------------------------------------------------------------------------- + def read(self, filename): + """ Opens a file from disk and populates the UI """ + + if not os.path.exists(filename): + print 'Invalid filename: {}'.format(filename) + return + + self.filename = filename + self.setData(partio.read(filename)) + self.setDirty(False) + + #-------------------------------------------------------------------------- + def write(self, filename, delta): + """ Write data to file. If delta is False, saves a full copy + of the data, rebaselining. If delta is True, saves only + the particles (todo: and attributes) that have changed, + but maintains the original baseline + """ + + if not self.data: + return + + # If we're saving a delta, create a new particle set with just + # the differences from the original. + if delta: + data = self.createDelta() + else: + data = self.data + + partio.write(filename, data) + + # If we saved a full copy, rebaseline + if not delta: + self.filename = filename + self.originalData = copy(data) + self.setDirty(False) + + #-------------------------------------------------------------------------- + def createDelta(self): + """ Creates a delta particle set between the current and original + data set. This is the brute-force method, simply comparing the + current data set against the original, but it's easier than + tracking individual changes. + """ + + def hashParticles(data): + """ Given a partio data set, create a dictionary of hashes + to indices + """ + items = {} + numAttrs = data.numAttributes() + for pnum in range(data.numParticles()): + item = [] + for anum in range(numAttrs): + attr = data.attributeInfo(anum) + item.append(data.get(attr, pnum)) + items[hash(str(item))] = pnum + return items + + # TODO: Handle new attributes as deltas + # For now, any new attributes will write all of the particles + + # Hash up the new data into an index table + newParticles = hashParticles(self.data) + oldParticles = hashParticles(self.originalData) + + # If nothing changed, easy out + data = partio.create() + if newParticles == oldParticles: + return data + + # Identify which particles changed + oldHashes = set(oldParticles.keys()) + newHashes = set(newParticles.keys()) + modifiedHashes = newHashes - oldHashes + + # Create the new particle set + numAttrs = self.data.numAttributes() + newAttrs = [] + oldAttrs = [] + for anum in range(numAttrs): + attr = self.data.attributeInfo(anum) + oldAttrs.append(attr) + newAttr = data.addAttribute(attr.name, attr.type, attr.count) + newAttrs.append(newAttr) + + data.addParticles(len(modifiedHashes)) + for newIndex, modifiedHash in enumerate(modifiedHashes): + oldIndex = newParticles[modifiedHash] + for anum, oldAttr in enumerate(oldAttrs): + value = self.data.get(oldAttr, oldIndex) + data.set(newAttrs[anum], newIndex, value) + + return data + + #-------------------------------------------------------------------------- + def addParticle(self): + """ Adds a new particle, emitting its new index. + The new particle's values are copied from the last particle. + If the particle set has the 'id' attribute, the new + particle id is set to max(ids)+1. + """ + + if not self.data: + return + + numParticles = self.numParticles() + index = self.data.addParticle() + numAttr = self.numAttributes() + + idAttr = self.attributeInfo('id') + if idAttr: + newId = max(self.data.get(idAttr, pnum)[0] for pnum in range(numParticles)) + 1 + + for anum in range(numAttr): + attr = self.attributeInfo(anum) + if idAttr and attr.name == 'id': + value = (newId,) + else: + value = self.get(attr, numParticles-1) + self.set(attr, numParticles, value) + + self.particleAdded.emit(index) + self.setDirty(True) + + #-------------------------------------------------------------------------- + def removeParticles(self, indices): + """ Removes the particles at the given indices. + partio doesn't support removing data, so we have + to construct all new data sans the given particle + """ + + attributes = [self.data.attributeInfo(anum) for anum in range(self.data.numAttributes())] + + want = [pnum for pnum in range(self.data.numParticles()) if pnum not in indices ] + newData = partio.create() + for attr in attributes: + newData.addAttribute(attr.name, attr.type, attr.count) + newData.addParticles(len(want)) + for i, idx in enumerate(want): + for attr in attributes: + newData.set(attr, i, self.data.get(attr, idx)) + + self.setData(newData) + self.setDirty(True) + + #-------------------------------------------------------------------------- + def addAttribute(self, name, attrType, count, fixed, defaultValue): + """ Adds a new attribute for the particles, returning a + handle to the new attribute. + """ + + if fixed: + attr = self.data.addFixedAttribute(name, attrType, count) + else: + attr = self.data.addAttribute(name, attrType, count) + + if not isinstance(defaultValue, tuple): + defaultValue = (defaultValue,) + for pnum in range(self.numParticles()): + self.data.set(attr, pnum, defaultValue) + + self.attributeAdded.emit(attr.name) + self.setDirty(True) + + #-------------------------------------------------------------------------- + def removeAttributes(self, names): + """ Removes the attributes at the given indices. + partio doesn't support removing data, so we have + to construct all new data sans the given attribute. + """ + + newData = partio.create() + attributes = [] + for anum in range(self.numAttributes()): + attr = self.attributeInfo(anum) + if attr.name not in names: + attributes.append(attr) + + newData = partio.create() + + # Create new attributes for the new partio set + attrs = [newData.addAttribute(attr.name, attr.type, attr.count) for attr in attributes] + + # Populate the particles + numParticles = self.data.numParticles() + newData.addParticles(numParticles) + for pnum in range(numParticles): + for anum, attr in enumerate(attrs): + # Set new attribute but pull from old attribute + newData.set(attr, pnum, self.data.get(attributes[anum], pnum)) + + self.setData(newData) + self.setDirty(True) + + +#------------------------------------------------------------------------------ +class NumericalEdit(QLineEdit): # pylint:disable=R0903 + """ A LineEdit that auto installs a validator for numerical types """ + + def __init__(self, value, parent=None): + QLineEdit.__init__(self, str(value), parent) + self.setAlignment(Qt.AlignRight) + if isinstance(value, int): + self.setValidator(QIntValidator()) + elif isinstance(value, float): + self.setValidator(QDoubleValidator()) + + +#------------------------------------------------------------------------------ +class AttrWidget(QFrame): # pylint:disable=R0903 + """ The primary widget for table entries representing a particle attribute """ + + widgetNumber = 0 + + def __init__(self, value, data, attr, particleNum, numColumns, parent=None): + QWidget.__init__(self, parent) + self.value = value + self.data = data + self.attr = attr + self.particleNum = particleNum + self.setFrameShape(QFrame.NoFrame) + + self.name = 'AttrWidget{}'.format(AttrWidget.widgetNumber) + self.setObjectName(self.name) + AttrWidget.widgetNumber += 1 + self.withBorderStyle = '#%s {border: 1px solid blue;}' % self.name + self.noBorderStyle = '#%s {border: 0px;}' % self.name + self.setStyleSheet(self.noBorderStyle) + + layout = QVBoxLayout() + layout.setContentsMargins(0,0,0,0) + self.setLayout(layout) + + idx = 0 + self.items = [] + numRows = int(math.ceil(len(value) / float(numColumns))) + for _ in range(numRows): + row = QHBoxLayout() + layout.addLayout(row) + for _ in range(numColumns): + item = NumericalEdit(value[idx]) + item.editingFinished.connect(self.applyEdit) + row.addWidget(item, Qt.AlignHCenter|Qt.AlignTop) + self.items.append(item) + idx += 1 + if idx == len(self.value): + break + + #-------------------------------------------------------------------------- + def applyEdit(self): + """ Callback when editing finished on a cell. Sets data value. """ + + newValue = [] + for item in self.items: + text = item.text() + if isinstance(self.value[0], int): + newValue.append(int(text)) + else: + newValue.append(float(text)) + item.clearFocus() + self.value = tuple(newValue) + self.data.set(self.attr, self.particleNum, self.value) + self.drawBorder(True) + + #-------------------------------------------------------------------------- + def drawBorder(self, border): + """ Sets or clears the border around the frame """ + + if border: + self.setStyleSheet(self.withBorderStyle) + else: + self.setStyleSheet(self.noBorderStyle) + +#------------------------------------------------------------------------------ +def getWidget(value, data, attr, particleNum): + """ Returns the correct type of QWidget based off of the item type """ + + if isinstance(value, tuple): + size = len(value) + if size == 16: + result = AttrWidget(value, data, attr, particleNum, 4) + else: + result = AttrWidget(value, data, attr, particleNum, size) + else: + result = QLabel(str(value)) + return result + + +#------------------------------------------------------------------------------ +#------------------------------------------------------------------------------ +class ParticleTableWidget(QTableWidget): # pylint:disable=R0903 + """ A QTableWidget interfacing with ParticleData""" + + def __init__(self, data, parent=None): + QTableWidget.__init__(self, parent) + self.data = data + + # Connect data signals to my slots + self.data.particleAdded.connect(self.particleAddedSlot) + self.data.attributeAdded.connect(self.attributeAddedSlot) + self.data.dataReset.connect(self.dataResetSlot) + self.data.dirtied.connect(self.dataDirtiedSlot) + + style = 'QTableWidget::item { border: 1px solid gray; }' + self.setStyleSheet(style) + self.ignoreSignals = False + self.populate() + + #-------------------------------------------------------------------------- + def populate(self): + """ Populate the table with the data """ + + self.clear() + + numAttr = self.data.numAttributes() + numParticles = self.data.numParticles() + + self.getAttrs(True) + self.setColumnCount(numAttr) + self.setRowCount(numParticles) + self.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive) + for col, (_, attr) in enumerate(self.attrs): + self.setHorizontalHeaderItem(col, QTableWidgetItem(attr.name)) + #self.horizontalHeader().setSectionResizeMode(col, QHeaderView.ResizeToContents) + self.horizontalHeader().setStretchLastSection(False) + self.setVerticalHeaderLabels([str(pnum+1) for pnum in range(numParticles)]) + self.setTabKeyNavigation(True) + self.horizontalHeader().setSectionsMovable(False) + + # Populate it with the particle data + self.widgets = [] + for pnum in range(numParticles): + self.populateParticle(pnum) + + self.horizontalHeader().resizeSections(QHeaderView.ResizeToContents) + self.verticalHeader().resizeSections(QHeaderView.ResizeToContents) + + #-------------------------------------------------------------------------- + def populateParticle(self, pnum, border=False): + """ Populates the table with a new particle - a full row """ + + for col, (_, attr) in enumerate(self.attrs): + self.populateAttribute(pnum, col, attr, border) + + #-------------------------------------------------------------------------- + def populateAttribute(self, pnum, col, attr, border=False): + """ Populates a single cell in the table """ + + value = self.data.get(attr, pnum) + widget = getWidget(value, self.data, attr, pnum) + if border: + widget.drawBorder(border) + self.setCellWidget(pnum, col, widget) + self.widgets.append(widget) + + #-------------------------------------------------------------------------- + def getAttrs(self, sort=False): + """ Return list of tuples of (attributeNum, attribute) """ + attrs = [] + numAttr = self.data.numAttributes() + + nameToIndex = {self.data.attributeInfo(anum).name:anum for anum in range(numAttr)} + names = nameToIndex.keys() + if sort: + names.sort() + + id_offset = 0 + for name in names: + anum = nameToIndex[name] + attr = self.data.attributeInfo(anum) + if sort and attr.name == 'id': + attrs.insert(0, (anum, attr)) + id_offset += 1 + elif sort and 'id' in attr.name: + attrs.insert(id_offset, (anum, attr)) + id_offset += 1 + else: + attrs.append((anum, attr)) + + self.attrs = attrs + + #-------------------------------------------------------------------------- + def keyPressEvent(self, event): + """ Handles certain keys """ + + if event.key() in (Qt.Key_Delete, Qt.Key_Backspace): + self.handleDeleteKey(event) + else: + QTableWidget.keyPressEvent(self, event) + + #-------------------------------------------------------------------------- + def handleDeleteKey(self, event): # pylint:disable=W0613 + """ Handles the delete or backspace key """ + + model = self.selectionModel() + rows = model.selectedRows() + columns = model.selectedColumns() + + if not rows and not columns: + return + + # Ignore signals as we rebuild + self.ignoreSignals = True + if rows: + particles = [row.row() for row in rows] + self.data.removeParticles(particles) + + if columns: + indices = [col.column() for col in columns] + attributes = [str(self.horizontalHeaderItem(index).text()) for index in indices] + self.data.removeAttributes(attributes) + + self.ignoreSignals = False + self.dataResetSlot() + + + #-------------------------------------------------------------------------- + def particleAddedSlot(self, index): # pylint:disable=W0613 + """ SLOT when a particle is added """ + + if self.ignoreSignals: + return + + numParticles = self.data.numParticles() + self.setRowCount(numParticles) + self.populateParticle(numParticles-1, True) + + #-------------------------------------------------------------------------- + def attributeAddedSlot(self, name): # pylint:disable=W0613 + """ SLOT when attribute is added """ + + numAttrs = self.data.numAttributes() + anum = numAttrs - 1 + name = str(name) # partio doesn't like unicode + attr = self.data.attributeInfo(name) + self.attrs.append((anum, attr)) + self.setColumnCount(numAttrs) + self.setHorizontalHeaderItem(numAttrs-1, QTableWidgetItem(attr.name)) + for pnum in range(self.data.numParticles()): + self.populateAttribute(pnum, anum, attr, True) + + #-------------------------------------------------------------------------- + def dataResetSlot(self): + """ SLOT when particle data is reconstructed """ + if not self.ignoreSignals: + self.populate() + + #-------------------------------------------------------------------------- + def dataDirtiedSlot(self, dirty): + """ SLOT when the particle data is dirtied or cleaned. + When cleaned, reset the style sheets on widgets for border. + """ + if not dirty: + for widget in self.widgets: + widget.drawBorder(False) + +#------------------------------------------------------------------------------ +#------------------------------------------------------------------------------ +class PartEdit(QMainWindow): + """ Main window / editor """ + + def __init__(self): + QMainWindow.__init__(self) + + self.data = ParticleData() + + toolbar = self.addToolBar("Test") + + openButton = QPushButton("") + openButton.setFlat(True) + openButton.setIconSize( QSize(32, 32) ) + openButton.setIcon(QIcon("/jobs2/soft/icons/dlight/open.png")) + openButton.setToolTip( "Open File" ) + toolbar.addWidget(openButton) + openButton.clicked.connect(self.openSlot) + QShortcut( QKeySequence(Qt.CTRL + Qt.Key_O), self, self.openSlot ) + + saveButton = QPushButton("") + saveButton.setFlat(True) + saveButton.setIconSize( QSize(32, 32) ) + saveButton.setIcon(QIcon("/jobs2/soft/icons/dlight/file_save.png")) + saveButton.setToolTip( "Save File" ) + toolbar.addWidget(saveButton) + saveButton.clicked.connect(self.saveSlot) + QShortcut( QKeySequence(Qt.CTRL + Qt.Key_S), self, self.saveSlot ) + + saveDeltaButton = QPushButton("") + saveDeltaButton.setFlat(True) + saveDeltaButton.setIconSize( QSize(32, 32) ) + saveDeltaButton.setIcon(QIcon("/jobs2/soft/icons/dlight/file_save_as.png")) + saveDeltaButton.setToolTip( "Save File As Delta" ) + toolbar.addWidget(saveDeltaButton) + saveDeltaButton.clicked.connect(self.saveDeltaSlot) + QShortcut( QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_S), self, self.saveDeltaSlot ) + + addParticleButton = QPushButton("Particle") + addParticleButton.setFlat(True) + addParticleButton.setIconSize( QSize(32, 32) ) + addParticleButton.setIcon(QIcon("/jobs2/soft/icons/shared/plus.png")) + addParticleButton.setToolTip( "Add Particle" ) + toolbar.addWidget(addParticleButton) + addParticleButton.clicked.connect(self.addParticleSlot) + + addAttributeButton = QPushButton("Attribute") + addAttributeButton.setFlat(True) + addAttributeButton.setIconSize( QSize(32, 32) ) + addAttributeButton.setIcon(QIcon("/jobs2/soft/icons/shared/plus.png")) + addAttributeButton.setToolTip( "Add Attribute" ) + toolbar.addWidget(addAttributeButton) + addAttributeButton.clicked.connect(self.addAttributeSlot) + + self.main = QWidget(self) + self.layout = QVBoxLayout(self.main) + self.main.setLayout(self.layout) + self.setCentralWidget(self.main) + + self.table = ParticleTableWidget(self.data, self) + self.layout.addWidget(self.table) + + self.data.dirtied.connect(self.dataDirtiedSlot) + + #-------------------------------------------------------------------------- + def openSlot(self): + """ Callback from Open button """ + + # TODO: Check for edits and prompt to save dirty + if self.data.filename: + dirname = os.path.dirname(self.data.filename) + else: + dirname = os.getcwd() + filename = QFileDialog.getOpenFileName(self, "Open particle file", dirname, "(*.bgeo *.bhclassic *.geo)") + if filename: + if isinstance(filename, tuple): + filename = filename[0] + self.open(str(filename)) + + #-------------------------------------------------------------------------- + def open(self, filename): + """ Opens a file from disk and populates the UI """ + + self.data.read(filename) + self.setWindowTitle(filename) + + #-------------------------------------------------------------------------- + def saveSlot(self): + """ Callback from Save button """ + self.save(False) + + #-------------------------------------------------------------------------- + def saveDeltaSlot(self): + """ Callback from Save-Delta button """ + self.save(True) + + #-------------------------------------------------------------------------- + def save(self, delta): + """ Saves the file, either as full or delta """ + filename = QFileDialog.getSaveFileName(self, "Save particle file", self.data.filename) + if isinstance(filename, tuple): + filename = filename[0] + filename = str(filename) + if not filename: + return + self.data.write(filename, delta) + + #-------------------------------------------------------------------------- + def addParticleSlot(self): + """ Adds a new particle (row) to the table """ + self.data.addParticle() + + #-------------------------------------------------------------------------- + def addAttributeSlot(self): + """ Adds a new attribute (column) to the table """ + + dialog = QDialog(self) + dialog.setModal(True) + dialog.setWindowTitle('Add Attribute') + + layout = QVBoxLayout() + dialog.setLayout(layout) + + types = {'Integer': partio.INT, + 'Float': partio.FLOAT, + 'Vector': partio.VECTOR, + } + form = QFormLayout() + nameBox = QLineEdit() + typeCombo = QComboBox() + for t in types: + typeCombo.addItem(t) + countBox = QLineEdit() + countBox.setValidator(QIntValidator()) + countBox.setText('1') + fixedCheckbox = QCheckBox() + valueBox = QLineEdit() + valueBox.setText('0') + form.addRow('Name:', nameBox) + form.addRow('Type:', typeCombo) + form.addRow('Count:', countBox) + form.addRow('Fixed:', fixedCheckbox) + form.addRow('Default Value:', valueBox) + layout.addLayout(form) + + buttons = QHBoxLayout() + layout.addLayout(buttons) + + add = QPushButton('Add') + add.clicked.connect(dialog.accept) + buttons.addWidget(add) + + cancel = QPushButton('Cancel') + cancel.clicked.connect(dialog.reject) + buttons.addWidget(cancel) + + if not dialog.exec_(): + return + + name = str(nameBox.text()) + if not name: + print 'Please supply a name for the new attribute' # TODO: prompt + return + + attrType = types[str(typeCombo.currentText())] + count = int(countBox.text()) + fixed = fixedCheckbox.isChecked() + if attrType == partio.INT: + value = int(valueBox.text()) + elif attrType == partio.FLOAT or attrType == partio.VECTOR: + value = float(valueBox.text()) # pylint:disable=R0204 + else: + value = 0.0 # pylint:disable=R0204 + value = tuple([value] * count) + + self.data.addAttribute(name, attrType, count, fixed, value) + + #-------------------------------------------------------------------------- + def dataDirtiedSlot(self, dirty): + """ Sets the window title with or without "*" for dirty state """ + + title = self.data.filename + if dirty: + title += '*' + self.setWindowTitle(title) + + +#---------------------------------------------------------------------------------------- +#---------------------------------------------------------------------------------------- +def main(): + """ Main """ + + # Process command-line arguments + filename = None + for arg in sys.argv[1:]: + if arg in ('-h', '--help'): + print __doc__ + sys.exit(0) + + filename = arg + + # Start up the QApplication + app = QApplication([]) + from minibar.gui import mbWidgetStyling + mbWidgetStyling.styleTheApplication() + window = PartEdit() + + # Open file if provided + if filename: + window.open(filename) + + window.show() + + # Configure ctrl-q to quit + QShortcut( QKeySequence(Qt.CTRL + Qt.Key_Q), window, window.close ) + + # Go + app.exec_() + + +if __name__ == '__main__': + main() From e412996dfbcd62fbec1581f1218a5134ff6037b0 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Mon, 30 Apr 2018 07:05:38 -0700 Subject: [PATCH 32/52] partedit: Added column tooltips --- src/tools/partedit.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/tools/partedit.py b/src/tools/partedit.py index c01cc12c..6cd54e1d 100644 --- a/src/tools/partedit.py +++ b/src/tools/partedit.py @@ -13,8 +13,8 @@ """ # TODO: -# Tooltips on column headers with attribute info # Support for indexed strings +# Support for fixed attributes # Tighten up whitespace usage (smaller font? popup matrix?) # Hook into aurora gui @@ -40,6 +40,15 @@ from Qt.QtCore import Qt, QSize, QObject#, pyqtSignal from PyQt5.QtCore import pyqtSignal +#------------------------------------------------------------------------------ +_attrTypeNames = ['None', 'Vector', 'Float', 'Integer', 'Indexed String'] +def attrTypeName(attrType): + """ Returns the attribute type as a string given its enumerated valued """ + try: + return _attrTypeNames[attrType] + except IndexError: + return 'invalid type index: {}'.format(attrType) + #------------------------------------------------------------------------------ def copy(srcData): """ Creates a copy of the given partio data set """ @@ -431,8 +440,11 @@ def populate(self): self.setRowCount(numParticles) self.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive) for col, (_, attr) in enumerate(self.attrs): - self.setHorizontalHeaderItem(col, QTableWidgetItem(attr.name)) - #self.horizontalHeader().setSectionResizeMode(col, QHeaderView.ResizeToContents) + item = QTableWidgetItem(attr.name) + tooltip = '

 Name: {}
 Type: {}
Count: {}

'.\ + format(attr.name, attrTypeName(attr.type), attr.count) + item.setToolTip(tooltip) + self.setHorizontalHeaderItem(col, item) self.horizontalHeader().setStretchLastSection(False) self.setVerticalHeaderLabels([str(pnum+1) for pnum in range(numParticles)]) self.setTabKeyNavigation(True) From 7b5bdf4b77e8175ede2508abcd90987c7bc1f0ce Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Mon, 30 Apr 2018 12:46:59 -0700 Subject: [PATCH 33/52] Install partedit as a module for reuse --- src/tools/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 520b6e00..2daa3812 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -56,3 +56,8 @@ target_link_libraries(partattr ${PARTIO_LIBRARIES}) install(PROGRAMS partedit.py DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME partedit) install(TARGETS partattr partconv partinfo DESTINATION bin) + +EXECUTE_PROCESS(COMMAND python -c "import sys;print('%s.%s'%sys.version_info[0:2])" + OUTPUT_VARIABLE PYTHON_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) +SET(PYTHON_DEST "${CMAKE_INSTALL_LIBDIR}/python${PYTHON_VERSION}/site-packages" ) +INSTALL(FILES partedit.py DESTINATION ${PYTHON_DEST}) From 23a7424c72af7b55894726546565e6b9c658cd6e Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Tue, 1 May 2018 13:06:49 -0700 Subject: [PATCH 34/52] partedit: Resize newly added particles/attributes --- src/tools/partedit.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/partedit.py b/src/tools/partedit.py index 6cd54e1d..cdd0c29b 100644 --- a/src/tools/partedit.py +++ b/src/tools/partedit.py @@ -343,7 +343,7 @@ def __init__(self, value, data, attr, particleNum, numColumns, parent=None): self.name = 'AttrWidget{}'.format(AttrWidget.widgetNumber) self.setObjectName(self.name) AttrWidget.widgetNumber += 1 - self.withBorderStyle = '#%s {border: 1px solid blue;}' % self.name + self.withBorderStyle = '#%s {border: 1px solid dodgerblue;}' % self.name self.noBorderStyle = '#%s {border: 0px;}' % self.name self.setStyleSheet(self.noBorderStyle) @@ -547,6 +547,7 @@ def particleAddedSlot(self, index): # pylint:disable=W0613 numParticles = self.data.numParticles() self.setRowCount(numParticles) self.populateParticle(numParticles-1, True) + self.verticalHeader().resizeSections(QHeaderView.ResizeToContents) #-------------------------------------------------------------------------- def attributeAddedSlot(self, name): # pylint:disable=W0613 @@ -561,6 +562,7 @@ def attributeAddedSlot(self, name): # pylint:disable=W0613 self.setHorizontalHeaderItem(numAttrs-1, QTableWidgetItem(attr.name)) for pnum in range(self.data.numParticles()): self.populateAttribute(pnum, anum, attr, True) + self.verticalHeader().resizeSections(QHeaderView.ResizeToContents) #-------------------------------------------------------------------------- def dataResetSlot(self): From 3178724f3a6c5f69cb5a8f4a9bd8937d7316245c Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Wed, 2 May 2018 15:28:33 -0700 Subject: [PATCH 35/52] partedit fixes - Don't traceback if non-partio file opened by accident - Recognize a true edit on a cell (was dirtying just clicking in and out) --- src/tools/partedit.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/tools/partedit.py b/src/tools/partedit.py index cdd0c29b..14334bd6 100644 --- a/src/tools/partedit.py +++ b/src/tools/partedit.py @@ -124,8 +124,13 @@ def read(self, filename): print 'Invalid filename: {}'.format(filename) return + data = partio.read(filename) + if not data: + print 'Invalid particle file:', filename + data = partio.create() + self.filename = filename - self.setData(partio.read(filename)) + self.setData(data) self.setDirty(False) #-------------------------------------------------------------------------- @@ -325,7 +330,6 @@ def __init__(self, value, parent=None): elif isinstance(value, float): self.setValidator(QDoubleValidator()) - #------------------------------------------------------------------------------ class AttrWidget(QFrame): # pylint:disable=R0903 """ The primary widget for table entries representing a particle attribute """ @@ -353,12 +357,14 @@ def __init__(self, value, data, attr, particleNum, numColumns, parent=None): idx = 0 self.items = [] + self.textValues = [] numRows = int(math.ceil(len(value) / float(numColumns))) for _ in range(numRows): row = QHBoxLayout() layout.addLayout(row) for _ in range(numColumns): item = NumericalEdit(value[idx]) + self.textValues.append(str(value[idx])) item.editingFinished.connect(self.applyEdit) row.addWidget(item, Qt.AlignHCenter|Qt.AlignTop) self.items.append(item) @@ -371,16 +377,20 @@ def applyEdit(self): """ Callback when editing finished on a cell. Sets data value. """ newValue = [] - for item in self.items: + changed = False + for i, item in enumerate(self.items): text = item.text() + if text != self.textValues[i]: + changed = True if isinstance(self.value[0], int): newValue.append(int(text)) else: newValue.append(float(text)) item.clearFocus() - self.value = tuple(newValue) - self.data.set(self.attr, self.particleNum, self.value) - self.drawBorder(True) + if changed: + self.value = tuple(newValue) + self.data.set(self.attr, self.particleNum, self.value) + self.drawBorder(True) #-------------------------------------------------------------------------- def drawBorder(self, border): From 25053396af94e5aa184187d53eb5e4be6cc4ac7d Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Thu, 17 May 2018 17:52:25 -0700 Subject: [PATCH 36/52] Fix Makefile to not put collection include before partio --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index c023800e..ea3086b4 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ SH ?= sh uname_S := $(shell $(SH) -c 'uname -s || echo kernel') uname_R := $(shell $(SH) -c 'uname -r | cut -d- -f1 || echo release') uname_M := $(shell $(SH) -c 'uname -m || echo machine') +lib ?= lib64 FLAVOR ?= optimize platformdir ?= $(uname_S)-$(uname_R)-$(uname_M)-$(FLAVOR) builddir ?= $(CURDIR)/build/$(platformdir) @@ -20,6 +21,11 @@ ifdef RP_SeExpr CMAKE_FLAGS += -DSEEXPR_BASE=$(RP_SeExpr) endif +ifdef RP_zlib + CMAKE_FLAGS += -DZLIB_INCLUDE_DIR=$(RP_zlib)/include + CMAKE_FLAGS += -DZLIB_LIBRARY_RELEASE=$(RP_zlib)/$(lib)/libz.so +endif + # The default target in this Makefile is... all:: From cd49311f78f880e2ced0b35ce695b5bb51c9be75 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Thu, 17 May 2018 17:55:51 -0700 Subject: [PATCH 37/52] Add .workonrc.py --- .workonrc.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .workonrc.py diff --git a/.workonrc.py b/.workonrc.py new file mode 100644 index 00000000..9cfbc246 --- /dev/null +++ b/.workonrc.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +import os, dshell + +from pathfinder import build +_opts = build.Options(absolute=True) + +shell = dshell.create() +shell.export('PARTIO', os.getcwd()) + +# Add to paths +test_dir = build.test('partio', opts=_opts) +shell.prepend('PATH', test_dir) +shell.prepend('PYTHONPATH', test_dir) From edae61752948dc9047d66a7586409d1ad10808cc Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Thu, 17 May 2018 17:54:39 -0700 Subject: [PATCH 38/52] Fix Partio::print() function It never incremented the iterator, so it always showed values from the first particle! --- src/lib/core/Particle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/Particle.cpp b/src/lib/core/Particle.cpp index 47f692ab..76ae71ee 100644 --- a/src/lib/core/Particle.cpp +++ b/src/lib/core/Particle.cpp @@ -181,7 +181,7 @@ print(const ParticlesData* particles) for(size_t k=0;k Date: Thu, 17 May 2018 17:55:36 -0700 Subject: [PATCH 39/52] Partio::print() needs a little love Better formatting for readability --- src/lib/core/Particle.cpp | 41 ++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/src/lib/core/Particle.cpp b/src/lib/core/Particle.cpp index 76ae71ee..dbba9039 100644 --- a/src/lib/core/Particle.cpp +++ b/src/lib/core/Particle.cpp @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. #include #include #include +#include namespace Partio{ std::string @@ -159,18 +160,27 @@ printAttr(const ParticlesData* p,const ParticleAttribute& attr,const int particl for(int k=0;k +getAttrs(const ParticlesData& particles) +{ + std::vector attrs(particles.numAttributes()); + for(int i=0;inumParticles()<numAttributes()< attrs; - for(int i=0;inumAttributes();i++){ - ParticleAttribute attr; - particles->attributeInfo(i,attr); - attrs.push_back(attr); - std::cout<<"attribute "< attrs = getAttrs(*particles); + for (const ParticleAttribute& attr : attrs) { + std::cout << "attribute " << attr.name + << " type=" << TypeName(attr.type) + << " count=" << attr.count << std::endl; } int numToPrint=std::min(10,particles->numParticles()); @@ -184,19 +194,32 @@ print(const ParticlesData* particles) for(int i=0;i(it)[c]; + for(int c=0;c(it)[c]; + } break; case INT: - for(int c=0;c(it)[c]; + for(int c=0;c(it)[c]<<","; + } break; case INDEXEDSTR: - for(int c=0;c(it)[c]; + for(int c=0;c(it)[c]<<","; + } break; } + if (attrs[k].count > 1) std::cout<<")"; + std::cout<<"\t"; } std::cout< Date: Thu, 17 May 2018 17:52:50 -0700 Subject: [PATCH 40/52] partedit: Row indices should be 0-based to match particle indices --- src/tools/partedit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/partedit.py b/src/tools/partedit.py index 14334bd6..f0d5ed4b 100644 --- a/src/tools/partedit.py +++ b/src/tools/partedit.py @@ -456,7 +456,7 @@ def populate(self): item.setToolTip(tooltip) self.setHorizontalHeaderItem(col, item) self.horizontalHeader().setStretchLastSection(False) - self.setVerticalHeaderLabels([str(pnum+1) for pnum in range(numParticles)]) + self.setVerticalHeaderLabels([str(pnum) for pnum in range(numParticles)]) self.setTabKeyNavigation(True) self.horizontalHeader().setSectionsMovable(False) From a83401c68d497c8d6932b6202a7091ea4cf2638f Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Thu, 17 May 2018 18:01:58 -0700 Subject: [PATCH 41/52] Toward FXSOFT-1129: Add Partio::merge() function void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::string& identifier=std::string()); Given a ParticleSetMutable, merges it with a second ParticleSet, copying particles and attributes that align with the base particle set. If an identifier is provided, that will be used as a key to replace the particle in the base set with the particle in the second set with the same identifier attribute value. If the identifier is not provided or the particle's attribute value is not found in the base set, a new particle is added. If used, the identifier must be a single INT. --- src/data/base.bgeo | Bin 0 -> 269 bytes src/data/delta.bgeo | Bin 0 -> 214 bytes src/lib/Partio.h | 13 ++++ src/lib/core/Particle.cpp | 143 ++++++++++++++++++++++++++++++++++++++ src/py/partio.i | 4 ++ src/tests/CMakeLists.txt | 7 +- src/tests/testmerge.cpp | 124 +++++++++++++++++++++++++++++++++ 7 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 src/data/base.bgeo create mode 100644 src/data/delta.bgeo create mode 100644 src/tests/testmerge.cpp diff --git a/src/data/base.bgeo b/src/data/base.bgeo new file mode 100644 index 0000000000000000000000000000000000000000..ac72cf4931985257406ff510d3a509bd93ed4399 GIT binary patch literal 269 zcmZ=tPt6ZwU|?W{Vju+vOmG$h0}}&FPG(vvkVXbfnJEm6Kmia21KTra&f58$Icwj* zz_5Sj%vp{KU||NBxE)XoB)1Q!1}eu0QV$Zh1L_6I*(2nb;Nn1Iz;e&h(xCd7!RkTc nk`OZ;jE#+ #include #include +#include + namespace Partio{ std::string @@ -225,5 +227,146 @@ print(const ParticlesData* particles) } } +template +struct AttributePair { + T base; + T delta; +}; + +void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::string& identifier) +{ + // Build a map from the identifier value to the particle index + // and locate the identifier attribute in the base. + // This assumes unique identifiers per particle. + std::unordered_map idToParticleIndex; + ParticleAttribute baseIdAttr; + bool baseHasIdentifier = base.attributeInfo(identifier.c_str(), baseIdAttr); + if (baseHasIdentifier) { + if (baseIdAttr.type == INT) { + for (int i=0; i(baseIdAttr,i)[0]] = i; + } + } else { + baseHasIdentifier = false; + } + } + + // Locate the identifier attribute in the delta + ParticleAttribute deltaIdAttr; + bool deltaHasIdentifier = delta.attributeInfo(identifier.c_str(), deltaIdAttr); + if (deltaHasIdentifier) { + deltaHasIdentifier &= deltaIdAttr.type == INT; + } + bool hasIdentifier = baseHasIdentifier && deltaHasIdentifier; + + // Identify the attributes to be copied (base present in delta) + std::vector> attrs; + std::vector indexStrAttrs; /* indexes into attrs */ + for (int i=0; i({std::move(baseAttr), std::move(deltaAttr)})); + } + } + + // Identify fixed attributes to override + for (int i=0; i(deltaAttr); + void *dst = base.fixedDataWrite(baseAttr); + std::memcpy(dst, src, size); + } + } + + // Identify fixed attributes to extend + for (int i=0; i(deltaAttr); + void *dst = base.fixedDataWrite(baseAttr); + std::memcpy(dst, src, size); + } + } + + // Merge the indexed strings. If the delta holds new strings for the same attribute, + // we have to re-index it and extend the base string list with the new strings. + // If the string exists in both, we still have to map the delta index to the base index. + std::unordered_map > stringToString; + for (size_t index : indexStrAttrs) { + const AttributePair& attr = attrs[index]; + + /* For each string in the delta, add to base if missing. And re-index. */ + const std::vector& baseStrs = base.indexedStrs(attr.base); + // Map source indices name->index for faster searching + std::unordered_map indexInBase; + for (size_t i=0; i& deltaStrs = delta.indexedStrs(attr.delta); + for (size_t i=0; isecond; + } else { + int newIndex = base.registerIndexedStr(attr.base, deltaStr.c_str()); + stringToString[attr.base.name][i] = newIndex; + } + } + } + + + // Loop through the delta particles and incorporate into the base + for (int i=0; i(deltaIdAttr, i)); + auto it = idToParticleIndex.find(idValue); + if (it != idToParticleIndex.end()) { + index = it->second; + } + } + if (index == -1) { + index = base.addParticle(); + } + + // Copy the attributes to the new/overridden particle + for (const AttributePair& attr : attrs) { + size_t size = Partio::TypeSize(attr.base.type) * attr.base.count; + void *dst = base.dataWrite(attr.base, index); + const void* src; + int* newIndices; + if (attr.base.type == INDEXEDSTR) { + newIndices = new int[attr.base.count]; + const int* indices = delta.data(attr.delta, i); + for (int j=0; j(attr.delta, i); + } + std::memcpy(dst, src, size); + } + } +} + } diff --git a/src/py/partio.i b/src/py/partio.i index 7b029758..b534769d 100644 --- a/src/py/partio.i +++ b/src/py/partio.i @@ -566,6 +566,10 @@ void write(const char* filename,const ParticlesData&,const bool=false); %feature("docstring","Print a summary of particle file"); void print(const ParticlesData* particles); +%feature("autodoc"); +%feature("docstring","Merge two particle sets"); +void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::string& identifier=std::string()); + class PartioSe{ public: PartioSe(ParticlesDataMutable* parts,const char* expr); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index c99f9002..7ec3511d 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -31,10 +31,11 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +require_disney_system_package(gtest) link_directories(${CMAKE_BINARY_DIR}/src/lib) -foreach(item testiterator test testcache testclonecopy teststr makecircle makeline testkdtree) +foreach(item testiterator test testcache testclonecopy teststr makecircle makeline testkdtree testmerge) ADD_EXECUTABLE(${item} "${item}.cpp") - target_link_libraries(${item} ${PARTIO_LIBRARIES}) - install(TARGETS ${item} DESTINATION share/partio/test) + target_link_libraries(${item} partio ${ZLIB_LIBRARY} gtest) #${PARTIO_LIBRARIES}) + install(TARGETS ${item} DESTINATION share/test/partio) endforeach(item) diff --git a/src/tests/testmerge.cpp b/src/tests/testmerge.cpp new file mode 100644 index 00000000..1ea5a56b --- /dev/null +++ b/src/tests/testmerge.cpp @@ -0,0 +1,124 @@ +/* +PARTIO SOFTWARE +Copyright 2010 Disney Enterprises, Inc. All rights reserved + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation +Studios" or the names of its contributors may NOT be used to +endorse or promote products derived from this software without +specific prior written permission from Walt Disney Pictures. + +Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED. +IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +*/ + + +#include +#include +#include + +using namespace Partio; + +// TODD - Create test base class to read in base and delta files +// and validate them, as well as release() on test completion. +// Add test to merge two particle sets without an identifier +// (should be fully additive) + +class PartioTest : public ::testing::Test { +public: + PartioTest() {} + virtual ~PartioTest() {} + + void SetUp() { + // Read in base and delta files + std::string datadir = std::string(getenv("PARTIO")) + "/src/data/"; + std::string base_geo = datadir + "base.bgeo"; + std::string delta_geo = datadir + "delta.bgeo"; + base = Partio::read(base_geo.c_str()); + delta = Partio::read(delta_geo.c_str()); + + // Validate each before merging (don't allow test data to change) + ASSERT_EQ(5, base->numParticles()); + ASSERT_EQ(3, delta->numParticles()); + ASSERT_TRUE(base->attributeInfo("life", base_life_attr)); + ASSERT_TRUE(delta->attributeInfo("life", delta_life_attr)); + ASSERT_TRUE(base->attributeInfo("position", base_pos_attr)); + ASSERT_TRUE(delta->attributeInfo("position", delta_pos_attr)); + for (int i=0; i<5; i++) { + ASSERT_EQ(base_values_life[i], base->data(base_life_attr, i)[0]); + ASSERT_EQ(base_values_posx[i], base->data(base_pos_attr, i)[0]); + } + for (int i=0; i<3; i++) { + ASSERT_EQ(delta_values_life[i], delta->data(delta_life_attr, i)[0]); + ASSERT_EQ(delta_values_posx[i], delta->data(delta_pos_attr, i)[0]); + } + } + + void TearDown() { + base->release(); + delta->release(); + } + + Partio::ParticlesDataMutable* base; + Partio::ParticlesDataMutable* delta; + ParticleAttribute base_life_attr, base_pos_attr; + ParticleAttribute delta_life_attr, delta_pos_attr; + std::vector base_values_life{ -1.2, -0.2, 0.8, 1.8, 2.8 }; + std::vector base_values_posx{ 0.0, 0.1, 0.2, 0.3, 0.4 }; + std::vector delta_values_life{ 1.0, 3.0, 5.0 }; + std::vector delta_values_posx{ 0.1, 0.3, 0.5 }; +}; + +TEST_F(PartioTest, merge) +{ + std::cout << "\nBase particle set:\n"; + Partio::print(base); + std::cout << "\nDelta particle set:\n"; + Partio::print(delta); + + // Do the merge + Partio::merge(*base, *delta, "id"); + std::cout << "\nMerged particle set:\n"; + Partio::print(base); + ASSERT_EQ(6, base->numParticles()); + std::vector expected_life({-1.2, 1.0, 0.8, 3.0, 2.8, 5.0}); + std::vector expected_posx({0.0, 0.1, 0.2, 0.3, 0.4, 0.5}); + for (int i=0; i<6; i++) { + ASSERT_EQ(expected_life[i], base->data(base_life_attr, i)[0]); + ASSERT_EQ(expected_posx[i], base->data(base_pos_attr, i)[0]); + } + + int numFixed = base->numFixedAttributes(); + ASSERT_EQ(3, numFixed); +} + +TEST_F(PartioTest, mergenoid) +{ +} + +int main(int argc, char* argv[]) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 36ef0af5b97be96b3488a020c8331fe8ac869403 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Mon, 21 May 2018 16:40:06 -0700 Subject: [PATCH 42/52] Expose functions to python partio::clone() PartioAttribute::TypeName() --- src/py/partio.i | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/py/partio.i b/src/py/partio.i index b534769d..670fdabb 100644 --- a/src/py/partio.i +++ b/src/py/partio.i @@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. #include #include #include +#include #include namespace Partio{ typedef uint64_t ParticleIndex; @@ -570,6 +571,14 @@ void print(const ParticlesData* particles); %feature("docstring","Merge two particle sets"); void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::string& identifier=std::string()); +%feature("autodoc"); +%feature("docstring","Clone a particle set"); +ParticlesDataMutable* clone(const ParticlesData& other, bool particles); + +%feature("autodoc"); +%feature("docstring","Return string name of given attribute type"); +std::string TypeName(ParticleAttributeType attrType); + class PartioSe{ public: PartioSe(ParticlesDataMutable* parts,const char* expr); From b7db341a1969ead13d869b803ec4a7396ee6aae5 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Tue, 22 May 2018 08:14:11 -0700 Subject: [PATCH 43/52] partedit: Add support for fixed attributes Can create them and set their value. Cannot yet rename or delete them. --- src/tools/partedit.py | 337 ++++++++++++++++++++++++++++++++---------- 1 file changed, 257 insertions(+), 80 deletions(-) diff --git a/src/tools/partedit.py b/src/tools/partedit.py index f0d5ed4b..07226233 100644 --- a/src/tools/partedit.py +++ b/src/tools/partedit.py @@ -13,10 +13,14 @@ """ # TODO: +# Support for fixed attribute delete and rename # Support for indexed strings -# Support for fixed attributes -# Tighten up whitespace usage (smaller font? popup matrix?) -# Hook into aurora gui +# Tighten up particle table whitespace usage (smaller font? popup matrix?) +# Performance - delay widget construction + +# NEXT UP: +# - delete fixed attribute +# - rename fixed attribute __copyright__ = """ CONFIDENTIAL INFORMATION: This software is the confidential and @@ -66,6 +70,53 @@ def copy(srcData): dstData.set(dstAttrs[anum], pnum, srcData.get(srcAttr, pnum)) return dstData +#-------------------------------------------------------------------------- +def getAttrs(numAttributesFunc, attributeInfoFunc, sort=False): + """ Return list of tuples of (attributeNum, attribute) """ + attrs = [] + numAttr = numAttributesFunc() + + nameToIndex = {attributeInfoFunc(anum).name:anum for anum in range(numAttr)} + names = nameToIndex.keys() + if sort: + names.sort() + + id_offset = 0 + for name in names: + anum = nameToIndex[name] + attr = attributeInfoFunc(anum) + if sort and attr.name == 'id': + attrs.insert(0, (anum, attr)) + id_offset += 1 + elif sort and 'id' in attr.name: + attrs.insert(id_offset, (anum, attr)) + id_offset += 1 + else: + attrs.append((anum, attr)) + + return attrs + +#-------------------------------------------------------------------------- +def copyParticles(src, dst): + """ Copy particles from src to dst. """ + + # Identify the attributes that are in both src and dst + srcAttrs = [src.attributeInfo(i) for i in range(src.numAttributes())] + dstAttrs = [dst.attributeInfo(i) for i in range(dst.numAttributes())] + srcAttrs = {attr.name:attr for attr in srcAttrs} + dstAttrs = {attr.name:attr for attr in dstAttrs} + attrs = {'src':[], 'dst':[]} + for name, srcAttr in srcAttrs.iteritems(): + if name in dstAttrs: + attrs['src'].append(srcAttr) + attrs['dst'].append(dstAttrs[name]) + + numParticles = src.numParticles() + dst.addParticles(numParticles) + for pnum in range(numParticles): + for anum in range(len(attrs)): + dst.set(attrs['dst'][anum], pnum, src.get(attrs['src'][anum], pnum)) + #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ class ParticleData(QObject): @@ -73,6 +124,7 @@ class ParticleData(QObject): particleAdded = pyqtSignal(int) attributeAdded = pyqtSignal(str) + fixedAttributeAdded = pyqtSignal(str) dataReset = pyqtSignal() dirtied = pyqtSignal(bool) @@ -105,9 +157,12 @@ def facade(self): """ Facades methods through to data """ self.get = self.data.get + self.getFixed = self.data.getFixed self.numAttributes = self.data.numAttributes + self.numFixedAttributes = self.data.numFixedAttributes self.numParticles = self.data.numParticles self.attributeInfo = self.data.attributeInfo + self.fixedAttributeInfo = self.data.fixedAttributeInfo #-------------------------------------------------------------------------- def set(self, *args): @@ -116,17 +171,24 @@ def set(self, *args): self.setDirty(True) self.data.set(*args) + #-------------------------------------------------------------------------- + def setFixed(self, *args): + """ Sets a fixed attribute value on the partio data, marking dirty. """ + + self.setDirty(True) + self.data.setFixed(*args) + #-------------------------------------------------------------------------- def read(self, filename): """ Opens a file from disk and populates the UI """ if not os.path.exists(filename): - print 'Invalid filename: {}'.format(filename) + sys.stderr.write('Invalid filename: {}\n'.format(filename)) return data = partio.read(filename) if not data: - print 'Invalid particle file:', filename + sys.stderr.write('Invalid particle file: {}\n'.format(filename)) data = partio.create() self.filename = filename @@ -254,10 +316,12 @@ def removeParticles(self, indices): to construct all new data sans the given particle """ + for anum in range(self.data.numAttributes()): + attr = self.data.attributeInfo(anum) attributes = [self.data.attributeInfo(anum) for anum in range(self.data.numAttributes())] want = [pnum for pnum in range(self.data.numParticles()) if pnum not in indices ] - newData = partio.create() + newData = partio.clone(self.data, False) for attr in attributes: newData.addAttribute(attr.name, attr.type, attr.count) newData.addParticles(len(want)) @@ -274,50 +338,72 @@ def addAttribute(self, name, attrType, count, fixed, defaultValue): handle to the new attribute. """ + if not isinstance(defaultValue, tuple): + defaultValue = (defaultValue,) + if fixed: attr = self.data.addFixedAttribute(name, attrType, count) + self.data.setFixed(attr, defaultValue) + self.fixedAttributeAdded.emit(attr.name) else: attr = self.data.addAttribute(name, attrType, count) + for pnum in range(self.numParticles()): + self.data.set(attr, pnum, defaultValue) + self.attributeAdded.emit(attr.name) - if not isinstance(defaultValue, tuple): - defaultValue = (defaultValue,) - for pnum in range(self.numParticles()): - self.data.set(attr, pnum, defaultValue) - - self.attributeAdded.emit(attr.name) self.setDirty(True) #-------------------------------------------------------------------------- def removeAttributes(self, names): - """ Removes the attributes at the given indices. + """ Removes the attributes with the given names. partio doesn't support removing data, so we have - to construct all new data sans the given attribute. + to construct all new data sans the given attribute(s). """ newData = partio.create() - attributes = [] for anum in range(self.numAttributes()): attr = self.attributeInfo(anum) if attr.name not in names: - attributes.append(attr) + newData.addAttribute(attr.name, attr.type, attr.count) + + # Copy particle data with new attributes + copyParticles(src=self.data, dst=newData) + + # Copy fixed attributes + for anum in range(self.data.numFixedAttributes()): + oldAttr = self.data.fixedAttributeInfo(anum) + newAttr = newData.addFixedAttribute(oldAttr.name, oldAttr.type, oldAttr.count) + newData.setFixed(newAttr, self.data.getFixed(oldAttr)) + + self.setData(newData) + self.setDirty(True) + + + #-------------------------------------------------------------------------- + def removeFixedAttributes(self, names): + """ Removes the fixed attributes with the given names. + partio doesn't support removing data, so we have + to construct all new data sans the given attribute(s). + """ newData = partio.create() - # Create new attributes for the new partio set - attrs = [newData.addAttribute(attr.name, attr.type, attr.count) for attr in attributes] + # Copy the regular (non-fixed) attributes and particles + for anum in range(self.data.numAttributes()): + attr = self.attributeInfo(anum) + newData.addAttribute(attr.name, attr.type, attr.count) + copyParticles(src=self.data, dst=newData) - # Populate the particles - numParticles = self.data.numParticles() - newData.addParticles(numParticles) - for pnum in range(numParticles): - for anum, attr in enumerate(attrs): - # Set new attribute but pull from old attribute - newData.set(attr, pnum, self.data.get(attributes[anum], pnum)) + # Create new fixed attributes + for anum in range(self.data.numFixedAttributes()): + srcAttr = self.fixedAttributeInfo(anum) + if srcAttr.name not in names: + dstAttr = newData.addFixedAttribute(srcAttr.name, srcAttr.type, srcAttr.count) + newData.setFixed(dstAttr, self.data.getFixed(srcAttr)) self.setData(newData) self.setDirty(True) - #------------------------------------------------------------------------------ class NumericalEdit(QLineEdit): # pylint:disable=R0903 """ A LineEdit that auto installs a validator for numerical types """ @@ -389,7 +475,10 @@ def applyEdit(self): item.clearFocus() if changed: self.value = tuple(newValue) - self.data.set(self.attr, self.particleNum, self.value) + if self.particleNum >= 0: + self.data.set(self.attr, self.particleNum, self.value) + else: + self.data.setFixed(self.attr, self.value) self.drawBorder(True) #-------------------------------------------------------------------------- @@ -402,8 +491,10 @@ def drawBorder(self, border): self.setStyleSheet(self.noBorderStyle) #------------------------------------------------------------------------------ -def getWidget(value, data, attr, particleNum): - """ Returns the correct type of QWidget based off of the item type """ +def getWidget(value, data, attr, particleNum=-1): + """ Returns the correct type of QWidget based off of the item type. + A particleNum<0 means a fixed attribute. + """ if isinstance(value, tuple): size = len(value) @@ -445,7 +536,7 @@ def populate(self): numAttr = self.data.numAttributes() numParticles = self.data.numParticles() - self.getAttrs(True) + self.attrs = getAttrs(self.data.numAttributes, self.data.attributeInfo, True) self.setColumnCount(numAttr) self.setRowCount(numParticles) self.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive) @@ -486,32 +577,6 @@ def populateAttribute(self, pnum, col, attr, border=False): self.setCellWidget(pnum, col, widget) self.widgets.append(widget) - #-------------------------------------------------------------------------- - def getAttrs(self, sort=False): - """ Return list of tuples of (attributeNum, attribute) """ - attrs = [] - numAttr = self.data.numAttributes() - - nameToIndex = {self.data.attributeInfo(anum).name:anum for anum in range(numAttr)} - names = nameToIndex.keys() - if sort: - names.sort() - - id_offset = 0 - for name in names: - anum = nameToIndex[name] - attr = self.data.attributeInfo(anum) - if sort and attr.name == 'id': - attrs.insert(0, (anum, attr)) - id_offset += 1 - elif sort and 'id' in attr.name: - attrs.insert(id_offset, (anum, attr)) - id_offset += 1 - else: - attrs.append((anum, attr)) - - self.attrs = attrs - #-------------------------------------------------------------------------- def keyPressEvent(self, event): """ Handles certain keys """ @@ -589,13 +654,99 @@ def dataDirtiedSlot(self, dirty): for widget in self.widgets: widget.drawBorder(False) +#------------------------------------------------------------------------------ +class FixedAttributesWidget(QWidget): + """ A widget for viewing/editing fixed attributes (non-varying) """ + + def __init__(self, data, parent=None): + QWidget.__init__(self, parent) + self.data = data + self.table = None + + vbox = QVBoxLayout() + self.setLayout(vbox) + title = QLabel('Fixed Attributes') + vbox.addWidget(title) + + self.frame = QFrame() + vbox.addWidget(self.frame) + self.vbox = QVBoxLayout() + self.frame.setLayout(self.vbox) + self.frame.setFrameShape(QFrame.Panel) + self.frame.setFrameShadow(QFrame.Sunken) + + self.table = QTableWidget() + self.table.horizontalHeader().hide() + self.vbox.addWidget(self.table) + self.table.hide() + + self.noAttrLabel = QLabel('No fixed attributes') + self.vbox.addWidget(self.noAttrLabel) + + + self.widgets = [] + self.populate() + + self.data.fixedAttributeAdded.connect(self.fixedAttributeAddedSlot) + self.data.dataReset.connect(self.dataResetSlot) + self.data.dirtied.connect(self.dataDirtiedSlot) + + def dataDirtiedSlot(self, dirty): + """ SLOT when the particle data is dirtied or cleaned.""" + if not dirty: + for widget in self.widgets: + widget.drawBorder(False) + + def dataResetSlot(self): + """ SLOT when particle data is reconstructed """ + self.populate() + + def fixedAttributeAddedSlot(self, name): #pylint:disable=W0613 + """ SLOT when a fixed attribute is added to the particle set """ + self.populate() + + def populate(self): + """ Populates the table of fixed attributes """ + + self.widgets = [] + + # If no widgets, just drop that in + numAttrs = self.data.numFixedAttributes() + if not numAttrs: + self.table.hide() + self.noAttrLabel.show() + return + + self.table.show() + self.noAttrLabel.hide() + self.table.setColumnCount(1) + self.table.setRowCount(numAttrs) + self.attrs = getAttrs(self.data.numFixedAttributes, self.data.fixedAttributeInfo, True) + + for row, (_, attr) in enumerate(self.attrs): + item = QTableWidgetItem(attr.name) + tooltip = '

 Name: {}
 Type: {}
Count: {}

'.\ + format(attr.name, attrTypeName(attr.type), attr.count) + item.setToolTip(tooltip) + self.table.setVerticalHeaderItem(row, item) + value = self.data.getFixed(attr) + widget = getWidget(value, self.data, attr) + self.table.setCellWidget(row, 0, widget) + self.widgets.append(widget) + self.table.horizontalHeader().setStretchLastSection(False) + self.table.setTabKeyNavigation(True) + self.table.horizontalHeader().setSectionsMovable(False) + + self.table.horizontalHeader().resizeSections(QHeaderView.ResizeToContents) + self.table.verticalHeader().resizeSections(QHeaderView.ResizeToContents) + #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ class PartEdit(QMainWindow): """ Main window / editor """ - def __init__(self): - QMainWindow.__init__(self) + def __init__(self, parent=None): + QMainWindow.__init__(self, parent) self.data = ParticleData() @@ -644,13 +795,25 @@ def __init__(self): toolbar.addWidget(addAttributeButton) addAttributeButton.clicked.connect(self.addAttributeSlot) - self.main = QWidget(self) - self.layout = QVBoxLayout(self.main) - self.main.setLayout(self.layout) - self.setCentralWidget(self.main) + mainWidget = QWidget(self) + hbox = QHBoxLayout(mainWidget) + mainWidget.setLayout(hbox) + self.setCentralWidget(mainWidget) + + particleTable = ParticleTableWidget(self.data, self) + hbox.addWidget(particleTable) - self.table = ParticleTableWidget(self.data, self) - self.layout.addWidget(self.table) + right = QWidget(self) + hbox.addWidget(right) + vbox = QVBoxLayout(right) + right.setLayout(vbox) + + fixedAttrWidget = FixedAttributesWidget(self.data, self) + vbox.addWidget(fixedAttrWidget) + + vbox.addStretch() + + # TODD: SCROLLABLE AREAS FOR EVERYTHING self.data.dirtied.connect(self.dataDirtiedSlot) @@ -663,7 +826,7 @@ def openSlot(self): dirname = os.path.dirname(self.data.filename) else: dirname = os.getcwd() - filename = QFileDialog.getOpenFileName(self, "Open particle file", dirname, "(*.bgeo *.bhclassic *.geo)") + filename = QFileDialog.getOpenFileName(self, "Open particle file", dirname, "(*.bgeo *.geo *.bhclassic *.ptc *.pdb)") if filename: if isinstance(filename, tuple): filename = filename[0] @@ -676,6 +839,12 @@ def open(self, filename): self.data.read(filename) self.setWindowTitle(filename) + #-------------------------------------------------------------------------- + def setData(self, particleSet): + """ Uses the given particle set as its data """ + + self.data.setData(particleSet) + #-------------------------------------------------------------------------- def saveSlot(self): """ Callback from Save button """ @@ -689,7 +858,12 @@ def saveDeltaSlot(self): #-------------------------------------------------------------------------- def save(self, delta): """ Saves the file, either as full or delta """ - filename = QFileDialog.getSaveFileName(self, "Save particle file", self.data.filename) + if self.data.filename: + filename = self.data.filename + else: + filename = os.getcwd() + filename = QFileDialog.getSaveFileName(self, "Save particle file", filename, + 'Particle Files (*.bgeo *.geo *.bhclassic *.ptc *.pdb );;All files(*)') if isinstance(filename, tuple): filename = filename[0] filename = str(filename) @@ -713,15 +887,12 @@ def addAttributeSlot(self): layout = QVBoxLayout() dialog.setLayout(layout) - types = {'Integer': partio.INT, - 'Float': partio.FLOAT, - 'Vector': partio.VECTOR, - } form = QFormLayout() nameBox = QLineEdit() typeCombo = QComboBox() - for t in types: - typeCombo.addItem(t) + for typeName in _attrTypeNames: + typeCombo.addItem(typeName) + typeCombo.setCurrentIndex(2) # Float countBox = QLineEdit() countBox.setValidator(QIntValidator()) countBox.setText('1') @@ -754,16 +925,22 @@ def addAttributeSlot(self): print 'Please supply a name for the new attribute' # TODO: prompt return - attrType = types[str(typeCombo.currentText())] + attrType = _attrTypeNames.index(str(typeCombo.currentText())) count = int(countBox.text()) fixed = fixedCheckbox.isChecked() - if attrType == partio.INT: - value = int(valueBox.text()) - elif attrType == partio.FLOAT or attrType == partio.VECTOR: - value = float(valueBox.text()) # pylint:disable=R0204 - else: - value = 0.0 # pylint:disable=R0204 - value = tuple([value] * count) + values = list(str(valueBox.text()).strip().split()) + for i in range(count): + if i < len(values): + value = values[i] + else: + value = values[-1] + if attrType == partio.INT or attrType == partio.INDEXEDSTR: + values[i] = int(value) + elif attrType == partio.FLOAT or attrType == partio.VECTOR: + values[i] = float(value) # pylint:disable=R0204 + else: + values[i] = 0.0 # pylint:disable=R0204 + value = tuple(values) self.data.addAttribute(name, attrType, count, fixed, value) From c653f52d6a25657a0e4abaa58227aac79a20416c Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Tue, 22 May 2018 09:58:34 -0700 Subject: [PATCH 44/52] partedit: Add support for viewing indexed strings Still cannot edit them. --- src/tools/partedit.py | 121 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 107 insertions(+), 14 deletions(-) diff --git a/src/tools/partedit.py b/src/tools/partedit.py index 07226233..d6f5ed7f 100644 --- a/src/tools/partedit.py +++ b/src/tools/partedit.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# pylint:disable=C0302 """ An interactive spreadsheet for viewing, editing, and saving @@ -44,14 +45,8 @@ from Qt.QtCore import Qt, QSize, QObject#, pyqtSignal from PyQt5.QtCore import pyqtSignal -#------------------------------------------------------------------------------ -_attrTypeNames = ['None', 'Vector', 'Float', 'Integer', 'Indexed String'] -def attrTypeName(attrType): - """ Returns the attribute type as a string given its enumerated valued """ - try: - return _attrTypeNames[attrType] - except IndexError: - return 'invalid type index: {}'.format(attrType) +#------------------------------------------------------------------------------_ +_attrTypes = [partio.NONE, partio.VECTOR, partio.FLOAT, partio.INT, partio.INDEXEDSTR] #------------------------------------------------------------------------------ def copy(srcData): @@ -163,6 +158,7 @@ def facade(self): self.numParticles = self.data.numParticles self.attributeInfo = self.data.attributeInfo self.fixedAttributeInfo = self.data.fixedAttributeInfo + self.indexedStrs = self.data.indexedStrs #-------------------------------------------------------------------------- def set(self, *args): @@ -543,7 +539,7 @@ def populate(self): for col, (_, attr) in enumerate(self.attrs): item = QTableWidgetItem(attr.name) tooltip = '

 Name: {}
 Type: {}
Count: {}

'.\ - format(attr.name, attrTypeName(attr.type), attr.count) + format(attr.name, partio.TypeName(attr.type), attr.count) item.setToolTip(tooltip) self.setHorizontalHeaderItem(col, item) self.horizontalHeader().setStretchLastSection(False) @@ -661,7 +657,6 @@ class FixedAttributesWidget(QWidget): def __init__(self, data, parent=None): QWidget.__init__(self, parent) self.data = data - self.table = None vbox = QVBoxLayout() self.setLayout(vbox) @@ -726,7 +721,7 @@ def populate(self): for row, (_, attr) in enumerate(self.attrs): item = QTableWidgetItem(attr.name) tooltip = '

 Name: {}
 Type: {}
Count: {}

'.\ - format(attr.name, attrTypeName(attr.type), attr.count) + format(attr.name, partio.TypeName(attr.type), attr.count) item.setToolTip(tooltip) self.table.setVerticalHeaderItem(row, item) value = self.data.getFixed(attr) @@ -740,6 +735,100 @@ def populate(self): self.table.horizontalHeader().resizeSections(QHeaderView.ResizeToContents) self.table.verticalHeader().resizeSections(QHeaderView.ResizeToContents) + +class IndexedStringsWidget(QWidget): + """ Holds the list of indexed string attributes """ + def __init__(self, data, parent=None): + QWidget.__init__(self, parent) + self.data = data + + vbox = QVBoxLayout() + self.setLayout(vbox) + title = QLabel('Indexed Strings') + vbox.addWidget(title) + + self.frame = QFrame() + vbox.addWidget(self.frame) + self.vbox = QVBoxLayout() + self.frame.setLayout(self.vbox) + self.frame.setFrameShape(QFrame.Panel) + self.frame.setFrameShadow(QFrame.Sunken) + + self.table = QTableWidget() + self.table.horizontalHeader().hide() + self.vbox.addWidget(self.table) + self.table.hide() + + self.noStringsLabel = QLabel('No indexed strings') + self.vbox.addWidget(self.noStringsLabel) + + self.widgets = [] + self.populate() + + self.data.attributeAdded.connect(self.attributeAddedSlot) + self.data.dataReset.connect(self.dataResetSlot) + self.data.dirtied.connect(self.dataDirtiedSlot) + + def dataDirtiedSlot(self, dirty): + """ SLOT when the particle data is dirtied or cleaned.""" + if not dirty: + for widget in self.widgets: + widget.drawBorder(False) + + def dataResetSlot(self): + """ SLOT when particle data is reconstructed """ + self.populate() + + def attributeAddedSlot(self, name): #pylint:disable=W0613 + """ SLOT when an attribute is added to the particle set """ + attr = self.data.attributeInfo(name) + if attr.type == partio.INDEXEDSTR: + self.populate() + + def populate(self): + """ Populates the table of indexed strings """ + + self.widgets = [] + + # If no widgets, just drop that in + attrs = [] + for anum in range(self.data.numAttributes()): + attr = self.data.attributeInfo(anum) + if attr.type == partio.INDEXEDSTR: + attrs.append(attr) + + if not attrs: + self.table.hide() + self.noStringsLabel.show() + return + + self.table.show() + self.noStringsLabel.hide() + self.table.setColumnCount(1) + self.table.setRowCount(len(attrs)) + + for row, attr in enumerate(attrs): + item = QTableWidgetItem(attr.name) + self.table.setVerticalHeaderItem(row, item) + strings = self.data.indexedStrs(attr) + table = QTableWidget() + table.setColumnCount(1) + table.setRowCount(len(strings)) + table.horizontalHeader().hide() + table.setVerticalHeaderLabels([str(i) for i in range(len(strings))]) + for i, string in enumerate(strings): + widget = QLabel(string) + table.setCellWidget(i, 0, widget) + self.widgets.append(widget) + self.table.setCellWidget(row, 0, table) + + self.table.horizontalHeader().setStretchLastSection(False) + self.table.setTabKeyNavigation(True) + self.table.horizontalHeader().setSectionsMovable(False) + + self.table.horizontalHeader().resizeSections(QHeaderView.ResizeToContents) + self.table.verticalHeader().resizeSections(QHeaderView.ResizeToContents) + #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ class PartEdit(QMainWindow): @@ -811,6 +900,9 @@ def __init__(self, parent=None): fixedAttrWidget = FixedAttributesWidget(self.data, self) vbox.addWidget(fixedAttrWidget) + indexedStrings = IndexedStringsWidget(self.data, self) + vbox.addWidget(indexedStrings) + vbox.addStretch() # TODD: SCROLLABLE AREAS FOR EVERYTHING @@ -890,9 +982,10 @@ def addAttributeSlot(self): form = QFormLayout() nameBox = QLineEdit() typeCombo = QComboBox() - for typeName in _attrTypeNames: + for attrType in _attrTypes: + typeName = partio.TypeName(attrType) typeCombo.addItem(typeName) - typeCombo.setCurrentIndex(2) # Float + typeCombo.setCurrentIndex(partio.FLOAT) countBox = QLineEdit() countBox.setValidator(QIntValidator()) countBox.setText('1') @@ -925,7 +1018,7 @@ def addAttributeSlot(self): print 'Please supply a name for the new attribute' # TODO: prompt return - attrType = _attrTypeNames.index(str(typeCombo.currentText())) + attrType = typeCombo.currentIndex() count = int(countBox.text()) fixed = fixedCheckbox.isChecked() values = list(str(valueBox.text()).strip().split()) From ca52151f7b1a41bbe5c33ab32d6552bbc402ec27 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Tue, 22 May 2018 10:02:28 -0700 Subject: [PATCH 45/52] partedit: Make main widget a splitter --- src/tools/partedit.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/tools/partedit.py b/src/tools/partedit.py index d6f5ed7f..d11d45bf 100644 --- a/src/tools/partedit.py +++ b/src/tools/partedit.py @@ -41,7 +41,7 @@ from Qt.QtWidgets import QShortcut, QApplication, QMainWindow, \ QPushButton, QTableWidget, QLabel, QWidget, QVBoxLayout, QHeaderView,\ QHBoxLayout, QLineEdit, QFileDialog, QFrame, QDialog, QFormLayout, \ - QComboBox, QCheckBox, QTableWidgetItem + QComboBox, QCheckBox, QTableWidgetItem, QSplitter from Qt.QtCore import Qt, QSize, QObject#, pyqtSignal from PyQt5.QtCore import pyqtSignal @@ -884,16 +884,14 @@ def __init__(self, parent=None): toolbar.addWidget(addAttributeButton) addAttributeButton.clicked.connect(self.addAttributeSlot) - mainWidget = QWidget(self) - hbox = QHBoxLayout(mainWidget) - mainWidget.setLayout(hbox) - self.setCentralWidget(mainWidget) + splitter = QSplitter(self) + self.setCentralWidget(splitter) particleTable = ParticleTableWidget(self.data, self) - hbox.addWidget(particleTable) + splitter.addWidget(particleTable) right = QWidget(self) - hbox.addWidget(right) + splitter.addWidget(right) vbox = QVBoxLayout(right) right.setLayout(vbox) From 46e645d08ef40f20e9db8b705de180954d149970 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Tue, 22 May 2018 08:14:47 -0700 Subject: [PATCH 46/52] partjson: Convert between bgeo and json (both ways) % partjson -h Converts partio files to and from json. Usage: partjson [FLAGS] Supported FLAGS: -c/--compress: When converting to partio, compress the output -v/--verbose : Turn on verbosity for partio -h/--help : Print this help message --- src/data/json.bgeo | Bin 0 -> 325 bytes src/tests/CMakeLists.txt | 2 + src/tests/testpartjson.py | 35 ++++++ src/tools/CMakeLists.txt | 3 + src/tools/partjson.py | 222 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 262 insertions(+) create mode 100644 src/data/json.bgeo create mode 100644 src/tests/testpartjson.py create mode 100644 src/tools/partjson.py diff --git a/src/data/json.bgeo b/src/data/json.bgeo new file mode 100644 index 0000000000000000000000000000000000000000..3346b369a09b7787046dd52c2bfcb1781a47f28f GIT binary patch literal 325 zcmYk1F%H5o3`KuSyYvQZxdL>iB@Bpx4GCsYQxqu>sbyf~8s#u>f%Y0)1ME;jEm?N{ zvmJYJRCWs>?wx|Skis=2GeN(J2vWA>x%X#vSUnub=>p*07v3LwEzGB literal 0 HcmV?d00001 diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 7ec3511d..d4c0c4c6 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -39,3 +39,5 @@ foreach(item testiterator test testcache testclonecopy teststr makecircle makeli target_link_libraries(${item} partio ${ZLIB_LIBRARY} gtest) #${PARTIO_LIBRARIES}) install(TARGETS ${item} DESTINATION share/test/partio) endforeach(item) + +install(PROGRAMS testpartjson.py DESTINATION share/test/partio RENAME testpartjson) diff --git a/src/tests/testpartjson.py b/src/tests/testpartjson.py new file mode 100644 index 00000000..de9eeb5d --- /dev/null +++ b/src/tests/testpartjson.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +""" +Test for partjson - back and forth +""" + +__copyright__ = """ +CONFIDENTIAL INFORMATION: This software is the confidential and +proprietary information of Walt Disney Animation Studios ("WDAS"). +This software may not be used, disclosed, reproduced or distributed +for any purpose without prior written authorization and license +from WDAS. Reproduction of any section of this software must +include this legend and all copyright notices. +Copyright Disney Enterprises, Inc. All rights reserved. +""" + +import os, unittest +import partjson, partio + + +class test(unittest.TestCase): + """ Test json conversions """ + + def testPartJson(self): + """ Test round-tripping """ + + filename = os.path.join(os.getenv('PARTIO'), 'src/data/json.bgeo') + particleSet = partio.read(filename) + json1 = partjson.toJson(particleSet) + particleSet2 = partjson.fromJson(json1) + json2 = partjson.toJson(particleSet2) + self.assertEquals(json1, json2) + +if __name__ == '__main__': + unittest.main() diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 2daa3812..f5fcc3eb 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -55,9 +55,12 @@ target_link_libraries(partattr ${PARTIO_LIBRARIES}) install(PROGRAMS partedit.py DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME partedit) +install(PROGRAMS partjson.py DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME partjson) + install(TARGETS partattr partconv partinfo DESTINATION bin) EXECUTE_PROCESS(COMMAND python -c "import sys;print('%s.%s'%sys.version_info[0:2])" OUTPUT_VARIABLE PYTHON_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) SET(PYTHON_DEST "${CMAKE_INSTALL_LIBDIR}/python${PYTHON_VERSION}/site-packages" ) INSTALL(FILES partedit.py DESTINATION ${PYTHON_DEST}) +INSTALL(FILES partjson.py DESTINATION ${PYTHON_DEST}) diff --git a/src/tools/partjson.py b/src/tools/partjson.py new file mode 100644 index 00000000..446344b1 --- /dev/null +++ b/src/tools/partjson.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python + +""" +Converts partio files to and from json. + +Usage: partjson [FLAGS] + +Supported FLAGS: + -c/--compress: When converting to partio, compress the output + -v/--verbose : Turn on verbosity for partio + -h/--help : Print this help message +""" + +__copyright__ = """ +CONFIDENTIAL INFORMATION: This software is the confidential and +proprietary information of Walt Disney Animation Studios ("WDAS"). +This software may not be used, disclosed, reproduced or distributed +for any purpose without prior written authorization and license +from WDAS. Reproduction of any section of this software must +include this legend and all copyright notices. +Copyright Disney Enterprises, Inc. All rights reserved. +""" + +import os, sys, json +import partio + +def toJson(particleSet): + """ Converts a particle set to json """ + + data = {} + + # Put types in json just for readability + data['__types__'] = { 0 : 'NONE', + 1 : 'VECTOR', + 2 : 'FLOAT', + 3 : 'INT', + 4 : 'INDEXED_STR', + } + + # Convert fixed attributes + fixedAttributes = {} + fixedIndexedStrings = {} + for i in range(particleSet.numFixedAttributes()): + attr = particleSet.fixedAttributeInfo(i) + fixedAttributes[attr.name] = {'type': attr.type, + 'count': attr.count, + 'value': particleSet.getFixed(attr), + } + + # Convert indexed string attributse + if attr.type == 4: + fixedIndexedStrings[attr.name] = particleSet.fixedIndexedStrs(attr) + + if fixedAttributes: + data['fixedAttributes'] = fixedAttributes + if fixedIndexedStrings: + data['fixedIndexedStrings'] = fixedIndexedStrings + + # Convert particle attributes + attributes = {} + attrs = [] + indexedStrings = {} + for i in range(particleSet.numAttributes()): + attr = particleSet.attributeInfo(i) + attrs.append(attr) + attributes[attr.name] = {'type': attr.type, 'count': attr.count } + + # Convert indexed string attributse + if attr.type == 4: + indexedStrings[attr.name] = particleSet.indexedStrs(attr) + + if attributes: + data['attributes'] = attributes + if indexedStrings: + data['indexedStrings'] = indexedStrings + + # Convert particles to an indexed dictionary + particles = {} + for i in range(particleSet.numParticles()): + particle = {} + for attr in attrs: + particle[attr.name] = particleSet.get(attr, i) + # Add an index purely for readability & debugging (not consumed converting back) + particles[i] = particle + + if particles: + data['particles'] = particles + + return data + + +def fromJson(data): + """ Converts a json dictionary to a particle set """ + + particleSet = partio.create() + + # Convert fixed attributes + fixedAttributes = {} + if 'fixedAttributes' in data: + for attrName, attrInfo in data['fixedAttributes'].iteritems(): + attrName = str(attrName) + attr = particleSet.addFixedAttribute(attrName, attrInfo['type'], attrInfo['count']) + fixedAttributes[attrName] = attr + if len(attrInfo['value']) == attrInfo['count']: + particleSet.setFixed(attr, attrInfo['value']) + else: + sys.stderr.write('Mismatched count for fixed attribute {}. Skipping.\n'.format(attrName)) + + # Convert attributes + attributes = {} + if 'attributes' in data: + for attrName, attrInfo in data['attributes'].iteritems(): + attrName = str(attrName) + attr = particleSet.addAttribute(attrName, attrInfo['type'], attrInfo['count']) + attributes[attrName] = attr + + # Convert fixed indexed strings + if 'fixedIndexedStrings' in data: + for attrName, strings in data['fixedIndexedStrings'].iteritems(): + if attrName not in fixedAttributes: + sys.stderr.write('Could not match fixed indexed string {} with any defined fixed attribute. Skipping.\n'.format(attrName)) + continue + for string in strings: + particleSet.registerFixedIndexedStr(fixedAttributes[attrName], string) + + # Convert indexed strings + if 'indexedStrings' in data: + for attrName, strings in data['indexedStrings'].iteritems(): + if attrName not in attributes: + sys.stderr.write('Could not match indexed string {} with any defined attribute. Skipping.\n'.format(attrName)) + continue + for string in strings: + particleSet.registerIndexedStr(attributes[attrName], str(string)) + + # Convert particles + if 'particles' in data: + particleSet.addParticles(len(data['particles'])) + for pnum, particle in data['particles'].iteritems(): + pnum = int(pnum) + for attrName, value in particle.iteritems(): + try: + attr = attributes[attrName] + except IndexError: + sys.stderr.write('Could not match attribute "{}" for particle {} with any defined attributes. Skipping.\n'.format(attrName, pnum)) + continue + if len(value) != attr.count: + sys.stderr.write('Mismatched count for attribute "{}" ({}) and particle {} ({}). Skipping.\n'.format(attrName, attr.count, pnum, len(value))) + continue + + particleSet.set(attr, pnum, value) + + return particleSet + +def main(): + """ Main """ + + # Process command-line arguments + filenames = [] + verbose = False + compress = False + for arg in sys.argv[1:]: + if arg in ('-h', '--help'): + print __doc__ + return + + if arg in ('-v', '--verbose'): + verbose = True + continue + + if arg in ('-c', '--compress'): + compress = True + continue + + filenames.append(arg) + + if len(filenames) != 2: + print __doc__ + sys.stderr.write('Incorrect number of arguments.\n') + sys.exit(1) + + file1, file2 = filenames[0:2] + ext1 = os.path.splitext(file1)[1] + ext2 = os.path.splitext(file2)[1] + + partio_extensions = ('.bgeo', '.geo', '.bhclassic', '.ptc', '.pdb') + + # Validate files + if not os.path.exists(file1): + sys.stderr.write('Invalid input file: {}\n'.format(file1)) + sys.exit(1) + + # Convert from json to partio + if ext1 == '.json': + if ext2 not in partio_extensions: + sys.stderr.write('Unknown partio extension for: {}\n'.format(file2)) + sys.exit(1) + + with open(file1, 'r') as fp: + data = json.load(fp) + particleSet = fromJson(data) + partio.write(file2, particleSet, compress) + sys.exit(0) + + if ext1 not in partio_extensions: + sys.stderr.write('Unknown partio extension for: {}\n'.format(file1)) + sys.exit(1) + + # Convert from partio to json + if ext1 in partio_extensions: + particleSet = partio.read(file1, verbose) + data = toJson(particleSet) + with open(file2, 'w') as fp: + json.dump(data, fp, indent=2, sort_keys=True) + sys.exit(0) + + print __doc__ + sys.stderr.write('Unknown file extension(s)') + sys.exit(1) + + +if __name__ == '__main__': + main() From 9943f019a56faedd27deb8bacd7cbeca9325b22e Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Tue, 22 May 2018 08:28:38 -0700 Subject: [PATCH 47/52] Add testSpecs for mentor run --- .gitignore | 9 +++++ src/tests/testSpecs.xml | 73 +++++++++++++++++++++++++++++++++++++++++ testSpecs.xml | 5 +++ 3 files changed, 87 insertions(+) create mode 100644 src/tests/testSpecs.xml create mode 100644 testSpecs.xml diff --git a/.gitignore b/.gitignore index f5c40a99..c4242994 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,12 @@ /bin /CMakeFiles Makefile +.mentor.* +report.html +/src/tests/testenv/*/test*.txt +/src/tests/testenv/*/test*-txt-diff.html +/src/tests/testenv/*/image* +/src/tests/testenv/*/*.bb +/src/tests/testenv/*/*geo* +/src/tests/testenv/*/*.ptc* +/src/tests/testenv/*/*.pdb* diff --git a/src/tests/testSpecs.xml b/src/tests/testSpecs.xml new file mode 100644 index 00000000..f6fdeea0 --- /dev/null +++ b/src/tests/testSpecs.xml @@ -0,0 +1,73 @@ + + + + + + Aurora API tests --------------------------------------------------------------------- + + + + Tests cached read + Unit + Checkin + Nightly + + + + + Tests copying and cloning a particle set + Unit + Checkin + Nightly + + + + + Tests various basics + Unit + Checkin + Nightly + + + + + Tests the particle iterator + Unit + Checkin + Nightly + + + + + Tests particle sorting + Unit + Checkin + Nightly + + + + + Tests merging a delta over a base + Unit + Checkin + Nightly + + + + + Tests converting a particle set to/from json + Unit + Checkin + Nightly + + + + + Tests string basics + Unit + Checkin + Nightly + + + + diff --git a/testSpecs.xml b/testSpecs.xml new file mode 100644 index 00000000..6d3fc9da --- /dev/null +++ b/testSpecs.xml @@ -0,0 +1,5 @@ + + + + + From d03ed52aeaf81bc02a0fb366296da3903195e19b Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Tue, 22 May 2018 10:46:17 -0700 Subject: [PATCH 48/52] Code review updates --- src/lib/core/Particle.cpp | 9 +++++---- src/tools/partjson.py | 25 +++++++++++-------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/lib/core/Particle.cpp b/src/lib/core/Particle.cpp index 9dd82d23..44fe621f 100644 --- a/src/lib/core/Particle.cpp +++ b/src/lib/core/Particle.cpp @@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. #include #include #include +#include namespace Partio{ @@ -351,14 +352,14 @@ void merge(ParticlesDataMutable& base, const ParticlesData& delta, const std::st size_t size = Partio::TypeSize(attr.base.type) * attr.base.count; void *dst = base.dataWrite(attr.base, index); const void* src; - int* newIndices; + std::unique_ptr newIndices; if (attr.base.type == INDEXEDSTR) { - newIndices = new int[attr.base.count]; + newIndices.reset(new int[attr.base.count]); const int* indices = delta.data(attr.delta, i); for (int j=0; j(attr.delta, i); diff --git a/src/tools/partjson.py b/src/tools/partjson.py index 446344b1..700ecbb7 100644 --- a/src/tools/partjson.py +++ b/src/tools/partjson.py @@ -11,6 +11,8 @@ -h/--help : Print this help message """ +# TODO: Unicode compliance + __copyright__ = """ CONFIDENTIAL INFORMATION: This software is the confidential and proprietary information of Walt Disney Animation Studios ("WDAS"). @@ -30,12 +32,7 @@ def toJson(particleSet): data = {} # Put types in json just for readability - data['__types__'] = { 0 : 'NONE', - 1 : 'VECTOR', - 2 : 'FLOAT', - 3 : 'INT', - 4 : 'INDEXED_STR', - } + data['__types__'] = { i : partio.TypeName(i) for i in range(5) } # Convert fixed attributes fixedAttributes = {} @@ -48,7 +45,7 @@ def toJson(particleSet): } # Convert indexed string attributse - if attr.type == 4: + if attr.type == partio.INDEXEDSTR: fixedIndexedStrings[attr.name] = particleSet.fixedIndexedStrs(attr) if fixedAttributes: @@ -66,7 +63,7 @@ def toJson(particleSet): attributes[attr.name] = {'type': attr.type, 'count': attr.count } # Convert indexed string attributse - if attr.type == 4: + if attr.type == partio.INDEXEDSTR: indexedStrings[attr.name] = particleSet.indexedStrs(attr) if attributes: @@ -97,7 +94,7 @@ def fromJson(data): # Convert fixed attributes fixedAttributes = {} if 'fixedAttributes' in data: - for attrName, attrInfo in data['fixedAttributes'].iteritems(): + for attrName, attrInfo in data['fixedAttributes'].items(): attrName = str(attrName) attr = particleSet.addFixedAttribute(attrName, attrInfo['type'], attrInfo['count']) fixedAttributes[attrName] = attr @@ -109,14 +106,14 @@ def fromJson(data): # Convert attributes attributes = {} if 'attributes' in data: - for attrName, attrInfo in data['attributes'].iteritems(): + for attrName, attrInfo in data['attributes'].items(): attrName = str(attrName) attr = particleSet.addAttribute(attrName, attrInfo['type'], attrInfo['count']) attributes[attrName] = attr # Convert fixed indexed strings if 'fixedIndexedStrings' in data: - for attrName, strings in data['fixedIndexedStrings'].iteritems(): + for attrName, strings in data['fixedIndexedStrings'].items(): if attrName not in fixedAttributes: sys.stderr.write('Could not match fixed indexed string {} with any defined fixed attribute. Skipping.\n'.format(attrName)) continue @@ -125,7 +122,7 @@ def fromJson(data): # Convert indexed strings if 'indexedStrings' in data: - for attrName, strings in data['indexedStrings'].iteritems(): + for attrName, strings in data['indexedStrings'].items(): if attrName not in attributes: sys.stderr.write('Could not match indexed string {} with any defined attribute. Skipping.\n'.format(attrName)) continue @@ -135,9 +132,9 @@ def fromJson(data): # Convert particles if 'particles' in data: particleSet.addParticles(len(data['particles'])) - for pnum, particle in data['particles'].iteritems(): + for pnum, particle in data['particles'].items(): pnum = int(pnum) - for attrName, value in particle.iteritems(): + for attrName, value in particle.items(): try: attr = attributes[attrName] except IndexError: From 93b1a1b1d1ac4269d9eb303b754e730743794102 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Tue, 22 May 2018 11:48:05 -0700 Subject: [PATCH 49/52] make test Removed mentor usage --- .gitignore | 9 ----- CMakeLists.txt | 2 ++ Makefile | 3 ++ src/tests/CMakeLists.txt | 5 +++ src/tests/testSpecs.xml | 73 ---------------------------------------- testSpecs.xml | 5 --- 6 files changed, 10 insertions(+), 87 deletions(-) delete mode 100644 src/tests/testSpecs.xml delete mode 100644 testSpecs.xml diff --git a/.gitignore b/.gitignore index c4242994..f5c40a99 100644 --- a/.gitignore +++ b/.gitignore @@ -21,12 +21,3 @@ /bin /CMakeFiles Makefile -.mentor.* -report.html -/src/tests/testenv/*/test*.txt -/src/tests/testenv/*/test*-txt-diff.html -/src/tests/testenv/*/image* -/src/tests/testenv/*/*.bb -/src/tests/testenv/*/*geo* -/src/tests/testenv/*/*.ptc* -/src/tests/testenv/*/*.pdb* diff --git a/CMakeLists.txt b/CMakeLists.txt index 66b24034..c573dc47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,8 @@ IF(NOT CMAKE_BUILD_TYPE) ENDIF(NOT CMAKE_BUILD_TYPE) find_package(dcmake REQUIRED) wdas_setup() +include(CTest) +enable_testing() ## Set install location IF (NOT DEFINED CMAKE_INSTALL_PREFIX) diff --git a/Makefile b/Makefile index ea3086b4..70628739 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,9 @@ all:: install: all $(MAKE) -C $(builddir) DESTDIR=$(DESTDIR) install +test: all + $(MAKE) -C $(builddir) DESTDIR=$(DESTDIR) test + $(builddir)/stamp: mkdir -p $(builddir) cd $(builddir) && cmake $(CMAKE_FLAGS) ../.. diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index d4c0c4c6..674ac963 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -40,4 +40,9 @@ foreach(item testiterator test testcache testclonecopy teststr makecircle makeli install(TARGETS ${item} DESTINATION share/test/partio) endforeach(item) + install(PROGRAMS testpartjson.py DESTINATION share/test/partio RENAME testpartjson) + +foreach(item testiterator test testcache testclonecopy teststr testkdtree testmerge testpartjson) + add_test(NAME ${item} COMMAND ${item}) +endforeach(item) diff --git a/src/tests/testSpecs.xml b/src/tests/testSpecs.xml deleted file mode 100644 index f6fdeea0..00000000 --- a/src/tests/testSpecs.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - Aurora API tests --------------------------------------------------------------------- - - - - Tests cached read - Unit - Checkin - Nightly - - - - - Tests copying and cloning a particle set - Unit - Checkin - Nightly - - - - - Tests various basics - Unit - Checkin - Nightly - - - - - Tests the particle iterator - Unit - Checkin - Nightly - - - - - Tests particle sorting - Unit - Checkin - Nightly - - - - - Tests merging a delta over a base - Unit - Checkin - Nightly - - - - - Tests converting a particle set to/from json - Unit - Checkin - Nightly - - - - - Tests string basics - Unit - Checkin - Nightly - - - - diff --git a/testSpecs.xml b/testSpecs.xml deleted file mode 100644 index 6d3fc9da..00000000 --- a/testSpecs.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - From 1c0c26be8ef2ead0480ed4e03080df6c7cc76883 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Wed, 23 May 2018 17:03:13 -0700 Subject: [PATCH 50/52] partedit: display attr size 9 as 3x3 matrix --- src/tools/partedit.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/partedit.py b/src/tools/partedit.py index d11d45bf..5ebe4de9 100644 --- a/src/tools/partedit.py +++ b/src/tools/partedit.py @@ -496,6 +496,8 @@ def getWidget(value, data, attr, particleNum=-1): size = len(value) if size == 16: result = AttrWidget(value, data, attr, particleNum, 4) + elif size == 9: + result = AttrWidget(value, data, attr, particleNum, 3) else: result = AttrWidget(value, data, attr, particleNum, size) else: From 838bfe47a68430c1599811c2c8b5f7cc213a3455 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Thu, 31 May 2018 08:30:11 -0700 Subject: [PATCH 51/52] Expose additional arg in partio::write() write() takes two bool arguments - compressed and verbose, but only one was exposed in Python. --- src/py/partio.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py/partio.i b/src/py/partio.i index 670fdabb..7de73259 100644 --- a/src/py/partio.i +++ b/src/py/partio.i @@ -561,7 +561,7 @@ ParticlesInfo* readHeaders(const char* filename,bool verbose=true,std::ostream& %feature("autodoc"); %feature("docstring","Writes a particle set to disk"); -void write(const char* filename,const ParticlesData&,const bool=false); +void write(const char* filename,const ParticlesData&,const bool=false,const bool=true); %feature("autodoc"); %feature("docstring","Print a summary of particle file"); From eee0a618c12cc0373e824c89896fd0c0487e9fd9 Mon Sep 17 00:00:00 2001 From: Todd Scopio Date: Thu, 31 May 2018 08:30:23 -0700 Subject: [PATCH 52/52] Add Ctrl-W shortcut to close editor window --- src/tools/partedit.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/tools/partedit.py b/src/tools/partedit.py index 5ebe4de9..9a6359bb 100644 --- a/src/tools/partedit.py +++ b/src/tools/partedit.py @@ -909,6 +909,11 @@ def __init__(self, parent=None): self.data.dirtied.connect(self.dataDirtiedSlot) + + # Configure ctrl-w to close the window + QShortcut( QKeySequence(Qt.CTRL + Qt.Key_W), self, self.close ) + + #-------------------------------------------------------------------------- def openSlot(self): """ Callback from Open button """