For another project, please consult its home page to locate the current issue tracker.
View Issue Details [ Jump to Notes ] | [ Print ] | ||||||||
ID | Project | Category | View Status | Date Submitted | Last Update | ||||
0009133 | ParaView | Bug | public | 2009-06-10 13:56 | 2010-05-04 20:02 | ||||
Reporter | Ken Moreland | ||||||||
Assigned To | Ken Moreland | ||||||||
Priority | immediate | Severity | minor | Reproducibility | have not tried | ||||
Status | closed | Resolution | fixed | ||||||
Platform | OS | OS Version | |||||||
Product Version | |||||||||
Target Version | 3.8 | Fixed in Version | 3.10 | ||||||
Summary | 0009133: Wireframe for quadratic faces is wrong | ||||||||
Description | When you turn on the wireframe for a data set that has quadratic elements, you get lines for all the internal edges created for the approximation. The wireframe should just be the lines around the actual cells. | ||||||||
Tags | No tags attached. | ||||||||
Project | |||||||||
Topic Name | |||||||||
Type | |||||||||
Attached Files | ![]() Index: Qt/Components/pqDisplayProxyEditor.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Qt/Components/pqDisplayProxyEditor.cxx,v retrieving revision 1.75 diff -u -r1.75 pqDisplayProxyEditor.cxx --- Qt/Components/pqDisplayProxyEditor.cxx 9 Jun 2009 17:33:32 -0000 1.75 +++ Qt/Components/pqDisplayProxyEditor.cxx 10 Jun 2009 22:25:02 -0000 @@ -384,6 +384,15 @@ "value", SIGNAL(editingFinished()), reprProxy, reprProxy->GetProperty("Opacity")); + // setup of nonlinear subdivision + if (reprProxy->GetProperty("NonlinearSubdivisionLevel")) + { + this->Internal->Links->addPropertyLink( + this->Internal->NonlinearSubdivisionLevel, + "value", SIGNAL(valueChanged(int)), + reprProxy, reprProxy->GetProperty("NonlinearSubdivisionLevel")); + } + // setup for map scalars this->Internal->Links->addPropertyLink( this->Internal->ColorMapScalars, "checked", SIGNAL(stateChanged(int)), Index: Qt/Components/Resources/UI/pqDisplayProxyEditor.ui =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui,v retrieving revision 1.42 diff -u -r1.42 pqDisplayProxyEditor.ui --- Qt/Components/Resources/UI/pqDisplayProxyEditor.ui 9 Jun 2009 17:33:32 -0000 1.42 +++ Qt/Components/Resources/UI/pqDisplayProxyEditor.ui 10 Jun 2009 22:25:02 -0000 @@ -669,14 +669,44 @@ </property> </spacer> </item> - <item row="7" column="0" > + <item row="7" column="0"> + <widget class="QLabel" name="label_17"> + <property name="text"> + <string>Subdivision</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QSpinBox" name="NonlinearSubdivisionLevel"> + <property name="toolTip"> + <string>Nonlinear faces are approximated with flat polygons. This parameter controls how many times to subdivide nonlinear surface cells. Higher subdivisions generate closer approximations but take more memory and rendering time. Subdivision is recursive, so the number of output polygons can grow exponentially with this parameter.</string> + </property> + <property name="maximum"> + <number>4</number> + </property> + </widget> + </item> + <item row="7" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="8" column="0" > <widget class="QLabel" name="label_19" > <property name="text" > <string>Volume mapper</string> </property> </widget> </item> - <item row="7" column="1" colspan="2" > + <item row="8" column="1" colspan="2" > <widget class="QComboBox" name="SelectedMapperIndex" > <property name="toolTip" > <string><html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:Sans Serif; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Choose the mapper to use for volume rendering.</p></body></html></string> @@ -1217,6 +1247,7 @@ <tabstop>StylePointSize</tabstop> <tabstop>StyleLineWidth</tabstop> <tabstop>Opacity</tabstop> + <tabstop>NonlinearSubdivisionLevel</tabstop> <tabstop>SelectedMapperIndex</tabstop> <tabstop>EdgeColor</tabstop> <tabstop>SpecularIntensity</tabstop> Index: Servers/Filters/CMakeLists.txt =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/Filters/CMakeLists.txt,v retrieving revision 1.195 diff -u -r1.195 CMakeLists.txt --- Servers/Filters/CMakeLists.txt 28 May 2009 19:02:11 -0000 1.195 +++ Servers/Filters/CMakeLists.txt 10 Jun 2009 22:25:02 -0000 @@ -98,6 +98,7 @@ vtkPVMain.cxx vtkPVMergeTables.cxx vtkPVNullSource.cxx + vtkPVRecoverGeometryWireframe.cxx vtkPVRenderViewProxy.cxx vtkPVScalarBarActor.cxx vtkPVSelectionSource.cxx Index: Servers/Filters/vtkPVGeometryFilter.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/Filters/vtkPVGeometryFilter.cxx,v retrieving revision 1.94 diff -u -r1.94 vtkPVGeometryFilter.cxx --- Servers/Filters/vtkPVGeometryFilter.cxx 8 May 2009 14:07:39 -0000 1.94 +++ Servers/Filters/vtkPVGeometryFilter.cxx 10 Jun 2009 22:25:02 -0000 @@ -18,6 +18,7 @@ #include "vtkCallbackCommand.h" #include "vtkCellArray.h" #include "vtkCellData.h" +#include "vtkCellTypes.h" #include "vtkCleanArrays.h" #include "vtkCommand.h" #include "vtkCompositeDataIterator.h" @@ -42,6 +43,7 @@ #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkPolygon.h" +#include "vtkPVRecoverGeometryWireframe.h" #include "vtkPVTrivialProducer.h" #include "vtkRectilinearGrid.h" #include "vtkRectilinearGridOutlineFilter.h" @@ -53,11 +55,15 @@ #include "vtkUnsignedCharArray.h" #include "vtkUnsignedIntArray.h" #include "vtkUnstructuredGrid.h" +#include "vtkUnstructuredGridGeometryFilter.h" #include <vtkstd/map> #include <vtkstd/string> #include <assert.h> +#define VTK_CREATE(type, name) \ + vtkSmartPointer<type> name = vtkSmartPointer<type>::New() + vtkCxxRevisionMacro(vtkPVGeometryFilter, "$Revision: 1.94 $"); vtkStandardNewMacro(vtkPVGeometryFilter); @@ -124,10 +130,12 @@ this->UseOutline = 1; this->UseStrips = 0; this->GenerateCellNormals = 1; + this->NonlinearSubdivisionLevel = 1; this->DataSetSurfaceFilter = vtkDataSetSurfaceFilter::New(); this->GenericGeometryFilter=vtkGenericGeometryFilter::New(); - + this->UnstructuredGridGeometryFilter=vtkUnstructuredGridGeometryFilter::New(); + // Setup a callback for the internal readers to report progress. this->InternalProgressObserver = vtkCallbackCommand::New(); this->InternalProgressObserver->SetCallback( @@ -154,13 +162,25 @@ //---------------------------------------------------------------------------- vtkPVGeometryFilter::~vtkPVGeometryFilter () { - if(this->DataSetSurfaceFilter) + // Be careful how you delete these so that you don't foul up the garbage + // collector. + if (this->DataSetSurfaceFilter) { - this->DataSetSurfaceFilter->Delete(); + vtkDataSetSurfaceFilter *tmp = this->DataSetSurfaceFilter; + this->DataSetSurfaceFilter = NULL; + tmp->Delete(); } - if(this->GenericGeometryFilter!=0) + if (this->GenericGeometryFilter) { - this->GenericGeometryFilter->Delete(); + vtkGenericGeometryFilter *tmp = this->GenericGeometryFilter; + this->GenericGeometryFilter = NULL; + tmp->Delete(); + } + if (this->UnstructuredGridGeometryFilter) + { + vtkUnstructuredGridGeometryFilter *tmp=this->UnstructuredGridGeometryFilter; + this->UnstructuredGridGeometryFilter = NULL; + tmp->Delete(); } this->OutlineSource->Delete(); this->InternalProgressObserver->Delete(); @@ -1009,7 +1029,71 @@ if (!this->UseOutline) { this->OutlineFlag = 0; + + bool handleSubdivision = false; + if (this->NonlinearSubdivisionLevel > 0) + { + // Check to see if the data actually has nonlinear cells. Handling + // nonlinear cells adds unnecessary work if we only have linear cells. + vtkUnsignedCharArray *types = input->GetCellTypesArray(); + vtkIdType numCells = input->GetNumberOfCells(); + for (vtkIdType i = 0; i < numCells; i++) + { + if (!vtkCellTypes::IsLinear(types->GetValue(i))) + { + handleSubdivision = true; + break; + } + } + } + + if (handleSubdivision) + { + // Use the vtkUnstructuredGridGeometryFilter to extract 2D surface cells + // from the geometry. This is important to extract an appropriate + // wireframe in vtkPVRecoverGeometryWireframe. Also, at the time of this + // writing vtkDataSetSurfaceFilter only properly subdivides 2D cells past + // level 1. + VTK_CREATE(vtkUnstructuredGrid, inputClone); + inputClone->ShallowCopy(input); + this->UnstructuredGridGeometryFilter->SetInput(inputClone); + + // Observe the progress of the internal filter. + // TODO: Make the consecutive internal filter execution have monotonically + // increasing progress rather than restarting for every internal filter. + this->UnstructuredGridGeometryFilter->AddObserver( + vtkCommand::ProgressEvent, + this->InternalProgressObserver); + this->UnstructuredGridGeometryFilter->Update(); + // The internal filter finished. Remove the observer. + this->UnstructuredGridGeometryFilter->RemoveObserver( + this->InternalProgressObserver); + + this->UnstructuredGridGeometryFilter->SetInput(NULL); + + // Feed the extracted surface as the input to the rest of the processing. + input->ShallowCopy(this->UnstructuredGridGeometryFilter->GetOutput()); + + // Flag the data set surface filter to record original cell ids, but do it + // in a specially named array that vtkPVRecoverGeometryWireframe will + // recognize. Note that because the data set comes from + // UnstructuredGridGeometryFilter, the ids will represent the faces rather + // than the original cells, which is important. + this->DataSetSurfaceFilter->PassThroughCellIdsOn(); + this->DataSetSurfaceFilter->SetOriginalCellIdsName( + vtkPVRecoverGeometryWireframe::ORIGINAL_FACE_IDS()); + } + this->DataSetSurfaceExecute(input, output); + + if (handleSubdivision) + { + // Restore state of DataSetSurfaceFilter. + this->DataSetSurfaceFilter->SetPassThroughCellIds( + this->PassThroughCellIds); + this->DataSetSurfaceFilter->SetOriginalCellIdsName(NULL); + } + return; } @@ -1132,6 +1216,8 @@ "DataSetSurfaceFilter"); vtkGarbageCollectorReport(collector, this->GenericGeometryFilter, "GenericGeometryFilter"); + vtkGarbageCollectorReport(collector, this->UnstructuredGridGeometryFilter, + "UnstructuredGridGeometryFilter"); } //---------------------------------------------------------------------------- @@ -1152,6 +1238,8 @@ os << indent << "UseStrips: " << (this->UseStrips?"on":"off") << endl; os << indent << "GenerateCellNormals: " << (this->GenerateCellNormals?"on":"off") << endl; + os << indent << "NonlinearSubdivisionLevel: " + << this->NonlinearSubdivisionLevel << endl; os << indent << "Controller: " << this->Controller << endl; os << indent << "PassThroughCellIds: " @@ -1235,3 +1323,20 @@ this->StripSettingMTime.Modified(); } } + +//----------------------------------------------------------------------------- +void vtkPVGeometryFilter::SetNonlinearSubdivisionLevel(int newvalue) +{ + if (this->NonlinearSubdivisionLevel != newvalue) + { + this->NonlinearSubdivisionLevel = newvalue; + + if (this->DataSetSurfaceFilter) + { + this->DataSetSurfaceFilter->SetNonlinearSubdivisionLevel( + this->NonlinearSubdivisionLevel); + } + + this->Modified(); + } +} Index: Servers/Filters/vtkPVGeometryFilter.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/Filters/vtkPVGeometryFilter.h,v retrieving revision 1.45 diff -u -r1.45 vtkPVGeometryFilter.h --- Servers/Filters/vtkPVGeometryFilter.h 22 Sep 2008 18:16:00 -0000 1.45 +++ Servers/Filters/vtkPVGeometryFilter.h 10 Jun 2009 22:25:02 -0000 @@ -38,6 +38,7 @@ class vtkRectilinearGrid; class vtkStructuredGrid; class vtkUnstructuredGrid; +class vtkUnstructuredGridGeometryFilter; class VTK_EXPORT vtkPVGeometryFilter : public vtkPolyDataAlgorithm { @@ -80,6 +81,15 @@ vtkBooleanMacro(GenerateCellNormals, int); // Description: + // Nonlinear faces are approximated with flat polygons. This parameter + // controls how many times to subdivide nonlinear surface cells. Higher + // subdivisions generate closer approximations but take more memory and + // rendering time. Subdivision is recursive, so the number of output polygons + // can grow exponentially with this parameter. + virtual void SetNonlinearSubdivisionLevel(int); + vtkGetMacro(NonlinearSubdivisionLevel, int); + + // Description: // Set and get the controller. virtual void SetController(vtkMultiProcessController*); vtkGetObjectMacro(Controller, vtkMultiProcessController); @@ -151,11 +161,13 @@ int UseOutline; int UseStrips; int GenerateCellNormals; + int NonlinearSubdivisionLevel; vtkMultiProcessController* Controller; vtkOutlineSource *OutlineSource; vtkDataSetSurfaceFilter* DataSetSurfaceFilter; vtkGenericGeometryFilter *GenericGeometryFilter; + vtkUnstructuredGridGeometryFilter *UnstructuredGridGeometryFilter; int CheckAttributes(vtkDataObject* input); Index: Servers/Filters/vtkPVRecoverGeometryWireframe.cxx =================================================================== RCS file: Servers/Filters/vtkPVRecoverGeometryWireframe.cxx diff -N Servers/Filters/vtkPVRecoverGeometryWireframe.cxx --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Servers/Filters/vtkPVRecoverGeometryWireframe.cxx 10 Jun 2009 22:25:02 -0000 @@ -0,0 +1,217 @@ +// -*- c++ -*- +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: pqBlotDialog.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*------------------------------------------------------------------------- + Copyright 2009 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, + the U.S. Government retains certain rights in this software. +-------------------------------------------------------------------------*/ + +#include "vtkPVRecoverGeometryWireframe.h" + +#include "vtkCellArray.h" +#include "vtkCellData.h" +#include "vtkIdTypeArray.h" +#include "vtkObjectFactory.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" + +#include "vtkSmartPointer.h" +#define VTK_CREATE(type, name) \ + vtkSmartPointer<type> name = vtkSmartPointer<type>::New() + +#include <vtksys/hash_map.hxx> + +//============================================================================= +namespace vtkPVRecoverGeometryWireframeNamespace +{ + // Description: + // Simple class used internally to define an edge based on the endpoints. The + // endpoints are canonically identified by the lower and higher values. + class EdgeEndpoints + { + public: + EdgeEndpoints() : MinEndPoint(-1), MaxEndPoint(-1) {} + EdgeEndpoints(vtkIdType endpointA, vtkIdType endpointB) + : MinEndPoint((endpointA < endpointB) ? endpointA : endpointB), + MaxEndPoint((endpointA < endpointB) ? endpointB : endpointA) + {} + const vtkIdType MinEndPoint; + const vtkIdType MaxEndPoint; + inline bool operator==(const EdgeEndpoints &other) const { + return ( (this->MinEndPoint == other.MinEndPoint) + && (this->MaxEndPoint == other.MaxEndPoint) ); + } + }; + struct EdgeEndpointsHash { + public: + size_t operator()(const EdgeEndpoints &edge) const { + return static_cast<size_t>(edge.MinEndPoint + edge.MaxEndPoint); + } + }; + + // Description: + // Holds the information necessary for the facet this edge came from. + class EdgeInformation + { + public: + vtkIdType OriginalFaceId; + vtkIdType InputCellId; + }; + + // Description: + // A map from edge endpoints to the information about that edge. + typedef vtksys::hash_map<EdgeEndpoints, EdgeInformation, EdgeEndpointsHash> + EdgeMapType; +} +using namespace vtkPVRecoverGeometryWireframeNamespace; + +//============================================================================= +vtkCxxRevisionMacro(vtkPVRecoverGeometryWireframe, "$Revision$"); +vtkStandardNewMacro(vtkPVRecoverGeometryWireframe); + +//----------------------------------------------------------------------------- +vtkPVRecoverGeometryWireframe::vtkPVRecoverGeometryWireframe() +{ +} + +vtkPVRecoverGeometryWireframe::~vtkPVRecoverGeometryWireframe() +{ +} + +void vtkPVRecoverGeometryWireframe::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +//----------------------------------------------------------------------------- +int vtkPVRecoverGeometryWireframe::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + vtkPolyData *input = vtkPolyData::GetData(inputVector[0]); + vtkPolyData *output = vtkPolyData::GetData(outputVector); + + if (!input->GetCellData()->HasArray(ORIGINAL_FACE_IDS())) + { + // Did not find the field used to identify the face each linear patch comes + // from. The original data was probably linear so using all the edges + // should be OK (and is at least the best we can do), so just pass the data. + output->ShallowCopy(input); + return 1; + } + + vtkIdTypeArray *faceIds = vtkIdTypeArray::SafeDownCast( + input->GetCellData()->GetAbstractArray(ORIGINAL_FACE_IDS())); + if (!faceIds) + { + vtkErrorMacro(<< ORIGINAL_FACE_IDS() << " array is not of expected type."); + return 0; + } + + // Shallow copy all point information to output. + output->SetPoints(input->GetPoints()); + output->GetPointData()->PassData(input->GetPointData()); + + // Get ready to copy cell data. + vtkCellData *inputCD = input->GetCellData(); + vtkCellData *outputCD = output->GetCellData(); + outputCD->CopyAllocate(inputCD); + vtkIdType inputCellId = 0; + vtkIdType nextCellId = 0; + + // Copy over vertex cells. We can shallow copy the topology because we will + // not edit it. + vtkCellArray *inputVerts = input->GetVerts(); + output->SetVerts(inputVerts); + for (vtkIdType i = 0; i < inputVerts->GetNumberOfCells(); i++) + { + outputCD->CopyData(inputCD, inputCellId, nextCellId); + inputCellId++; nextCellId++; + } + + // Copy over line cells. Deep copy the topology because we will add to it + // later. + vtkCellArray *inputLines = input->GetLines(); + VTK_CREATE(vtkCellArray, outputLines); + outputLines->DeepCopy(inputLines); + for (vtkIdType i = 0; i < inputLines->GetNumberOfCells(); i++) + { + outputCD->CopyData(inputCD, inputCellId, nextCellId); + inputCellId++; nextCellId++; + } + + // Iterate over all the input facets and see which edge interfaces belonged + // to different faces. We do that by recording the original face id in + // a map. When we find a pair of edges, we keep them if they came from + // different faces, or discard them if they came from the same face. + EdgeMapType edgeMap; + vtkCellArray *inputPolys = input->GetPolys(); + inputPolys->InitTraversal(); + for (vtkIdType i = 0; i < inputPolys->GetNumberOfCells(); i++) + { + vtkIdType originalFace = faceIds->GetValue(inputCellId); + vtkIdType npts, *pts; + inputPolys->GetNextCell(npts, pts); + for (vtkIdType j = 0; j < npts; j++) + { + EdgeEndpoints edge(pts[j], pts[(j+1)%npts]); + EdgeMapType::iterator iter = edgeMap.find(edge); + if (iter == edgeMap.end()) + { + // Not encountered yet. Add to the map. + EdgeInformation edgeInfo; + edgeInfo.OriginalFaceId = originalFace; + edgeInfo.InputCellId = inputCellId; + edgeMap.insert(vtkstd::make_pair(edge, edgeInfo)); + } + else + { + if (iter->second.OriginalFaceId != originalFace) + { + // This edge belongs to two different faces. Add it to the output. + vtkIdType edgeIds[2]; + edgeIds[0] = edge.MinEndPoint; edgeIds[1] = edge.MaxEndPoint; + outputLines->InsertNextCell(2, edgeIds); + outputCD->CopyData(inputCD, inputCellId, nextCellId); + nextCellId++; + } + // Remove the edge from the map since we already found the pair. + edgeMap.erase(iter); + } + } + inputCellId++; + } + + // Everything left in the edge map has no match. It must necessarily be + // on the outside of a face. + for (EdgeMapType::iterator iter = edgeMap.begin(); + iter != edgeMap.end(); iter++) + { + const EdgeEndpoints &edge = iter->first; + const EdgeInformation &edgeInfo = iter->second; + vtkIdType edgeIds[2]; + edgeIds[0] = edge.MinEndPoint; edgeIds[1] = edge.MaxEndPoint; + outputLines->InsertNextCell(2, edgeIds); + outputCD->CopyData(inputCD, edgeInfo.InputCellId, nextCellId); + nextCellId++; + } + + output->SetLines(outputLines); + + return 1; +} + Index: Servers/Filters/vtkPVRecoverGeometryWireframe.h =================================================================== RCS file: Servers/Filters/vtkPVRecoverGeometryWireframe.h diff -N Servers/Filters/vtkPVRecoverGeometryWireframe.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Servers/Filters/vtkPVRecoverGeometryWireframe.h 10 Jun 2009 22:25:02 -0000 @@ -0,0 +1,72 @@ +// -*- c++ -*- +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: pqBlotDialog.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*------------------------------------------------------------------------- + Copyright 2009 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, + the U.S. Government retains certain rights in this software. +-------------------------------------------------------------------------*/ + +// .NAME vtkPVRecoverGeometryWireframe - Get corrected wireframe from tesselated facets +// +// .SECTION Description +// +// When vtkPVGeometryFilter tessellates nonlinear faces into linear +// approximations, it introduces edges in the middle of the facets of the +// original mesh (as any valid tessellation would). To correct for this, +// vtkPVGeometryFilter also writes out some fields that allows use to identify +// the edges that are actually part of the original mesh. This filter works in +// conjunction with vtkPVGeometryFilter by taking its output and extracting the +// appropriate mesh. +// +// .SECTION See Also +// vtkPVGeometryFilter +// + +#ifndef __vtkPVRecoverGeometryWireframe_h +#define __vtkPVRecoverGeometryWireframe_h + +#include "vtkPolyDataAlgorithm.h" + +class VTK_EXPORT vtkPVRecoverGeometryWireframe : public vtkPolyDataAlgorithm +{ +public: + vtkTypeRevisionMacro(vtkPVRecoverGeometryWireframe, vtkPolyDataAlgorithm); + static vtkPVRecoverGeometryWireframe *New(); + virtual void PrintSelf(ostream &os, vtkIndent indent); + + // Description: + // In order to determine which edges existed in the original data, we need an + // identifier on each cell determining which face (not cell) it originally + // came from. The ids should be put in a cell data array with this name. The + // existance of this field is also a signal that this wireframe extraction is + // necessary. + static const char *ORIGINAL_FACE_IDS() + { return "vtkPVRecoverWireframeOriginalFaceIds"; } + +protected: + vtkPVRecoverGeometryWireframe(); + ~vtkPVRecoverGeometryWireframe(); + + virtual int RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + +private: + vtkPVRecoverGeometryWireframe(const vtkPVRecoverGeometryWireframe &); // Not implemented + void operator=(const vtkPVRecoverGeometryWireframe &); // Not implemented +}; + +#endif //__vtkPVRecoverGeometryWireframe_h Index: Servers/ServerManager/vtkSMSurfaceRepresentationProxy.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/ServerManager/vtkSMSurfaceRepresentationProxy.cxx,v retrieving revision 1.31 diff -u -r1.31 vtkSMSurfaceRepresentationProxy.cxx --- Servers/ServerManager/vtkSMSurfaceRepresentationProxy.cxx 2 Dec 2008 16:42:26 -0000 1.31 +++ Servers/ServerManager/vtkSMSurfaceRepresentationProxy.cxx 10 Jun 2009 22:25:02 -0000 @@ -46,6 +46,7 @@ vtkSMSurfaceRepresentationProxy::vtkSMSurfaceRepresentationProxy() { this->GeometryFilter = 0; + this->WireframeFilter = 0; this->Mapper = 0; this->LODMapper = 0; this->Prop3D = 0; @@ -102,7 +103,8 @@ strategy->SetEnableLOD(true); this->Connect(this->GeometryFilter, strategy); - this->Connect(strategy->GetOutput(), this->Mapper); + this->Connect(strategy->GetOutput(), this->WireframeFilter); + this->Connect(this->WireframeFilter, this->Mapper); // Go in EndCreateVTKObjects? this->Connect(strategy->GetLODOutput(), this->LODMapper); // Creates the strategy objects. @@ -124,12 +126,16 @@ // Set server flags correctly on all subproxies. this->GeometryFilter = vtkSMSourceProxy::SafeDownCast(this->GetSubProxy("GeometryFilter")); + this->WireframeFilter = + vtkSMSourceProxy::SafeDownCast(this->GetSubProxy("WireframeFilter")); this->Mapper = this->GetSubProxy("Mapper"); this->LODMapper = this->GetSubProxy("LODMapper"); this->Prop3D = this->GetSubProxy("Prop3D"); this->Property = this->GetSubProxy("Property"); this->GeometryFilter->SetServers(vtkProcessModule::DATA_SERVER); + this->WireframeFilter->SetServers( + vtkProcessModule::CLIENT | vtkProcessModule::RENDER_SERVER); this->Mapper->SetServers( vtkProcessModule::CLIENT | vtkProcessModule::RENDER_SERVER); this->LODMapper->SetServers( Index: Servers/ServerManager/vtkSMSurfaceRepresentationProxy.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/ServerManager/vtkSMSurfaceRepresentationProxy.h,v retrieving revision 1.17 diff -u -r1.17 vtkSMSurfaceRepresentationProxy.h --- Servers/ServerManager/vtkSMSurfaceRepresentationProxy.h 28 May 2008 12:06:10 -0000 1.17 +++ Servers/ServerManager/vtkSMSurfaceRepresentationProxy.h 10 Jun 2009 22:25:02 -0000 @@ -175,6 +175,7 @@ virtual void UpdateShadingParameters(); vtkSMSourceProxy* GeometryFilter; + vtkSMSourceProxy* WireframeFilter; vtkSMProxy* Mapper; vtkSMProxy* LODMapper; vtkSMProxy* Prop3D; Index: Servers/ServerManager/Resources/filters.xml =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/ServerManager/Resources/filters.xml,v retrieving revision 1.352 diff -u -r1.352 filters.xml --- Servers/ServerManager/Resources/filters.xml 8 Jun 2009 15:02:01 -0000 1.352 +++ Servers/ServerManager/Resources/filters.xml 10 Jun 2009 22:25:02 -0000 @@ -1524,6 +1524,26 @@ If the value of this property is set to 1, internal surfaces along process boundaries will be removed. NOTE: Enabling this option might cause multiple executions of the data source because more information is needed to remove internal surfaces. </Documentation> </IntVectorProperty> + + <IntVectorProperty name="NonlinearSubdivisionLevel" + command="SetNonlinearSubdivisionLevel" + number_of_elements="1" + default_values="1"> + <IntRangeDomain name="range" min="0" max="4" /> + <Documentation> + If the input is an unstructured grid with nonlinear faces, this + parameter determines how many times the face is subdivided into + linear faces. If 0, the output is the equivalent of its linear + couterpart (and the midpoints determining the nonlinear + interpolation are discarded). If 1, the nonlinear face is + triangulated based on the midpoints. If greater than 1, the + triangulated pieces are recursively subdivided to reach the + desired subdivision. Setting the value to greater than 1 may + cause some point data to not be passed even if no quadratic faces + exist. This option has no effect if the input is not an + unstructured grid. + </Documentation> + </IntVectorProperty> <!-- End DataSetSurfaceFilter --> </SourceProxy> @@ -6863,6 +6883,20 @@ Toggle whether to generate an outline or a surface. </Documentation> </IntVectorProperty> + <IntVectorProperty name="NonlinearSubdivisionLevel" + command="SetNonlinearSubdivisionLevel" + number_of_elements="1" + default_values="1"> + <IntRangeDomain name="range" min="0" max="4" /> + <Documentation> + Nonlinear faces are approximated with flat polygons. This + parameter controls how many times to subdivide nonlinear surface + cells. Higher subdivisions generate closer approximations but + take more memory and rendering time. Subdivision is recursive, + so the number of output polygons can grow exponentially with this + parameter. + </Documentation> + </IntVectorProperty> <IntVectorProperty name="PassThroughIds" command="SetPassThroughCellIds" @@ -6888,6 +6922,21 @@ <!-- End GeometryFilter --> </SourceProxy> + <!-- ================================================================== --> + <SourceProxy name="RecoverGeometryWireframe" + class="vtkPVRecoverGeometryWireframe"> + <InputProperty name="Input" + command="SetInputConnection"> + <ProxyGroupDomain name="groups"> + <Group name="sources" /> + <Group name="filters" /> + </ProxyGroupDomain> + <DataTypeDomain name="input_type"> + <DataType value="vtkPolyData" /> + </DataTypeDomain> + </InputProperty> + </SourceProxy> <!-- RecoverGeometryWireframe --> + <!-- ==================================================================== --> <SourceProxy name="OrderedCompositeDistributor" class="vtkOrderedCompositeDistributor"> Index: Servers/ServerManager/Resources/rendering.xml =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/ServerManager/Resources/rendering.xml,v retrieving revision 1.352 diff -u -r1.352 rendering.xml --- Servers/ServerManager/Resources/rendering.xml 9 Jun 2009 17:38:12 -0000 1.352 +++ Servers/ServerManager/Resources/rendering.xml 10 Jun 2009 22:25:02 -0000 @@ -5861,7 +5861,7 @@ <SubProxy> <!-- - Geometry filter is used to conver non-polydata input to polydata. + Geometry filter is used to convert non-polydata input to polydata. It is also used to convert poly data to triangle strips when requested. --> @@ -5870,8 +5870,18 @@ <ExposedProperties> <Property name="UseStrips" /> <Property name="ForceStrips" /> + <Property name="NonlinearSubdivisionLevel" /> </ExposedProperties> </SubProxy> + + <SubProxy> + <!-- + Wireframe filter is used to extract the propery wireframe from + polygonal geometry that was derived from nonlinear cells. + --> + <Proxy name="WireframeFilter" + proxygroup="filters" proxyname="RecoverGeometryWireframe" /> + </SubProxy> <SubProxy> <!-- @@ -6651,6 +6661,7 @@ <!-- Geometry Filter properties --> <Property name="UseStrips" /> <Property name="ForceStrips" /> + <Property name="NonlinearSubdivisionLevel" /> <!-- Mapper properties --> <Property name="LookupTable" /> Index: VTK/Filtering/vtkCellType.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Filtering/vtkCellType.h,v retrieving revision 1.5 diff -u -r1.5 vtkCellType.h --- VTK/Filtering/vtkCellType.h 7 May 2007 15:40:59 -0000 1.5 +++ VTK/Filtering/vtkCellType.h 10 Jun 2009 22:25:02 -0000 @@ -29,7 +29,8 @@ // GetCell() and vtkGenericCell::SetCellType(). Also, to do the job right, // you'll also have to modify some filters (vtkGeometryFilter...) and // regression tests (example scripts) to reflect the new cell addition. -// Also, make sure to update vtkCellTypesStrings in vtkCellTypes.cxx. +// Also, make sure to update vtkCellTypesStrings in vtkCellTypes.cxx +// and the vtkCellTypes::IsLinear method in vtkCellTypes.h. // .SECTION Caveats // An unstructured grid stores the types of its cells as a Index: VTK/Filtering/vtkCellTypes.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Filtering/vtkCellTypes.h,v retrieving revision 1.3 diff -u -r1.3 vtkCellTypes.h --- VTK/Filtering/vtkCellTypes.h 11 Dec 2008 21:47:19 -0000 1.3 +++ VTK/Filtering/vtkCellTypes.h 10 Jun 2009 22:25:02 -0000 @@ -118,6 +118,13 @@ // defined in vtkCellType.h) static int GetTypeIdFromClassName(const char* classname); + // Description: + // This convenience method is a fast check to determine if a cell type + // represents a linear or nonlinear cell. This is generally much more + // efficient than getting the appropriate vtkCell and checking its IsLinear + // method. + static int IsLinear(unsigned char type); + protected: vtkCellTypes(); ~vtkCellTypes(); @@ -148,5 +155,11 @@ return 0; } +//----------------------------------------------------------------------------- +inline int vtkCellTypes::IsLinear(unsigned char type) +{ + return ((type <= 20) || (type == VTK_CONVEX_POINT_SET)); +} + #endif Index: VTK/Graphics/vtkDataSetSurfaceFilter.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Graphics/vtkDataSetSurfaceFilter.cxx,v retrieving revision 1.70 diff -u -r1.70 vtkDataSetSurfaceFilter.cxx --- VTK/Graphics/vtkDataSetSurfaceFilter.cxx 25 Mar 2009 14:35:52 -0000 1.70 +++ VTK/Graphics/vtkDataSetSurfaceFilter.cxx 10 Jun 2009 22:25:03 -0000 @@ -16,8 +16,10 @@ #include "vtkCellArray.h" #include "vtkCellData.h" +#include "vtkDoubleArray.h" #include "vtkGenericCell.h" #include "vtkHexahedron.h" +#include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMergePoints.h" @@ -26,18 +28,19 @@ #include "vtkPolyData.h" #include "vtkPyramid.h" #include "vtkRectilinearGrid.h" -#include "vtkStructuredGrid.h" -#include "vtkUniformGrid.h" #include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkStructuredGrid.h" #include "vtkStructuredGridGeometryFilter.h" #include "vtkStructuredPoints.h" #include "vtkTetra.h" +#include "vtkUniformGrid.h" #include "vtkUnsignedCharArray.h" #include "vtkUnstructuredGrid.h" #include "vtkVoxel.h" #include "vtkWedge.h" -#include "vtkIdTypeArray.h" +#include <vtkstd/algorithm> +#include <vtksys/hash_map.hxx> static int sizeofFastQuad(int numPts) { @@ -45,6 +48,39 @@ return static_cast<int>(sizeof(vtkFastGeomQuad)+(numPts-4)*sizeof(vtkIdType)); } +class vtkDataSetSurfaceFilter::vtkEdgeInterpolationMap +{ +public: + void AddEdge(vtkIdType endpoint1, vtkIdType endpoint2, vtkIdType midpoint) { + if (endpoint1 > endpoint2) vtkstd::swap(endpoint1, endpoint2); + Map.insert(vtkstd::make_pair(vtkstd::make_pair(endpoint1, endpoint2), + midpoint)); + } + vtkIdType FindEdge(vtkIdType endpoint1, vtkIdType endpoint2) { + if (endpoint1 > endpoint2) vtkstd::swap(endpoint1, endpoint2); + MapType::iterator iter = Map.find(vtkstd::make_pair(endpoint1, endpoint2)); + if (iter != Map.end()) + { + return iter->second; + } + else + { + return -1; + } + } + +protected: + struct HashFunction { + public: + size_t operator()(vtkstd::pair<vtkIdType,vtkIdType> edge) const { + return static_cast<size_t>(edge.first + edge.second); + } + }; + typedef vtksys::hash_map<vtkstd::pair<vtkIdType, vtkIdType>, vtkIdType, + HashFunction> MapType; + MapType Map; +}; + vtkCxxRevisionMacro(vtkDataSetSurfaceFilter, "$Revision: 1.70 $"); vtkStandardNewMacro(vtkDataSetSurfaceFilter); @@ -53,6 +89,7 @@ { this->QuadHash = NULL; this->PointMap = NULL; + this->EdgeMap = NULL; this->QuadHashLength = 0; this->UseStrips = 0; this->NumberOfNewCells = 0; @@ -70,6 +107,10 @@ this->PassThroughPointIds = 0; this->OriginalCellIds = NULL; this->OriginalPointIds = NULL; + this->OriginalCellIdsName = NULL; + this->OriginalPointIdsName = NULL; + + this->NonlinearSubdivisionLevel = 1; } //---------------------------------------------------------------------------- @@ -179,7 +220,7 @@ { //make a 1:1 mapping this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); vtkCellData *outputCD = output->GetCellData(); outputCD->AddArray(this->OriginalCellIds); @@ -196,7 +237,7 @@ { //make a 1:1 mapping this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); vtkPointData *outputPD = output->GetPointData(); outputPD->AddArray(this->OriginalPointIds); @@ -348,14 +389,14 @@ if (this->PassThroughCellIds) { this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); output->GetCellData()->AddArray(this->OriginalCellIds); } if (this->PassThroughPointIds) { this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); output->GetPointData()->AddArray(this->OriginalPointIds); } @@ -916,6 +957,8 @@ os << indent << "PassThroughCellIds: " << (this->PassThroughCellIds ? "On\n" : "Off\n"); os << indent << "PassThroughPointIds: " << (this->PassThroughPointIds ? "On\n" : "Off\n"); + os << indent << "NonlinearSubdivisionLevel: " + << this->NonlinearSubdivisionLevel << endl; } //======================================================================== @@ -949,7 +992,6 @@ vtkCellData *cd = input->GetCellData(); vtkPointData *outputPD = output->GetPointData(); vtkCellData *outputCD = output->GetCellData(); - vtkIdType outPts[6]; vtkFastGeomQuad *q; unsigned char* cellTypes = input->GetCellTypesArray()->GetPointer(0); @@ -958,9 +1000,19 @@ vtkPoints *coords; vtkCell *face; int flag2D = 0; + + // These are for subdividing quadratic cells + vtkDoubleArray *parametricCoords; + vtkDoubleArray *parametricCoords2; + vtkIdList *outPts; + vtkIdList *outPts2; pts = vtkIdList::New(); coords = vtkPoints::New(); + parametricCoords = vtkDoubleArray::New(); + parametricCoords2 = vtkDoubleArray::New(); + outPts = vtkIdList::New(); + outPts2 = vtkIdList::New(); // might not be necessary to set the data type for coords // but certainly safer to do so coords->SetDataType(input->GetPoints()->GetData()->GetDataType()); @@ -979,21 +1031,28 @@ newVerts = vtkCellArray::New(); newLines = vtkCellArray::New(); - outputPD->CopyGlobalIdsOn(); - outputPD->CopyAllocate(inputPD, numPts, numPts/2); + if (this->NonlinearSubdivisionLevel <= 1) + { + outputPD->CopyGlobalIdsOn(); + outputPD->CopyAllocate(inputPD, numPts, numPts/2); + } + else + { + outputPD->InterpolateAllocate(inputPD, numPts, numPts/2); + } outputCD->CopyGlobalIdsOn(); outputCD->CopyAllocate(inputCD, numCells, numCells/2); if (this->PassThroughCellIds) { this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); } if (this->PassThroughPointIds) { this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); } @@ -1201,14 +1260,40 @@ if ( cellIds->GetNumberOfIds() <= 0) { // FIXME: Face could not be consistent. vtkOrderedTriangulator is a better option - face->Triangulate(0,pts,coords); - for (i=0; i < pts->GetNumberOfIds(); i+=3) + if (this->NonlinearSubdivisionLevel >= 1) { - this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1), - pts->GetId(i+2), cellId); + // TODO: Handle NonlinearSubdivisionLevel > 1 correctly. + face->Triangulate(0,pts,coords); + for (i=0; i < pts->GetNumberOfIds(); i+=3) + { + this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1), + pts->GetId(i+2), cellId); + } } - } - } + else + { + switch (face->GetCellType()) + { + case VTK_QUADRATIC_TRIANGLE: + this->InsertTriInHash(face->PointIds->GetId(0), + face->PointIds->GetId(1), + face->PointIds->GetId(2), cellId); + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + case VTK_QUADRATIC_LINEAR_QUAD: + this->InsertQuadInHash(face->PointIds->GetId(0), + face->PointIds->GetId(1), + face->PointIds->GetId(2), + face->PointIds->GetId(3), cellId); + break; + default: + vtkWarningMacro(<< "Encountered unknown nonlinear face."); + break; + } // switch cell type + } // subdivision level + } // cell has ids + } // for faces cellIds->Delete(); } //3d cell } //nonlinear cell @@ -1232,6 +1317,25 @@ // Move to the next cell. cellPointer += (1 + *cellPointer); + // If we have a quadratic face and our subdivision level is zero, just treat + // it as a linear cell. This should work so long as the first points of the + // quadratic cell correspond to all those of the equivalent linear cell + // (which all the current definitions do). + if (this->NonlinearSubdivisionLevel < 1) + { + switch (cellType) + { + case VTK_QUADRATIC_TRIANGLE: + cellType = VTK_TRIANGLE; numCellPts = 3; + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + case VTK_QUADRATIC_LINEAR_QUAD: + cellType = VTK_POLYGON; numCellPts = 4; + break; + } + } + // A couple of common cases to see if things go faster. if (cellType == VTK_PIXEL) { // Do we really want to insert the 2D cells into a hash? @@ -1283,14 +1387,99 @@ || cellType == VTK_BIQUADRATIC_QUAD || cellType == VTK_QUADRATIC_LINEAR_QUAD) { + // Note: we should not be here if this->NonlinearSubdivisionLevel is less + // than 1. See the check above. input->GetCell( cellId, cell ); cell->Triangulate( 0, pts, coords ); - for ( i=0; i < pts->GetNumberOfIds(); i+=3 ) + // Copy the level 1 subdivision points (which also exist in the input and + // can therefore just be copied over. Note that the output of Triangulate + // records triangles in pts where each 3 points defines a triangle. We + // will keep this invariant and also keep the same invariant in + // parametericCoords and outPts later. + outPts->Reset(); + for ( i=0; i < pts->GetNumberOfIds(); i++ ) + { + vtkIdType op; + op = this->GetOutputPointId(pts->GetId(i), input, newPts, outputPD); + outPts->InsertNextId(op); + } + // Do any further subdivision if necessary. + if (this->NonlinearSubdivisionLevel > 1) + { + // We are going to need parametric coordinates to further subdivide. + double *pc = cell->GetParametricCoords(); + parametricCoords->Reset(); + parametricCoords->SetNumberOfComponents(3); + for (i = 0; i < pts->GetNumberOfIds(); i++) + { + vtkIdType ptId = pts->GetId(i); + vtkIdType cellPtId; + for (cellPtId = 0; cell->GetPointId(cellPtId) != ptId; cellPtId++); + parametricCoords->InsertNextTupleValue(pc + 3*cellPtId); + } + // Subdivide these triangles as many more times as necessary. Remember + // that we have already done the first subdivision. + for (j = 1; j < this->NonlinearSubdivisionLevel; j++) + { + parametricCoords2->Reset(); + parametricCoords2->SetNumberOfComponents(3); + outPts2->Reset(); + // Each triangle will be split into 4 triangles. + for (i = 0; i < outPts->GetNumberOfIds(); i += 3) + { + // Hold the input point ids and parametric coordinates. First 3 + // indices are the original points. Second three are the midpoints + // in the edges (0,1), (1,2) and (2,0), respectively (see comment + // below). + vtkIdType inPts[6]; + double inParamCoords[6][3]; + int k; + for (k = 0; k < 3; k++) + { + inPts[k] = outPts->GetId(i+k); + parametricCoords->GetTupleValue(i+k, inParamCoords[k]); + } + for (k = 3; k < 6; k++) + { + int pt1 = k-3; + int pt2 = (pt1 < 2) ? (pt1 + 1) : 0; + inParamCoords[k][0] = 0.5*(inParamCoords[pt1][0] + inParamCoords[pt2][0]); + inParamCoords[k][1] = 0.5*(inParamCoords[pt1][1] + inParamCoords[pt2][1]); + inParamCoords[k][2] = 0.5*(inParamCoords[pt1][2] + inParamCoords[pt2][2]); + inPts[k] = GetInterpolatedPointId(inPts[pt1], inPts[pt2], + input, cell, + inParamCoords[k], newPts, + outputPD); + } + // * 0 + // / \ Use the 6 points recorded + // / \ in inPts and inParamCoords + // 3 *-----* 5 to create the 4 triangles + // / \ / \ shown here. + // / \ / \ . + // *-----*-----* + // 1 4 2 + const int subtriangles[12] = {0,3,5, 3,1,4, 3,4,5, 5,4,2}; + for (k = 0; k < 12; k++) + { + int localId = subtriangles[k]; + outPts2->InsertNextId(inPts[localId]); + parametricCoords2->InsertNextTupleValue(inParamCoords[localId]); + } + } // Iterate over triangles + // Now that we have recorded the subdivided triangles in outPts2 and + // parametricCoords2, swap them with outPts and parametricCoords to + // make them the current ones. + vtkstd::swap(outPts, outPts2); + vtkstd::swap(parametricCoords, parametricCoords2); + } // Iterate over subdivision levels + } // If further subdivision + + // Now that we have done all the subdivisions and created all of the + // points, record the triangles. + for (i = 0; i < outPts->GetNumberOfIds(); i += 3) { - outPts[0] = this->GetOutputPointId( pts->GetId(i), input, newPts, outputPD ); - outPts[1] = this->GetOutputPointId( pts->GetId(i+1), input, newPts, outputPD ); - outPts[2] = this->GetOutputPointId( pts->GetId(i+2), input, newPts, outputPD ); - newPolys->InsertNextCell( 3, outPts ); + newPolys->InsertNextCell(3, outPts->GetPointer(i)); this->RecordOrigCellId(this->NumberOfNewCells, cellId); outputCD->CopyData(cd, cellId, this->NumberOfNewCells++); } @@ -1326,6 +1515,10 @@ cell->Delete(); coords->Delete(); pts->Delete(); + parametricCoords->Delete(); + parametricCoords2->Delete(); + outPts->Delete(); + outPts2->Delete(); output->SetPoints(newPts); newPts->Delete(); @@ -1387,6 +1580,7 @@ this->QuadHash[i] = NULL; this->PointMap[i] = -1; } + this->EdgeMap = new vtkEdgeInterpolationMap; } //---------------------------------------------------------------------------- @@ -1406,6 +1600,8 @@ this->QuadHashLength = 0; delete [] this->PointMap; this->PointMap = NULL; + delete this->EdgeMap; + this->EdgeMap = NULL; } //---------------------------------------------------------------------------- @@ -1800,6 +1996,34 @@ return outPtId; } +//----------------------------------------------------------------------------- +vtkIdType vtkDataSetSurfaceFilter::GetInterpolatedPointId(vtkIdType edgePtA, + vtkIdType edgePtB, + vtkDataSet *input, + vtkCell *cell, + double pcoords[3], + vtkPoints *outPts, + vtkPointData *outPD) +{ + vtkIdType outPtId; + + outPtId = this->EdgeMap->FindEdge(edgePtA, edgePtB); + if (outPtId == -1) + { + int subId = -1; + double wcoords[3]; + double weights[100]; // Any reason to need more? + cell->EvaluateLocation(subId, pcoords, wcoords, weights); + outPtId = outPts->InsertNextPoint(wcoords); + outPD->InterpolatePoint(input->GetPointData(), outPtId, + cell->GetPointIds(), weights); + this->RecordOrigPointId(outPtId, -1); + this->EdgeMap->AddEdge(edgePtA, edgePtB, outPtId); + } + + return outPtId; +} + //---------------------------------------------------------------------------- void vtkDataSetSurfaceFilter::RecordOrigCellId(vtkIdType destIndex, vtkIdType originalId) Index: VTK/Graphics/vtkDataSetSurfaceFilter.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Graphics/vtkDataSetSurfaceFilter.h,v retrieving revision 1.26 diff -u -r1.26 vtkDataSetSurfaceFilter.h --- VTK/Graphics/vtkDataSetSurfaceFilter.h 25 Mar 2009 14:35:54 -0000 1.26 +++ VTK/Graphics/vtkDataSetSurfaceFilter.h 10 Jun 2009 22:25:03 -0000 @@ -80,6 +80,35 @@ vtkGetMacro(PassThroughPointIds,int); vtkBooleanMacro(PassThroughPointIds,int); + // Description: + // If PassThroughCellIds or PassThroughPointIds is on, then these ivars + // control the name given to the field in which the ids are written into. If + // set to NULL, then vtkOriginalCellIds or vtkOriginalPointIds (the default) + // is used, respectively. + vtkSetStringMacro(OriginalCellIdsName); + virtual const char *GetOriginalCellIdsName() { + return ( this->OriginalCellIdsName + ? this->OriginalCellIdsName : "vtkOriginalCellIds"); + } + vtkSetStringMacro(OriginalPointIdsName); + virtual const char *GetOriginalPointIdsName() { + return ( this->OriginalPointIdsName + ? this->OriginalPointIdsName : "vtkOriginalPointIds"); + } + + // Description: + // If the input is an unstructured grid with nonlinear faces, this parameter + // determines how many times the face is subdivided into linear faces. If 0, + // the output is the equivalent of its linear couterpart (and the midpoints + // determining the nonlinear interpolation are discarded). If 1 (the + // default), the nonlinear face is triangulated based on the midpoints. If + // greater than 1, the triangulated pieces are recursively subdivided to reach + // the desired subdivision. Setting the value to greater than 1 may cause + // some point data to not be passed even if no nonlinear faces exist. This + // option has no effect if the input is not an unstructured grid. + vtkSetMacro(NonlinearSubdivisionLevel, int); + vtkGetMacro(NonlinearSubdivisionLevel, int); + protected: vtkDataSetSurfaceFilter(); ~vtkDataSetSurfaceFilter(); @@ -124,6 +153,14 @@ vtkIdType *PointMap; vtkIdType GetOutputPointId(vtkIdType inPtId, vtkDataSet *input, vtkPoints *outPts, vtkPointData *outPD); +//BTX + class vtkEdgeInterpolationMap; +//ETX + vtkEdgeInterpolationMap *EdgeMap; + vtkIdType GetInterpolatedPointId(vtkIdType edgePtA, vtkIdType edgePtB, + vtkDataSet *input, vtkCell *cell, + double pcoords[3], vtkPoints *outPts, + vtkPointData *outPD); vtkIdType NumberOfNewCells; @@ -144,10 +181,14 @@ int PassThroughCellIds; void RecordOrigCellId(vtkIdType newIndex, vtkIdType origId); vtkIdTypeArray *OriginalCellIds; + char *OriginalCellIdsName; int PassThroughPointIds; void RecordOrigPointId(vtkIdType newIndex, vtkIdType origId); vtkIdTypeArray *OriginalPointIds; + char *OriginalPointIdsName; + + int NonlinearSubdivisionLevel; private: vtkDataSetSurfaceFilter(const vtkDataSetSurfaceFilter&); // Not implemented. ![]() Index: Qt/Components/pqDisplayProxyEditor.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Qt/Components/pqDisplayProxyEditor.cxx,v retrieving revision 1.75 diff -u -r1.75 pqDisplayProxyEditor.cxx --- Qt/Components/pqDisplayProxyEditor.cxx 9 Jun 2009 17:33:32 -0000 1.75 +++ Qt/Components/pqDisplayProxyEditor.cxx 12 Jun 2009 20:06:32 -0000 @@ -384,6 +384,15 @@ "value", SIGNAL(editingFinished()), reprProxy, reprProxy->GetProperty("Opacity")); + // setup of nonlinear subdivision + if (reprProxy->GetProperty("NonlinearSubdivisionLevel")) + { + this->Internal->Links->addPropertyLink( + this->Internal->NonlinearSubdivisionLevel, + "value", SIGNAL(valueChanged(int)), + reprProxy, reprProxy->GetProperty("NonlinearSubdivisionLevel")); + } + // setup for map scalars this->Internal->Links->addPropertyLink( this->Internal->ColorMapScalars, "checked", SIGNAL(stateChanged(int)), Index: Qt/Components/Resources/UI/pqDisplayProxyEditor.ui =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui,v retrieving revision 1.42 diff -u -r1.42 pqDisplayProxyEditor.ui --- Qt/Components/Resources/UI/pqDisplayProxyEditor.ui 9 Jun 2009 17:33:32 -0000 1.42 +++ Qt/Components/Resources/UI/pqDisplayProxyEditor.ui 12 Jun 2009 20:06:32 -0000 @@ -669,14 +669,44 @@ </property> </spacer> </item> - <item row="7" column="0" > + <item row="7" column="0"> + <widget class="QLabel" name="label_17"> + <property name="text"> + <string>Subdivision</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QSpinBox" name="NonlinearSubdivisionLevel"> + <property name="toolTip"> + <string>Nonlinear faces are approximated with flat polygons. This parameter controls how many times to subdivide nonlinear surface cells. Higher subdivisions generate closer approximations but take more memory and rendering time. Subdivision is recursive, so the number of output polygons can grow exponentially with this parameter.</string> + </property> + <property name="maximum"> + <number>4</number> + </property> + </widget> + </item> + <item row="7" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="8" column="0" > <widget class="QLabel" name="label_19" > <property name="text" > <string>Volume mapper</string> </property> </widget> </item> - <item row="7" column="1" colspan="2" > + <item row="8" column="1" colspan="2" > <widget class="QComboBox" name="SelectedMapperIndex" > <property name="toolTip" > <string><html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:Sans Serif; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Choose the mapper to use for volume rendering.</p></body></html></string> @@ -1217,6 +1247,7 @@ <tabstop>StylePointSize</tabstop> <tabstop>StyleLineWidth</tabstop> <tabstop>Opacity</tabstop> + <tabstop>NonlinearSubdivisionLevel</tabstop> <tabstop>SelectedMapperIndex</tabstop> <tabstop>EdgeColor</tabstop> <tabstop>SpecularIntensity</tabstop> Index: Servers/Filters/CMakeLists.txt =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/Filters/CMakeLists.txt,v retrieving revision 1.195 diff -u -r1.195 CMakeLists.txt --- Servers/Filters/CMakeLists.txt 28 May 2009 19:02:11 -0000 1.195 +++ Servers/Filters/CMakeLists.txt 12 Jun 2009 20:06:32 -0000 @@ -98,6 +98,7 @@ vtkPVMain.cxx vtkPVMergeTables.cxx vtkPVNullSource.cxx + vtkPVRecoverGeometryWireframe.cxx vtkPVRenderViewProxy.cxx vtkPVScalarBarActor.cxx vtkPVSelectionSource.cxx Index: Servers/Filters/vtkPVGeometryFilter.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/Filters/vtkPVGeometryFilter.cxx,v retrieving revision 1.94 diff -u -r1.94 vtkPVGeometryFilter.cxx --- Servers/Filters/vtkPVGeometryFilter.cxx 8 May 2009 14:07:39 -0000 1.94 +++ Servers/Filters/vtkPVGeometryFilter.cxx 12 Jun 2009 20:06:32 -0000 @@ -18,6 +18,7 @@ #include "vtkCallbackCommand.h" #include "vtkCellArray.h" #include "vtkCellData.h" +#include "vtkCellTypes.h" #include "vtkCleanArrays.h" #include "vtkCommand.h" #include "vtkCompositeDataIterator.h" @@ -42,6 +43,7 @@ #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkPolygon.h" +#include "vtkPVRecoverGeometryWireframe.h" #include "vtkPVTrivialProducer.h" #include "vtkRectilinearGrid.h" #include "vtkRectilinearGridOutlineFilter.h" @@ -53,11 +55,15 @@ #include "vtkUnsignedCharArray.h" #include "vtkUnsignedIntArray.h" #include "vtkUnstructuredGrid.h" +#include "vtkUnstructuredGridGeometryFilter.h" #include <vtkstd/map> #include <vtkstd/string> #include <assert.h> +#define VTK_CREATE(type, name) \ + vtkSmartPointer<type> name = vtkSmartPointer<type>::New() + vtkCxxRevisionMacro(vtkPVGeometryFilter, "$Revision: 1.94 $"); vtkStandardNewMacro(vtkPVGeometryFilter); @@ -124,10 +130,13 @@ this->UseOutline = 1; this->UseStrips = 0; this->GenerateCellNormals = 1; + this->NonlinearSubdivisionLevel = 1; this->DataSetSurfaceFilter = vtkDataSetSurfaceFilter::New(); this->GenericGeometryFilter=vtkGenericGeometryFilter::New(); - + this->UnstructuredGridGeometryFilter=vtkUnstructuredGridGeometryFilter::New(); + this->RecoverWireframeFilter = vtkPVRecoverGeometryWireframe::New(); + // Setup a callback for the internal readers to report progress. this->InternalProgressObserver = vtkCallbackCommand::New(); this->InternalProgressObserver->SetCallback( @@ -154,13 +163,31 @@ //---------------------------------------------------------------------------- vtkPVGeometryFilter::~vtkPVGeometryFilter () { - if(this->DataSetSurfaceFilter) + // Be careful how you delete these so that you don't foul up the garbage + // collector. + if (this->DataSetSurfaceFilter) + { + vtkDataSetSurfaceFilter *tmp = this->DataSetSurfaceFilter; + this->DataSetSurfaceFilter = NULL; + tmp->Delete(); + } + if (this->GenericGeometryFilter) { - this->DataSetSurfaceFilter->Delete(); + vtkGenericGeometryFilter *tmp = this->GenericGeometryFilter; + this->GenericGeometryFilter = NULL; + tmp->Delete(); } - if(this->GenericGeometryFilter!=0) + if (this->UnstructuredGridGeometryFilter) { - this->GenericGeometryFilter->Delete(); + vtkUnstructuredGridGeometryFilter *tmp=this->UnstructuredGridGeometryFilter; + this->UnstructuredGridGeometryFilter = NULL; + tmp->Delete(); + } + if (this->RecoverWireframeFilter) + { + vtkPVRecoverGeometryWireframe *tmp = this->RecoverWireframeFilter; + this->RecoverWireframeFilter = NULL; + tmp->Delete(); } this->OutlineSource->Delete(); this->InternalProgressObserver->Delete(); @@ -1009,7 +1036,93 @@ if (!this->UseOutline) { this->OutlineFlag = 0; + + bool handleSubdivision = false; + if (this->NonlinearSubdivisionLevel > 0) + { + // Check to see if the data actually has nonlinear cells. Handling + // nonlinear cells adds unnecessary work if we only have linear cells. + vtkUnsignedCharArray *types = input->GetCellTypesArray(); + vtkIdType numCells = input->GetNumberOfCells(); + for (vtkIdType i = 0; i < numCells; i++) + { + if (!vtkCellTypes::IsLinear(types->GetValue(i))) + { + handleSubdivision = true; + break; + } + } + } + + if (handleSubdivision) + { + // Use the vtkUnstructuredGridGeometryFilter to extract 2D surface cells + // from the geometry. This is important to extract an appropriate + // wireframe in vtkPVRecoverGeometryWireframe. Also, at the time of this + // writing vtkDataSetSurfaceFilter only properly subdivides 2D cells past + // level 1. + VTK_CREATE(vtkUnstructuredGrid, inputClone); + inputClone->ShallowCopy(input); + this->UnstructuredGridGeometryFilter->SetInput(inputClone); + + // Observe the progress of the internal filter. + // TODO: Make the consecutive internal filter execution have monotonically + // increasing progress rather than restarting for every internal filter. + this->UnstructuredGridGeometryFilter->AddObserver( + vtkCommand::ProgressEvent, + this->InternalProgressObserver); + this->UnstructuredGridGeometryFilter->Update(); + // The internal filter finished. Remove the observer. + this->UnstructuredGridGeometryFilter->RemoveObserver( + this->InternalProgressObserver); + + this->UnstructuredGridGeometryFilter->SetInput(NULL); + + // Feed the extracted surface as the input to the rest of the processing. + input->ShallowCopy(this->UnstructuredGridGeometryFilter->GetOutput()); + + // Flag the data set surface filter to record original cell ids, but do it + // in a specially named array that vtkPVRecoverGeometryWireframe will + // recognize. Note that because the data set comes from + // UnstructuredGridGeometryFilter, the ids will represent the faces rather + // than the original cells, which is important. + this->DataSetSurfaceFilter->PassThroughCellIdsOn(); + this->DataSetSurfaceFilter->SetOriginalCellIdsName( + vtkPVRecoverGeometryWireframe::ORIGINAL_FACE_IDS()); + } + this->DataSetSurfaceExecute(input, output); + + if (handleSubdivision) + { + // Restore state of DataSetSurfaceFilter. + this->DataSetSurfaceFilter->SetPassThroughCellIds( + this->PassThroughCellIds); + this->DataSetSurfaceFilter->SetOriginalCellIdsName(NULL); + + // Now use vtkPVRecoverGeometryWireframe to create an edge flag attribute + // that will cause the wireframe to be rendered correctly. + VTK_CREATE(vtkPolyData, nextStageInput); + nextStageInput->ShallowCopy(output); // Yes output is correct. + this->RecoverWireframeFilter->SetInput(nextStageInput); + + // Observe the progress of the internal filter. + // TODO: Make the consecutive internal filter execution have monotonically + // increasing progress rather than restarting for every internal filter. + this->RecoverWireframeFilter->AddObserver( + vtkCommand::ProgressEvent, + this->InternalProgressObserver); + this->RecoverWireframeFilter->Update(); + // The internal filter finished. Remove the observer. + this->RecoverWireframeFilter->RemoveObserver( + this->InternalProgressObserver); + + this->RecoverWireframeFilter->SetInput(NULL); + + // Get what should be the final output. + output->ShallowCopy(this->RecoverWireframeFilter->GetOutput()); + } + return; } @@ -1132,6 +1245,10 @@ "DataSetSurfaceFilter"); vtkGarbageCollectorReport(collector, this->GenericGeometryFilter, "GenericGeometryFilter"); + vtkGarbageCollectorReport(collector, this->UnstructuredGridGeometryFilter, + "UnstructuredGridGeometryFilter"); + vtkGarbageCollectorReport(collector, this->RecoverWireframeFilter, + "RecoverWireframeFilter"); } //---------------------------------------------------------------------------- @@ -1152,6 +1269,8 @@ os << indent << "UseStrips: " << (this->UseStrips?"on":"off") << endl; os << indent << "GenerateCellNormals: " << (this->GenerateCellNormals?"on":"off") << endl; + os << indent << "NonlinearSubdivisionLevel: " + << this->NonlinearSubdivisionLevel << endl; os << indent << "Controller: " << this->Controller << endl; os << indent << "PassThroughCellIds: " @@ -1235,3 +1354,20 @@ this->StripSettingMTime.Modified(); } } + +//----------------------------------------------------------------------------- +void vtkPVGeometryFilter::SetNonlinearSubdivisionLevel(int newvalue) +{ + if (this->NonlinearSubdivisionLevel != newvalue) + { + this->NonlinearSubdivisionLevel = newvalue; + + if (this->DataSetSurfaceFilter) + { + this->DataSetSurfaceFilter->SetNonlinearSubdivisionLevel( + this->NonlinearSubdivisionLevel); + } + + this->Modified(); + } +} Index: Servers/Filters/vtkPVGeometryFilter.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/Filters/vtkPVGeometryFilter.h,v retrieving revision 1.45 diff -u -r1.45 vtkPVGeometryFilter.h --- Servers/Filters/vtkPVGeometryFilter.h 22 Sep 2008 18:16:00 -0000 1.45 +++ Servers/Filters/vtkPVGeometryFilter.h 12 Jun 2009 20:06:32 -0000 @@ -35,9 +35,11 @@ class vtkCompositeDataSet; class vtkMultiProcessController; class vtkOutlineSource; +class vtkPVRecoverGeometryWireframe; class vtkRectilinearGrid; class vtkStructuredGrid; class vtkUnstructuredGrid; +class vtkUnstructuredGridGeometryFilter; class VTK_EXPORT vtkPVGeometryFilter : public vtkPolyDataAlgorithm { @@ -80,6 +82,15 @@ vtkBooleanMacro(GenerateCellNormals, int); // Description: + // Nonlinear faces are approximated with flat polygons. This parameter + // controls how many times to subdivide nonlinear surface cells. Higher + // subdivisions generate closer approximations but take more memory and + // rendering time. Subdivision is recursive, so the number of output polygons + // can grow exponentially with this parameter. + virtual void SetNonlinearSubdivisionLevel(int); + vtkGetMacro(NonlinearSubdivisionLevel, int); + + // Description: // Set and get the controller. virtual void SetController(vtkMultiProcessController*); vtkGetObjectMacro(Controller, vtkMultiProcessController); @@ -151,11 +162,14 @@ int UseOutline; int UseStrips; int GenerateCellNormals; + int NonlinearSubdivisionLevel; vtkMultiProcessController* Controller; vtkOutlineSource *OutlineSource; vtkDataSetSurfaceFilter* DataSetSurfaceFilter; vtkGenericGeometryFilter *GenericGeometryFilter; + vtkUnstructuredGridGeometryFilter *UnstructuredGridGeometryFilter; + vtkPVRecoverGeometryWireframe *RecoverWireframeFilter; int CheckAttributes(vtkDataObject* input); Index: Servers/Filters/vtkPVRecoverGeometryWireframe.cxx =================================================================== RCS file: Servers/Filters/vtkPVRecoverGeometryWireframe.cxx diff -N Servers/Filters/vtkPVRecoverGeometryWireframe.cxx --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Servers/Filters/vtkPVRecoverGeometryWireframe.cxx 12 Jun 2009 20:06:32 -0000 @@ -0,0 +1,308 @@ +// -*- c++ -*- +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: pqBlotDialog.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*------------------------------------------------------------------------- + Copyright 2009 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, + the U.S. Government retains certain rights in this software. +-------------------------------------------------------------------------*/ + +#include "vtkPVRecoverGeometryWireframe.h" + +#include "vtkCellArray.h" +#include "vtkCellData.h" +#include "vtkIdTypeArray.h" +#include "vtkObjectFactory.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" +#include "vtkUnsignedCharArray.h" + +#include "vtkSmartPointer.h" +#define VTK_CREATE(type, name) \ + vtkSmartPointer<type> name = vtkSmartPointer<type>::New() + +#include <vtkstd/algorithm> +#include <vtkstd/vector> +#include <vtksys/hash_map.hxx> + +static const unsigned char NO_EDGE_FLAG = static_cast<unsigned char >(-1); + +//============================================================================= +namespace vtkPVRecoverGeometryWireframeNamespace +{ + // Description: + // Simple class used internally to define an edge based on the endpoints. The + // endpoints are canonically identified by the lower and higher values. + class EdgeEndpoints + { + public: + EdgeEndpoints() : MinEndPoint(-1), MaxEndPoint(-1) {} + EdgeEndpoints(vtkIdType endpointA, vtkIdType endpointB) + : MinEndPoint((endpointA < endpointB) ? endpointA : endpointB), + MaxEndPoint((endpointA < endpointB) ? endpointB : endpointA) + {} + const vtkIdType MinEndPoint; + const vtkIdType MaxEndPoint; + inline bool operator==(const EdgeEndpoints &other) const { + return ( (this->MinEndPoint == other.MinEndPoint) + && (this->MaxEndPoint == other.MaxEndPoint) ); + } + }; + struct EdgeEndpointsHash { + public: + size_t operator()(const EdgeEndpoints &edge) const { + return static_cast<size_t>(edge.MinEndPoint + edge.MaxEndPoint); + } + }; + + // Description: + // Holds the information necessary for the facet this edge came from. + class EdgeInformation + { + public: + vtkIdType OriginalFaceId; + vtkIdType *StartPointIdP; + }; + + // Description: + // A map from edge endpoints to the information about that edge. + typedef vtksys::hash_map<EdgeEndpoints, EdgeInformation, EdgeEndpointsHash> + EdgeMapType; + + void RecordEdgeFlag(vtkPolyData *output, const EdgeInformation &edgeInfo, + vtkUnsignedCharArray *edgeFlagArray, unsigned char flag, + vtkIdType *duplicatePointMap) + { + vtkIdType pt = edgeInfo.StartPointIdP[0]; + if (edgeFlagArray->GetValue(pt) == flag) + { + // Edge flag already set correctly. Nothing to do. + return; + } + if (edgeFlagArray->GetValue(pt) == NO_EDGE_FLAG) + { + // Nothing has set the edge flag yet. Just set it and return. + edgeFlagArray->SetValue(pt, flag); + return; + } + + // If we are here then some other cell has already put a flag on this + // point different than ours. We have to adjust our cell topology to + // use a duplicate point. + if (duplicatePointMap[pt] == -1) + { + // No duplicate made. We need to make one. + vtkPoints *points = output->GetPoints(); + double coords[3]; + points->GetPoint(pt, coords); + vtkIdType newPt = points->InsertNextPoint(coords); + duplicatePointMap[pt] = newPt; + // Copying attributes from yourself seems weird, but is valid. + vtkPointData *pd = output->GetPointData(); + pd->CopyData(pd, pt, newPt); + edgeFlagArray->InsertValue(newPt, flag); + } + edgeInfo.StartPointIdP[0] = duplicatePointMap[pt]; + } +} +using namespace vtkPVRecoverGeometryWireframeNamespace; + +//============================================================================= +vtkCxxRevisionMacro(vtkPVRecoverGeometryWireframe, "$Revision$"); +vtkStandardNewMacro(vtkPVRecoverGeometryWireframe); + +//----------------------------------------------------------------------------- +vtkPVRecoverGeometryWireframe::vtkPVRecoverGeometryWireframe() +{ +} + +vtkPVRecoverGeometryWireframe::~vtkPVRecoverGeometryWireframe() +{ +} + +void vtkPVRecoverGeometryWireframe::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +//----------------------------------------------------------------------------- +int vtkPVRecoverGeometryWireframe::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + vtkPolyData *input = vtkPolyData::GetData(inputVector[0]); + vtkPolyData *output = vtkPolyData::GetData(outputVector); + + vtkIdType npts, *pts; + vtkstd::vector<vtkIdType> originalPts; + + if (!input->GetCellData()->HasArray(ORIGINAL_FACE_IDS())) + { + // Did not find the field used to identify the face each linear patch comes + // from. The original data was probably linear so using all the edges + // should be OK (and is at least the best we can do), so just pass the data. + output->ShallowCopy(input); + return 1; + } + + vtkIdTypeArray *faceIds = vtkIdTypeArray::SafeDownCast( + input->GetCellData()->GetAbstractArray(ORIGINAL_FACE_IDS())); + if (!faceIds) + { + vtkErrorMacro(<< ORIGINAL_FACE_IDS() << " array is not of expected type."); + return 0; + } + + // Shallow copy the cell data. All the cells get copied to output. + output->GetCellData()->PassData(input->GetCellData()); + + // Deep copy the point information and be ready to add points. + VTK_CREATE(vtkPoints, points); + points->DeepCopy(input->GetPoints()); + output->SetPoints(points); + vtkPointData *inputPD = input->GetPointData(); + vtkPointData *outputPD = output->GetPointData(); + outputPD->CopyAllocate(inputPD); + vtkIdType numOriginalPoints = points->GetNumberOfPoints(); + for (vtkIdType i = 0; i < numOriginalPoints; i++) + { + outputPD->CopyData(inputPD, i, i); + } + + // Create an edge flag array. + VTK_CREATE(vtkUnsignedCharArray, edgeflags); + edgeflags->SetName("vtkEdgeFlags"); + outputPD->AddArray(edgeflags); + outputPD->SetActiveAttribute("vtkEdgeFlags", vtkDataSetAttributes::EDGEFLAG); + edgeflags->SetNumberOfComponents(1); + edgeflags->SetNumberOfTuples(numOriginalPoints); + vtkstd::fill(edgeflags->GetPointer(0), + edgeflags->GetPointer(numOriginalPoints), NO_EDGE_FLAG); + + // Some (probably many) points will have to be duplicated because different + // cells will need different edge flags. This array maps the original + // point id to the duplicate id. + vtkstd::vector<vtkIdType> duplicatePointMap(numOriginalPoints); + vtkstd::fill(duplicatePointMap.begin(), duplicatePointMap.end(), -1); + + // Shallow copy the verts. Set the edge flags to true. + vtkCellArray *inputVerts = input->GetVerts(); + output->SetVerts(inputVerts); + for (inputVerts->InitTraversal(); inputVerts->GetNextCell(npts, pts); ) + { + for (vtkIdType i = 0; i < npts; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Shallow copy the lines. Set the edge flags to true. + vtkCellArray *inputLines = input->GetLines(); + output->SetLines(inputLines); + for (inputLines->InitTraversal(); inputLines->GetNextCell(npts, pts); ) + { + // No need to set edge flag for last index. + for (vtkIdType i = 0; i < npts-1; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Shallow copy the triangle strips. Set the edge flags to true. + vtkCellArray *inputStrips = input->GetStrips(); + output->SetStrips(inputStrips); + for (inputStrips->InitTraversal(); inputStrips->GetNextCell(npts, pts); ) + { + for (vtkIdType i = 0; i < npts; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Deep copy the polygons because we will be changing some indices when we + // duplicate points. + VTK_CREATE(vtkCellArray, outputPolys); + outputPolys->DeepCopy(input->GetPolys()); + output->SetPolys(outputPolys); + + // Iterate over all the input facets and see which edge interfaces belonged to + // different faces. We do that by recording the original face id in a map. + // When we find a pair of edges, we turn on the appropriate edge flag if they + // came from different faces, or turn it off if they came from the same face. + EdgeMapType edgeMap; + vtkIdType inputCellId + = inputVerts->GetNumberOfCells() + inputLines->GetNumberOfCells(); + for (outputPolys->InitTraversal(); outputPolys->GetNextCell(npts, pts); + inputCellId++) + { + if ((inputCellId%1000) == 0) + { + this->UpdateProgress(static_cast<double>(inputCellId) + /input->GetNumberOfCells()); + if (this->GetAbortExecute()) return 0; + } + // Record the original points of the polygon. As we iterate over edges, + // we may change the indices, but we allways compare edges by the original + // indices. + originalPts.resize(npts); + vtkstd::copy(pts, pts+npts, originalPts.begin()); + vtkIdType originalFace = faceIds->GetValue(inputCellId); + for (vtkIdType i = 0; i < npts; i++) + { + EdgeEndpoints edge(originalPts[i], originalPts[(i+1)%npts]); + EdgeInformation edgeInfo; + edgeInfo.OriginalFaceId = originalFace; + edgeInfo.StartPointIdP = &pts[i]; + + EdgeMapType::iterator edgeMatch = edgeMap.find(edge); + if (edgeMatch == edgeMap.end()) + { + // Not encountered yet. Add to the map. + edgeMap.insert(vtkstd::make_pair(edge, edgeInfo)); + } + else + { + // The edge flag is true if the edge connects two different faces. + unsigned char eflag = static_cast<unsigned char>( + edgeMatch->second.OriginalFaceId != originalFace); + RecordEdgeFlag(output, edgeMatch->second, edgeflags, eflag, + &duplicatePointMap.at(0)); + RecordEdgeFlag(output, edgeInfo, edgeflags, eflag, + &duplicatePointMap.at(0)); + // Remove the edge from the map since we already found the pair. + edgeMap.erase(edgeMatch); + } + } // For each edge + } // For each cell. + + // Everything left in the edge map has no match. It must necessarily be + // on the outside of a face. + for (EdgeMapType::iterator iter = edgeMap.begin(); + iter != edgeMap.end(); iter++) + { + RecordEdgeFlag(output, iter->second, edgeflags, 1, + &duplicatePointMap.at(0)); + } + + // If any points are unmarked, set some edge flag on them (although they + // are probably not referenced by any cell). + for (vtkIdType i = 0; i < numOriginalPoints; i++) + { + if (edgeflags->GetValue(i) == NO_EDGE_FLAG) edgeflags->SetValue(i, 1); + } + + return 1; +} Index: Servers/Filters/vtkPVRecoverGeometryWireframe.h =================================================================== RCS file: Servers/Filters/vtkPVRecoverGeometryWireframe.h diff -N Servers/Filters/vtkPVRecoverGeometryWireframe.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Servers/Filters/vtkPVRecoverGeometryWireframe.h 12 Jun 2009 20:06:32 -0000 @@ -0,0 +1,73 @@ +// -*- c++ -*- +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: pqBlotDialog.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*------------------------------------------------------------------------- + Copyright 2009 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, + the U.S. Government retains certain rights in this software. +-------------------------------------------------------------------------*/ + +// .NAME vtkPVRecoverGeometryWireframe - Get corrected wireframe from tesselated facets +// +// .SECTION Description +// +// When vtkPVGeometryFilter tessellates nonlinear faces into linear +// approximations, it introduces edges in the middle of the facets of the +// original mesh (as any valid tessellation would). To correct for this, +// vtkPVGeometryFilter also writes out some fields that allows use to identify +// the edges that are actually part of the original mesh. This filter works in +// conjunction with vtkPVGeometryFilter by taking its output, adding an edge +// flag and making the appropriate adjustments so that rendering with line +// fill mode will make the correct wireframe. +// +// .SECTION See Also +// vtkPVGeometryFilter +// + +#ifndef __vtkPVRecoverGeometryWireframe_h +#define __vtkPVRecoverGeometryWireframe_h + +#include "vtkPolyDataAlgorithm.h" + +class VTK_EXPORT vtkPVRecoverGeometryWireframe : public vtkPolyDataAlgorithm +{ +public: + vtkTypeRevisionMacro(vtkPVRecoverGeometryWireframe, vtkPolyDataAlgorithm); + static vtkPVRecoverGeometryWireframe *New(); + virtual void PrintSelf(ostream &os, vtkIndent indent); + + // Description: + // In order to determine which edges existed in the original data, we need an + // identifier on each cell determining which face (not cell) it originally + // came from. The ids should be put in a cell data array with this name. The + // existance of this field is also a signal that this wireframe extraction is + // necessary. + static const char *ORIGINAL_FACE_IDS() + { return "vtkPVRecoverWireframeOriginalFaceIds"; } + +protected: + vtkPVRecoverGeometryWireframe(); + ~vtkPVRecoverGeometryWireframe(); + + virtual int RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + +private: + vtkPVRecoverGeometryWireframe(const vtkPVRecoverGeometryWireframe &); // Not implemented + void operator=(const vtkPVRecoverGeometryWireframe &); // Not implemented +}; + +#endif //__vtkPVRecoverGeometryWireframe_h Index: Servers/ServerManager/Resources/filters.xml =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/ServerManager/Resources/filters.xml,v retrieving revision 1.353 diff -u -r1.353 filters.xml --- Servers/ServerManager/Resources/filters.xml 12 Jun 2009 14:19:58 -0000 1.353 +++ Servers/ServerManager/Resources/filters.xml 12 Jun 2009 20:06:32 -0000 @@ -1524,6 +1524,26 @@ If the value of this property is set to 1, internal surfaces along process boundaries will be removed. NOTE: Enabling this option might cause multiple executions of the data source because more information is needed to remove internal surfaces. </Documentation> </IntVectorProperty> + + <IntVectorProperty name="NonlinearSubdivisionLevel" + command="SetNonlinearSubdivisionLevel" + number_of_elements="1" + default_values="1"> + <IntRangeDomain name="range" min="0" max="4" /> + <Documentation> + If the input is an unstructured grid with nonlinear faces, this + parameter determines how many times the face is subdivided into + linear faces. If 0, the output is the equivalent of its linear + couterpart (and the midpoints determining the nonlinear + interpolation are discarded). If 1, the nonlinear face is + triangulated based on the midpoints. If greater than 1, the + triangulated pieces are recursively subdivided to reach the + desired subdivision. Setting the value to greater than 1 may + cause some point data to not be passed even if no quadratic faces + exist. This option has no effect if the input is not an + unstructured grid. + </Documentation> + </IntVectorProperty> <!-- End DataSetSurfaceFilter --> </SourceProxy> @@ -6863,6 +6883,20 @@ Toggle whether to generate an outline or a surface. </Documentation> </IntVectorProperty> + <IntVectorProperty name="NonlinearSubdivisionLevel" + command="SetNonlinearSubdivisionLevel" + number_of_elements="1" + default_values="1"> + <IntRangeDomain name="range" min="0" max="4" /> + <Documentation> + Nonlinear faces are approximated with flat polygons. This + parameter controls how many times to subdivide nonlinear surface + cells. Higher subdivisions generate closer approximations but + take more memory and rendering time. Subdivision is recursive, + so the number of output polygons can grow exponentially with this + parameter. + </Documentation> + </IntVectorProperty> <IntVectorProperty name="PassThroughIds" command="SetPassThroughCellIds" Index: Servers/ServerManager/Resources/rendering.xml =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/Servers/ServerManager/Resources/rendering.xml,v retrieving revision 1.352 diff -u -r1.352 rendering.xml --- Servers/ServerManager/Resources/rendering.xml 9 Jun 2009 17:38:12 -0000 1.352 +++ Servers/ServerManager/Resources/rendering.xml 12 Jun 2009 20:06:32 -0000 @@ -5861,7 +5861,7 @@ <SubProxy> <!-- - Geometry filter is used to conver non-polydata input to polydata. + Geometry filter is used to convert non-polydata input to polydata. It is also used to convert poly data to triangle strips when requested. --> @@ -5870,6 +5870,7 @@ <ExposedProperties> <Property name="UseStrips" /> <Property name="ForceStrips" /> + <Property name="NonlinearSubdivisionLevel" /> </ExposedProperties> </SubProxy> @@ -6651,6 +6652,7 @@ <!-- Geometry Filter properties --> <Property name="UseStrips" /> <Property name="ForceStrips" /> + <Property name="NonlinearSubdivisionLevel" /> <!-- Mapper properties --> <Property name="LookupTable" /> Index: VTK/Filtering/vtkCellType.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Filtering/vtkCellType.h,v retrieving revision 1.5 diff -u -r1.5 vtkCellType.h --- VTK/Filtering/vtkCellType.h 7 May 2007 15:40:59 -0000 1.5 +++ VTK/Filtering/vtkCellType.h 12 Jun 2009 20:06:32 -0000 @@ -29,7 +29,8 @@ // GetCell() and vtkGenericCell::SetCellType(). Also, to do the job right, // you'll also have to modify some filters (vtkGeometryFilter...) and // regression tests (example scripts) to reflect the new cell addition. -// Also, make sure to update vtkCellTypesStrings in vtkCellTypes.cxx. +// Also, make sure to update vtkCellTypesStrings in vtkCellTypes.cxx +// and the vtkCellTypes::IsLinear method in vtkCellTypes.h. // .SECTION Caveats // An unstructured grid stores the types of its cells as a Index: VTK/Filtering/vtkCellTypes.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Filtering/vtkCellTypes.h,v retrieving revision 1.3 diff -u -r1.3 vtkCellTypes.h --- VTK/Filtering/vtkCellTypes.h 11 Dec 2008 21:47:19 -0000 1.3 +++ VTK/Filtering/vtkCellTypes.h 12 Jun 2009 20:06:32 -0000 @@ -118,6 +118,13 @@ // defined in vtkCellType.h) static int GetTypeIdFromClassName(const char* classname); + // Description: + // This convenience method is a fast check to determine if a cell type + // represents a linear or nonlinear cell. This is generally much more + // efficient than getting the appropriate vtkCell and checking its IsLinear + // method. + static int IsLinear(unsigned char type); + protected: vtkCellTypes(); ~vtkCellTypes(); @@ -148,5 +155,11 @@ return 0; } +//----------------------------------------------------------------------------- +inline int vtkCellTypes::IsLinear(unsigned char type) +{ + return ((type <= 20) || (type == VTK_CONVEX_POINT_SET)); +} + #endif Index: VTK/Filtering/vtkDataSetAttributes.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Filtering/vtkDataSetAttributes.cxx,v retrieving revision 1.30 diff -u -r1.30 vtkDataSetAttributes.cxx --- VTK/Filtering/vtkDataSetAttributes.cxx 9 Oct 2008 16:27:50 -0000 1.30 +++ VTK/Filtering/vtkDataSetAttributes.cxx 12 Jun 2009 20:06:32 -0000 @@ -43,7 +43,9 @@ "TCoords", "Tensors", "GlobalIds", - "PedigreeIds" }; + "PedigreeIds", + "EdgeFlag" +}; const char vtkDataSetAttributes ::LongAttributeNames[vtkDataSetAttributes::NUM_ATTRIBUTES][35] = @@ -53,7 +55,9 @@ "vtkDataSetAttributes::TCOORDS", "vtkDataSetAttributes::TENSORS", "vtkDataSetAttributes::GLOBALIDS", - "vtkDataSetAttributes::PEDIGREEIDS" }; + "vtkDataSetAttributes::PEDIGREEIDS", + "vtkDataSetAttributes::EDGEFLAG" +}; //-------------------------------------------------------------------------- // Construct object with copying turned on for all data. @@ -1064,6 +1068,7 @@ 3, 9, 1, + 1, 1}; //-------------------------------------------------------------------------- @@ -1076,6 +1081,7 @@ MAX, EXACT, EXACT, + EXACT, EXACT}; //-------------------------------------------------------------------------- Index: VTK/Filtering/vtkDataSetAttributes.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Filtering/vtkDataSetAttributes.h,v retrieving revision 1.13 diff -u -r1.13 vtkDataSetAttributes.h --- VTK/Filtering/vtkDataSetAttributes.h 11 Jun 2009 19:16:48 -0000 1.13 +++ VTK/Filtering/vtkDataSetAttributes.h 12 Jun 2009 20:06:32 -0000 @@ -90,6 +90,7 @@ TENSORS=4, GLOBALIDS=5, PEDIGREEIDS=6, + EDGEFLAG=7, NUM_ATTRIBUTES }; @@ -165,6 +166,7 @@ // vtkDataSetAttributes::TENSORS = 4 // vtkDataSetAttributes::GLOBALIDS = 5 // vtkDataSetAttributes::PEDIGREEIDS = 6 + // vtkDataSetAttributes::EDGEFLAG = 7 // Returns the index of the array if succesful, -1 if the array // is not in the list of arrays. int SetActiveAttribute(const char* name, int attributeType); Index: VTK/Graphics/vtkDataSetSurfaceFilter.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Graphics/vtkDataSetSurfaceFilter.cxx,v retrieving revision 1.70 diff -u -r1.70 vtkDataSetSurfaceFilter.cxx --- VTK/Graphics/vtkDataSetSurfaceFilter.cxx 25 Mar 2009 14:35:52 -0000 1.70 +++ VTK/Graphics/vtkDataSetSurfaceFilter.cxx 12 Jun 2009 20:06:32 -0000 @@ -16,8 +16,10 @@ #include "vtkCellArray.h" #include "vtkCellData.h" +#include "vtkDoubleArray.h" #include "vtkGenericCell.h" #include "vtkHexahedron.h" +#include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMergePoints.h" @@ -26,18 +28,19 @@ #include "vtkPolyData.h" #include "vtkPyramid.h" #include "vtkRectilinearGrid.h" -#include "vtkStructuredGrid.h" -#include "vtkUniformGrid.h" #include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkStructuredGrid.h" #include "vtkStructuredGridGeometryFilter.h" #include "vtkStructuredPoints.h" #include "vtkTetra.h" +#include "vtkUniformGrid.h" #include "vtkUnsignedCharArray.h" #include "vtkUnstructuredGrid.h" #include "vtkVoxel.h" #include "vtkWedge.h" -#include "vtkIdTypeArray.h" +#include <vtkstd/algorithm> +#include <vtksys/hash_map.hxx> static int sizeofFastQuad(int numPts) { @@ -45,6 +48,39 @@ return static_cast<int>(sizeof(vtkFastGeomQuad)+(numPts-4)*sizeof(vtkIdType)); } +class vtkDataSetSurfaceFilter::vtkEdgeInterpolationMap +{ +public: + void AddEdge(vtkIdType endpoint1, vtkIdType endpoint2, vtkIdType midpoint) { + if (endpoint1 > endpoint2) vtkstd::swap(endpoint1, endpoint2); + Map.insert(vtkstd::make_pair(vtkstd::make_pair(endpoint1, endpoint2), + midpoint)); + } + vtkIdType FindEdge(vtkIdType endpoint1, vtkIdType endpoint2) { + if (endpoint1 > endpoint2) vtkstd::swap(endpoint1, endpoint2); + MapType::iterator iter = Map.find(vtkstd::make_pair(endpoint1, endpoint2)); + if (iter != Map.end()) + { + return iter->second; + } + else + { + return -1; + } + } + +protected: + struct HashFunction { + public: + size_t operator()(vtkstd::pair<vtkIdType,vtkIdType> edge) const { + return static_cast<size_t>(edge.first + edge.second); + } + }; + typedef vtksys::hash_map<vtkstd::pair<vtkIdType, vtkIdType>, vtkIdType, + HashFunction> MapType; + MapType Map; +}; + vtkCxxRevisionMacro(vtkDataSetSurfaceFilter, "$Revision: 1.70 $"); vtkStandardNewMacro(vtkDataSetSurfaceFilter); @@ -53,6 +89,7 @@ { this->QuadHash = NULL; this->PointMap = NULL; + this->EdgeMap = NULL; this->QuadHashLength = 0; this->UseStrips = 0; this->NumberOfNewCells = 0; @@ -70,6 +107,10 @@ this->PassThroughPointIds = 0; this->OriginalCellIds = NULL; this->OriginalPointIds = NULL; + this->OriginalCellIdsName = NULL; + this->OriginalPointIdsName = NULL; + + this->NonlinearSubdivisionLevel = 1; } //---------------------------------------------------------------------------- @@ -179,7 +220,7 @@ { //make a 1:1 mapping this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); vtkCellData *outputCD = output->GetCellData(); outputCD->AddArray(this->OriginalCellIds); @@ -196,7 +237,7 @@ { //make a 1:1 mapping this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); vtkPointData *outputPD = output->GetPointData(); outputPD->AddArray(this->OriginalPointIds); @@ -348,14 +389,14 @@ if (this->PassThroughCellIds) { this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); output->GetCellData()->AddArray(this->OriginalCellIds); } if (this->PassThroughPointIds) { this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); output->GetPointData()->AddArray(this->OriginalPointIds); } @@ -916,6 +957,8 @@ os << indent << "PassThroughCellIds: " << (this->PassThroughCellIds ? "On\n" : "Off\n"); os << indent << "PassThroughPointIds: " << (this->PassThroughPointIds ? "On\n" : "Off\n"); + os << indent << "NonlinearSubdivisionLevel: " + << this->NonlinearSubdivisionLevel << endl; } //======================================================================== @@ -949,7 +992,6 @@ vtkCellData *cd = input->GetCellData(); vtkPointData *outputPD = output->GetPointData(); vtkCellData *outputCD = output->GetCellData(); - vtkIdType outPts[6]; vtkFastGeomQuad *q; unsigned char* cellTypes = input->GetCellTypesArray()->GetPointer(0); @@ -958,9 +1000,19 @@ vtkPoints *coords; vtkCell *face; int flag2D = 0; + + // These are for subdividing quadratic cells + vtkDoubleArray *parametricCoords; + vtkDoubleArray *parametricCoords2; + vtkIdList *outPts; + vtkIdList *outPts2; pts = vtkIdList::New(); coords = vtkPoints::New(); + parametricCoords = vtkDoubleArray::New(); + parametricCoords2 = vtkDoubleArray::New(); + outPts = vtkIdList::New(); + outPts2 = vtkIdList::New(); // might not be necessary to set the data type for coords // but certainly safer to do so coords->SetDataType(input->GetPoints()->GetData()->GetDataType()); @@ -979,21 +1031,28 @@ newVerts = vtkCellArray::New(); newLines = vtkCellArray::New(); - outputPD->CopyGlobalIdsOn(); - outputPD->CopyAllocate(inputPD, numPts, numPts/2); + if (this->NonlinearSubdivisionLevel <= 1) + { + outputPD->CopyGlobalIdsOn(); + outputPD->CopyAllocate(inputPD, numPts, numPts/2); + } + else + { + outputPD->InterpolateAllocate(inputPD, numPts, numPts/2); + } outputCD->CopyGlobalIdsOn(); outputCD->CopyAllocate(inputCD, numCells, numCells/2); if (this->PassThroughCellIds) { this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); } if (this->PassThroughPointIds) { this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); } @@ -1201,14 +1260,40 @@ if ( cellIds->GetNumberOfIds() <= 0) { // FIXME: Face could not be consistent. vtkOrderedTriangulator is a better option - face->Triangulate(0,pts,coords); - for (i=0; i < pts->GetNumberOfIds(); i+=3) + if (this->NonlinearSubdivisionLevel >= 1) { - this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1), - pts->GetId(i+2), cellId); + // TODO: Handle NonlinearSubdivisionLevel > 1 correctly. + face->Triangulate(0,pts,coords); + for (i=0; i < pts->GetNumberOfIds(); i+=3) + { + this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1), + pts->GetId(i+2), cellId); + } } - } - } + else + { + switch (face->GetCellType()) + { + case VTK_QUADRATIC_TRIANGLE: + this->InsertTriInHash(face->PointIds->GetId(0), + face->PointIds->GetId(1), + face->PointIds->GetId(2), cellId); + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + case VTK_QUADRATIC_LINEAR_QUAD: + this->InsertQuadInHash(face->PointIds->GetId(0), + face->PointIds->GetId(1), + face->PointIds->GetId(2), + face->PointIds->GetId(3), cellId); + break; + default: + vtkWarningMacro(<< "Encountered unknown nonlinear face."); + break; + } // switch cell type + } // subdivision level + } // cell has ids + } // for faces cellIds->Delete(); } //3d cell } //nonlinear cell @@ -1232,6 +1317,25 @@ // Move to the next cell. cellPointer += (1 + *cellPointer); + // If we have a quadratic face and our subdivision level is zero, just treat + // it as a linear cell. This should work so long as the first points of the + // quadratic cell correspond to all those of the equivalent linear cell + // (which all the current definitions do). + if (this->NonlinearSubdivisionLevel < 1) + { + switch (cellType) + { + case VTK_QUADRATIC_TRIANGLE: + cellType = VTK_TRIANGLE; numCellPts = 3; + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + case VTK_QUADRATIC_LINEAR_QUAD: + cellType = VTK_POLYGON; numCellPts = 4; + break; + } + } + // A couple of common cases to see if things go faster. if (cellType == VTK_PIXEL) { // Do we really want to insert the 2D cells into a hash? @@ -1283,14 +1387,99 @@ || cellType == VTK_BIQUADRATIC_QUAD || cellType == VTK_QUADRATIC_LINEAR_QUAD) { + // Note: we should not be here if this->NonlinearSubdivisionLevel is less + // than 1. See the check above. input->GetCell( cellId, cell ); cell->Triangulate( 0, pts, coords ); - for ( i=0; i < pts->GetNumberOfIds(); i+=3 ) + // Copy the level 1 subdivision points (which also exist in the input and + // can therefore just be copied over. Note that the output of Triangulate + // records triangles in pts where each 3 points defines a triangle. We + // will keep this invariant and also keep the same invariant in + // parametericCoords and outPts later. + outPts->Reset(); + for ( i=0; i < pts->GetNumberOfIds(); i++ ) + { + vtkIdType op; + op = this->GetOutputPointId(pts->GetId(i), input, newPts, outputPD); + outPts->InsertNextId(op); + } + // Do any further subdivision if necessary. + if (this->NonlinearSubdivisionLevel > 1) + { + // We are going to need parametric coordinates to further subdivide. + double *pc = cell->GetParametricCoords(); + parametricCoords->Reset(); + parametricCoords->SetNumberOfComponents(3); + for (i = 0; i < pts->GetNumberOfIds(); i++) + { + vtkIdType ptId = pts->GetId(i); + vtkIdType cellPtId; + for (cellPtId = 0; cell->GetPointId(cellPtId) != ptId; cellPtId++); + parametricCoords->InsertNextTupleValue(pc + 3*cellPtId); + } + // Subdivide these triangles as many more times as necessary. Remember + // that we have already done the first subdivision. + for (j = 1; j < this->NonlinearSubdivisionLevel; j++) + { + parametricCoords2->Reset(); + parametricCoords2->SetNumberOfComponents(3); + outPts2->Reset(); + // Each triangle will be split into 4 triangles. + for (i = 0; i < outPts->GetNumberOfIds(); i += 3) + { + // Hold the input point ids and parametric coordinates. First 3 + // indices are the original points. Second three are the midpoints + // in the edges (0,1), (1,2) and (2,0), respectively (see comment + // below). + vtkIdType inPts[6]; + double inParamCoords[6][3]; + int k; + for (k = 0; k < 3; k++) + { + inPts[k] = outPts->GetId(i+k); + parametricCoords->GetTupleValue(i+k, inParamCoords[k]); + } + for (k = 3; k < 6; k++) + { + int pt1 = k-3; + int pt2 = (pt1 < 2) ? (pt1 + 1) : 0; + inParamCoords[k][0] = 0.5*(inParamCoords[pt1][0] + inParamCoords[pt2][0]); + inParamCoords[k][1] = 0.5*(inParamCoords[pt1][1] + inParamCoords[pt2][1]); + inParamCoords[k][2] = 0.5*(inParamCoords[pt1][2] + inParamCoords[pt2][2]); + inPts[k] = GetInterpolatedPointId(inPts[pt1], inPts[pt2], + input, cell, + inParamCoords[k], newPts, + outputPD); + } + // * 0 + // / \ Use the 6 points recorded + // / \ in inPts and inParamCoords + // 3 *-----* 5 to create the 4 triangles + // / \ / \ shown here. + // / \ / \ . + // *-----*-----* + // 1 4 2 + const int subtriangles[12] = {0,3,5, 3,1,4, 3,4,5, 5,4,2}; + for (k = 0; k < 12; k++) + { + int localId = subtriangles[k]; + outPts2->InsertNextId(inPts[localId]); + parametricCoords2->InsertNextTupleValue(inParamCoords[localId]); + } + } // Iterate over triangles + // Now that we have recorded the subdivided triangles in outPts2 and + // parametricCoords2, swap them with outPts and parametricCoords to + // make them the current ones. + vtkstd::swap(outPts, outPts2); + vtkstd::swap(parametricCoords, parametricCoords2); + } // Iterate over subdivision levels + } // If further subdivision + + // Now that we have done all the subdivisions and created all of the + // points, record the triangles. + for (i = 0; i < outPts->GetNumberOfIds(); i += 3) { - outPts[0] = this->GetOutputPointId( pts->GetId(i), input, newPts, outputPD ); - outPts[1] = this->GetOutputPointId( pts->GetId(i+1), input, newPts, outputPD ); - outPts[2] = this->GetOutputPointId( pts->GetId(i+2), input, newPts, outputPD ); - newPolys->InsertNextCell( 3, outPts ); + newPolys->InsertNextCell(3, outPts->GetPointer(i)); this->RecordOrigCellId(this->NumberOfNewCells, cellId); outputCD->CopyData(cd, cellId, this->NumberOfNewCells++); } @@ -1326,6 +1515,10 @@ cell->Delete(); coords->Delete(); pts->Delete(); + parametricCoords->Delete(); + parametricCoords2->Delete(); + outPts->Delete(); + outPts2->Delete(); output->SetPoints(newPts); newPts->Delete(); @@ -1387,6 +1580,7 @@ this->QuadHash[i] = NULL; this->PointMap[i] = -1; } + this->EdgeMap = new vtkEdgeInterpolationMap; } //---------------------------------------------------------------------------- @@ -1406,6 +1600,8 @@ this->QuadHashLength = 0; delete [] this->PointMap; this->PointMap = NULL; + delete this->EdgeMap; + this->EdgeMap = NULL; } //---------------------------------------------------------------------------- @@ -1800,6 +1996,34 @@ return outPtId; } +//----------------------------------------------------------------------------- +vtkIdType vtkDataSetSurfaceFilter::GetInterpolatedPointId(vtkIdType edgePtA, + vtkIdType edgePtB, + vtkDataSet *input, + vtkCell *cell, + double pcoords[3], + vtkPoints *outPts, + vtkPointData *outPD) +{ + vtkIdType outPtId; + + outPtId = this->EdgeMap->FindEdge(edgePtA, edgePtB); + if (outPtId == -1) + { + int subId = -1; + double wcoords[3]; + double weights[100]; // Any reason to need more? + cell->EvaluateLocation(subId, pcoords, wcoords, weights); + outPtId = outPts->InsertNextPoint(wcoords); + outPD->InterpolatePoint(input->GetPointData(), outPtId, + cell->GetPointIds(), weights); + this->RecordOrigPointId(outPtId, -1); + this->EdgeMap->AddEdge(edgePtA, edgePtB, outPtId); + } + + return outPtId; +} + //---------------------------------------------------------------------------- void vtkDataSetSurfaceFilter::RecordOrigCellId(vtkIdType destIndex, vtkIdType originalId) Index: VTK/Graphics/vtkDataSetSurfaceFilter.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Graphics/vtkDataSetSurfaceFilter.h,v retrieving revision 1.26 diff -u -r1.26 vtkDataSetSurfaceFilter.h --- VTK/Graphics/vtkDataSetSurfaceFilter.h 25 Mar 2009 14:35:54 -0000 1.26 +++ VTK/Graphics/vtkDataSetSurfaceFilter.h 12 Jun 2009 20:06:32 -0000 @@ -80,6 +80,35 @@ vtkGetMacro(PassThroughPointIds,int); vtkBooleanMacro(PassThroughPointIds,int); + // Description: + // If PassThroughCellIds or PassThroughPointIds is on, then these ivars + // control the name given to the field in which the ids are written into. If + // set to NULL, then vtkOriginalCellIds or vtkOriginalPointIds (the default) + // is used, respectively. + vtkSetStringMacro(OriginalCellIdsName); + virtual const char *GetOriginalCellIdsName() { + return ( this->OriginalCellIdsName + ? this->OriginalCellIdsName : "vtkOriginalCellIds"); + } + vtkSetStringMacro(OriginalPointIdsName); + virtual const char *GetOriginalPointIdsName() { + return ( this->OriginalPointIdsName + ? this->OriginalPointIdsName : "vtkOriginalPointIds"); + } + + // Description: + // If the input is an unstructured grid with nonlinear faces, this parameter + // determines how many times the face is subdivided into linear faces. If 0, + // the output is the equivalent of its linear couterpart (and the midpoints + // determining the nonlinear interpolation are discarded). If 1 (the + // default), the nonlinear face is triangulated based on the midpoints. If + // greater than 1, the triangulated pieces are recursively subdivided to reach + // the desired subdivision. Setting the value to greater than 1 may cause + // some point data to not be passed even if no nonlinear faces exist. This + // option has no effect if the input is not an unstructured grid. + vtkSetMacro(NonlinearSubdivisionLevel, int); + vtkGetMacro(NonlinearSubdivisionLevel, int); + protected: vtkDataSetSurfaceFilter(); ~vtkDataSetSurfaceFilter(); @@ -124,6 +153,14 @@ vtkIdType *PointMap; vtkIdType GetOutputPointId(vtkIdType inPtId, vtkDataSet *input, vtkPoints *outPts, vtkPointData *outPD); +//BTX + class vtkEdgeInterpolationMap; +//ETX + vtkEdgeInterpolationMap *EdgeMap; + vtkIdType GetInterpolatedPointId(vtkIdType edgePtA, vtkIdType edgePtB, + vtkDataSet *input, vtkCell *cell, + double pcoords[3], vtkPoints *outPts, + vtkPointData *outPD); vtkIdType NumberOfNewCells; @@ -144,10 +181,14 @@ int PassThroughCellIds; void RecordOrigCellId(vtkIdType newIndex, vtkIdType origId); vtkIdTypeArray *OriginalCellIds; + char *OriginalCellIdsName; int PassThroughPointIds; void RecordOrigPointId(vtkIdType newIndex, vtkIdType origId); vtkIdTypeArray *OriginalPointIds; + char *OriginalPointIdsName; + + int NonlinearSubdivisionLevel; private: vtkDataSetSurfaceFilter(const vtkDataSetSurfaceFilter&); // Not implemented. Index: VTK/Rendering/vtkLinesPainter.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Rendering/vtkLinesPainter.cxx,v retrieving revision 1.6 diff -u -r1.6 vtkLinesPainter.cxx --- VTK/Rendering/vtkLinesPainter.cxx 18 Jul 2008 19:12:16 -0000 1.6 +++ VTK/Rendering/vtkLinesPainter.cxx 12 Jun 2009 20:06:33 -0000 @@ -131,6 +131,9 @@ // we just ignore the flag. idx &= (~VTK_PDM_FIELD_COLORS); + // Also ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + // draw all the elements, use fast path if available switch (idx) { Index: VTK/Rendering/vtkOpenGLPainterDeviceAdapter.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Rendering/vtkOpenGLPainterDeviceAdapter.cxx,v retrieving revision 1.27 diff -u -r1.27 vtkOpenGLPainterDeviceAdapter.cxx --- VTK/Rendering/vtkOpenGLPainterDeviceAdapter.cxx 15 Jan 2009 15:54:21 -0000 1.27 +++ VTK/Rendering/vtkOpenGLPainterDeviceAdapter.cxx 12 Jun 2009 20:06:33 -0000 @@ -259,6 +259,7 @@ case vtkDataSetAttributes::NORMALS: case vtkDataSetAttributes::SCALARS: case vtkDataSetAttributes::TCOORDS: + case vtkDataSetAttributes::EDGEFLAG: return 1; } return 0; @@ -534,6 +535,18 @@ return; } break; + case vtkDataSetAttributes::EDGEFLAG: // Edge Flag + if (numcomp != 1) + { + vtkErrorMacro("Bad number of components."); + return; + } + switch (type) + { + vtkTemplateMacro(glEdgeFlag(static_cast<GLboolean>( + reinterpret_cast<const VTK_TT*>(attribute)[offset]))); + } + break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -715,6 +728,33 @@ } glTexCoordPointer(numcomponents, gltype, stride, pointer); break; + case vtkDataSetAttributes::EDGEFLAG: // Edge flag + if (numcomponents != 1) + { + vtkErrorMacro("Edge flag must have one component."); + return; + } + // Flag must be conformant to GLboolean + if ((type == VTK_FLOAT) || (type == GL_DOUBLE)) + { + vtkErrorMacro("Unsupported type for edge flag: " << type); + return; + } + // Thus is an unfriendly way to force the array to be conformant to + // a GLboolean array. At the very least there should be some indication + // in VTK outside of OpenGL to determine which VTK type to use. + switch (type) + { + vtkTemplateMacro(if (sizeof(VTK_TT) != sizeof(GLboolean)) + { + vtkErrorMacro(<< "Unsupported tyep for edge flag: " + << type); + return; + } + ); + } + glEdgeFlagPointer(stride, pointer); + break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -735,6 +775,8 @@ glEnableClientState(GL_COLOR_ARRAY); break; case vtkDataSetAttributes::TCOORDS: glEnableClientState(GL_TEXTURE_COORD_ARRAY); break; + case vtkDataSetAttributes::EDGEFLAG: + glEnableClientState(GL_EDGE_FLAG_ARRAY); break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -753,6 +795,8 @@ glDisableClientState(GL_COLOR_ARRAY); break; case vtkDataSetAttributes::TCOORDS: glDisableClientState(GL_TEXTURE_COORD_ARRAY); break; + case vtkDataSetAttributes::EDGEFLAG: + glDisableClientState(GL_EDGE_FLAG_ARRAY); break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; Index: VTK/Rendering/vtkPointsPainter.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Rendering/vtkPointsPainter.cxx,v retrieving revision 1.4 diff -u -r1.4 vtkPointsPainter.cxx --- VTK/Rendering/vtkPointsPainter.cxx 23 Feb 2008 17:18:46 -0000 1.4 +++ VTK/Rendering/vtkPointsPainter.cxx 12 Jun 2009 20:06:33 -0000 @@ -107,6 +107,10 @@ // since this painter does not deal with field colors specially, // we just ignore the flag. idx &= (~VTK_PDM_FIELD_COLORS); + + // Also ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + switch (idx) { case 0://no cell/point attribs are present. Index: VTK/Rendering/vtkPolygonsPainter.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Rendering/vtkPolygonsPainter.cxx,v retrieving revision 1.4 diff -u -r1.4 vtkPolygonsPainter.cxx --- VTK/Rendering/vtkPolygonsPainter.cxx 23 Feb 2008 17:18:46 -0000 1.4 +++ VTK/Rendering/vtkPolygonsPainter.cxx 12 Jun 2009 20:06:33 -0000 @@ -181,6 +181,8 @@ pd->GetLines()->GetNumberOfCells(); vtkIdType cellNumStart = cellNum; vtkIdType totalCells = ca->GetNumberOfCells(); + vtkUnsignedCharArray *ef = vtkUnsignedCharArray::SafeDownCast( + pd->GetPointData()->GetAttribute(vtkDataSetAttributes::EDGEFLAG)); vtkPainterDeviceAdapter* device = ren->GetRenderWindow()-> GetPainterDeviceAdapter(); @@ -188,6 +190,7 @@ void *normals = 0; void *tcoords = 0; unsigned char *colors = 0; + unsigned char *edgeflags = 0; int primitive = VTK_POLYGON; if (ca->GetNumberOfCells() == 0) @@ -211,12 +214,17 @@ { tcoords = t->GetVoidPointer(0); } + if (ef) + { + edgeflags = ef->GetPointer(0); + } vtkIdType *ptIds = ca->GetPointer(); vtkIdType *endPtIds = ptIds + ca->GetNumberOfConnectivityEntries(); int ptype = p->GetDataType(); int ntype = (n)? n->GetDataType() : 0; int ttype = (t)? t->GetDataType() : 0; int tcomps = (t)? t->GetNumberOfComponents() : 0; + int eftype = (ef)? ef->GetDataType() : 0; int celloffset = 0; // since this painter does not deal with field colors specially, @@ -412,9 +420,266 @@ VTK_UNSIGNED_CHAR, colors); colors += 4;, celloffset = cellNum;); break; + + case VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, ;,;); + } + break; + + case VTK_PDM_NORMALS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + + case VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, 1, + ttype, tcoords, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, colors); + colors += 4;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, colors); + colors += 4;,;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++; + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, colors); + colors += 4;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++; + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, colors); + colors += 4;, + celloffset = cellNum;); + break; + default: return 0; // let the delegate painter handle it. } + + if (idx & VTK_PDM_EDGEFLAGS) + { + // Reset the edge flag to 1 so that if the next thing rendered does not + // have an edge flag, it will have all edges on. + unsigned char edgeflag = 1; + device->SendAttribute(vtkPointData::EDGEFLAG, 1, VTK_UNSIGNED_CHAR, + &edgeflag, 0); + } + return 1; } Index: VTK/Rendering/vtkPrimitivePainter.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Rendering/vtkPrimitivePainter.cxx,v retrieving revision 1.11 diff -u -r1.11 vtkPrimitivePainter.cxx --- VTK/Rendering/vtkPrimitivePainter.cxx 8 Dec 2008 19:28:35 -0000 1.11 +++ VTK/Rendering/vtkPrimitivePainter.cxx 12 Jun 2009 20:06:33 -0000 @@ -159,6 +159,7 @@ vtkUnsignedCharArray *c=NULL; vtkDataArray *n; vtkDataArray *t; + vtkDataArray *ef; int tDim; vtkPolyData *input = this->GetInputAsPolyData(); int cellNormals; @@ -269,6 +270,28 @@ idx |= VTK_PDM_TCOORDS; } + // Edge flag + ef = input->GetPointData()->GetAttribute(vtkDataSetAttributes::EDGEFLAG); + if (ef) + { + if (ef->GetNumberOfComponents() != 1) + { + vtkDebugMacro(<< "Currently only 1d edge flags are supported."); + ef = NULL; + } + if (!ef->IsA("vtkUnsignedCharArray")) + { + vtkDebugMacro(<< "Currently only unsigned char edge flags are suported."); + ef = NULL; + } + } + + // Set the flags + if (ef) + { + idx |= VTK_PDM_EDGEFLAGS; + } + if (!act) { vtkErrorMacro("No actor"); Index: VTK/Rendering/vtkPrimitivePainter.h =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Rendering/vtkPrimitivePainter.h,v retrieving revision 1.9 diff -u -r1.9 vtkPrimitivePainter.h --- VTK/Rendering/vtkPrimitivePainter.h 28 Jul 2008 17:08:42 -0000 1.9 +++ VTK/Rendering/vtkPrimitivePainter.h 12 Jun 2009 20:06:33 -0000 @@ -49,14 +49,15 @@ //BTX enum { - VTK_PDM_NORMALS = 0x01, - VTK_PDM_COLORS = 0x02, - VTK_PDM_TCOORDS = 0x04, - VTK_PDM_CELL_COLORS = 0x08, - VTK_PDM_CELL_NORMALS = 0x10, - VTK_PDM_OPAQUE_COLORS = 0x20, - VTK_PDM_FIELD_COLORS = 0x40, - VTK_PDM_GENERIC_VERTEX_ATTRIBUTES =0x80 + VTK_PDM_NORMALS = 0x001, + VTK_PDM_COLORS = 0x002, + VTK_PDM_TCOORDS = 0x004, + VTK_PDM_CELL_COLORS = 0x008, + VTK_PDM_CELL_NORMALS = 0x010, + VTK_PDM_OPAQUE_COLORS = 0x020, + VTK_PDM_FIELD_COLORS = 0x040, + VTK_PDM_EDGEFLAGS = 0x080, + VTK_PDM_GENERIC_VERTEX_ATTRIBUTES = 0x100 }; //ETX Index: VTK/Rendering/vtkTStripsPainter.cxx =================================================================== RCS file: /cvsroot/ParaView3/ParaView3/VTK/Rendering/vtkTStripsPainter.cxx,v retrieving revision 1.5 diff -u -r1.5 vtkTStripsPainter.cxx --- VTK/Rendering/vtkTStripsPainter.cxx 23 Feb 2008 17:18:46 -0000 1.5 +++ VTK/Rendering/vtkTStripsPainter.cxx 12 Jun 2009 20:06:33 -0000 @@ -189,6 +189,9 @@ int ttype = (t)? t->GetDataType() : 0; int tcomps = (t)? t->GetNumberOfComponents() : 0; + // Ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + // draw all the elements, use fast path if available switch (idx) { ![]() diff --git a/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui b/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui index 7ef509d..e50801b 100644 --- a/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui +++ b/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui @@ -669,14 +669,44 @@ </property> </spacer> </item> - <item row="7" column="0" > + <item row="7" column="0"> + <widget class="QLabel" name="label_17"> + <property name="text"> + <string>Subdivision</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QSpinBox" name="NonlinearSubdivisionLevel"> + <property name="toolTip"> + <string>Nonlinear faces are approximated with flat polygons. This parameter controls how many times to subdivide nonlinear surface cells. Higher subdivisions generate closer approximations but take more memory and rendering time. Subdivision is recursive, so the number of output polygons can grow exponentially with this parameter.</string> + </property> + <property name="maximum"> + <number>4</number> + </property> + </widget> + </item> + <item row="7" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="8" column="0" > <widget class="QLabel" name="label_19" > <property name="text" > <string>Volume mapper</string> </property> </widget> </item> - <item row="7" column="1" colspan="2" > + <item row="8" column="1" colspan="2" > <widget class="QComboBox" name="SelectedMapperIndex" > <property name="toolTip" > <string><html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:Sans Serif; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Choose the mapper to use for volume rendering.</p></body></html></string> @@ -1217,6 +1247,7 @@ <tabstop>StylePointSize</tabstop> <tabstop>StyleLineWidth</tabstop> <tabstop>Opacity</tabstop> + <tabstop>NonlinearSubdivisionLevel</tabstop> <tabstop>SelectedMapperIndex</tabstop> <tabstop>EdgeColor</tabstop> <tabstop>SpecularIntensity</tabstop> diff --git a/Qt/Components/pqDisplayProxyEditor.cxx b/Qt/Components/pqDisplayProxyEditor.cxx index 794e904..580efab 100644 --- a/Qt/Components/pqDisplayProxyEditor.cxx +++ b/Qt/Components/pqDisplayProxyEditor.cxx @@ -385,6 +385,15 @@ void pqDisplayProxyEditor::setRepresentation(pqPipelineRepresentation* repr) "value", SIGNAL(editingFinished()), reprProxy, reprProxy->GetProperty("Opacity")); + // setup of nonlinear subdivision + if (reprProxy->GetProperty("NonlinearSubdivisionLevel")) + { + this->Internal->Links->addPropertyLink( + this->Internal->NonlinearSubdivisionLevel, + "value", SIGNAL(valueChanged(int)), + reprProxy, reprProxy->GetProperty("NonlinearSubdivisionLevel")); + } + // setup for map scalars this->Internal->Links->addPropertyLink( this->Internal->ColorMapScalars, "checked", SIGNAL(stateChanged(int)), diff --git a/Servers/Filters/CMakeLists.txt b/Servers/Filters/CMakeLists.txt index 30e6d53..75e473c 100644 --- a/Servers/Filters/CMakeLists.txt +++ b/Servers/Filters/CMakeLists.txt @@ -108,6 +108,7 @@ SET(Filters_SRCS vtkPVMain.cxx vtkPVMergeTables.cxx vtkPVNullSource.cxx + vtkPVRecoverGeometryWireframe.cxx vtkPVRenderViewProxy.cxx vtkPVScalarBarActor.cxx vtkPVSelectionSource.cxx diff --git a/Servers/Filters/vtkPVGeometryFilter.cxx b/Servers/Filters/vtkPVGeometryFilter.cxx index 5bb831e..ae881c6 100644 --- a/Servers/Filters/vtkPVGeometryFilter.cxx +++ b/Servers/Filters/vtkPVGeometryFilter.cxx @@ -14,10 +14,12 @@ =========================================================================*/ #include "vtkPVGeometryFilter.h" +#include "vtkAlgorithmOutput.h" #include "vtkAppendPolyData.h" #include "vtkCallbackCommand.h" #include "vtkCellArray.h" #include "vtkCellData.h" +#include "vtkCellTypes.h" #include "vtkCleanArrays.h" #include "vtkCommand.h" #include "vtkCompositeDataIterator.h" @@ -42,6 +44,7 @@ #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkPolygon.h" +#include "vtkPVRecoverGeometryWireframe.h" #include "vtkPVTrivialProducer.h" #include "vtkRectilinearGrid.h" #include "vtkRectilinearGridOutlineFilter.h" @@ -52,13 +55,16 @@ #include "vtkStructuredGridOutlineFilter.h" #include "vtkUnsignedCharArray.h" #include "vtkUnsignedIntArray.h" -#include "vtkAlgorithmOutput.h" #include "vtkUnstructuredGrid.h" +#include "vtkUnstructuredGridGeometryFilter.h" #include <vtkstd/map> #include <vtkstd/string> #include <assert.h> +#define VTK_CREATE(type, name) \ + vtkSmartPointer<type> name = vtkSmartPointer<type>::New() + vtkCxxRevisionMacro(vtkPVGeometryFilter, "$Revision$"); vtkStandardNewMacro(vtkPVGeometryFilter); @@ -125,10 +131,13 @@ vtkPVGeometryFilter::vtkPVGeometryFilter () this->UseOutline = 1; this->UseStrips = 0; this->GenerateCellNormals = 1; + this->NonlinearSubdivisionLevel = 1; this->DataSetSurfaceFilter = vtkDataSetSurfaceFilter::New(); this->GenericGeometryFilter=vtkGenericGeometryFilter::New(); - + this->UnstructuredGridGeometryFilter=vtkUnstructuredGridGeometryFilter::New(); + this->RecoverWireframeFilter = vtkPVRecoverGeometryWireframe::New(); + // Setup a callback for the internal readers to report progress. this->InternalProgressObserver = vtkCallbackCommand::New(); this->InternalProgressObserver->SetCallback( @@ -155,13 +164,31 @@ vtkPVGeometryFilter::vtkPVGeometryFilter () //---------------------------------------------------------------------------- vtkPVGeometryFilter::~vtkPVGeometryFilter () { - if(this->DataSetSurfaceFilter) + // Be careful how you delete these so that you don't foul up the garbage + // collector. + if (this->DataSetSurfaceFilter) { - this->DataSetSurfaceFilter->Delete(); + vtkDataSetSurfaceFilter *tmp = this->DataSetSurfaceFilter; + this->DataSetSurfaceFilter = NULL; + tmp->Delete(); } - if(this->GenericGeometryFilter!=0) + if (this->GenericGeometryFilter) { - this->GenericGeometryFilter->Delete(); + vtkGenericGeometryFilter *tmp = this->GenericGeometryFilter; + this->GenericGeometryFilter = NULL; + tmp->Delete(); + } + if (this->UnstructuredGridGeometryFilter) + { + vtkUnstructuredGridGeometryFilter *tmp=this->UnstructuredGridGeometryFilter; + this->UnstructuredGridGeometryFilter = NULL; + tmp->Delete(); + } + if (this->RecoverWireframeFilter) + { + vtkPVRecoverGeometryWireframe *tmp = this->RecoverWireframeFilter; + this->RecoverWireframeFilter = NULL; + tmp->Delete(); } this->OutlineSource->Delete(); this->InternalProgressObserver->Delete(); @@ -1028,7 +1055,157 @@ void vtkPVGeometryFilter::UnstructuredGridExecute( if (!this->UseOutline) { this->OutlineFlag = 0; + + bool handleSubdivision = false; + if (this->NonlinearSubdivisionLevel > 0) + { + // Check to see if the data actually has nonlinear cells. Handling + // nonlinear cells adds unnecessary work if we only have linear cells. + vtkUnsignedCharArray *types = input->GetCellTypesArray(); + vtkIdType numCells = input->GetNumberOfCells(); + for (vtkIdType i = 0; i < numCells; i++) + { + if (!vtkCellTypes::IsLinear(types->GetValue(i))) + { + handleSubdivision = true; + break; + } + } + } + + vtkSmartPointer<vtkIdTypeArray> facePtIds2OriginalPtIds; + + if (handleSubdivision) + { + // Use the vtkUnstructuredGridGeometryFilter to extract 2D surface cells + // from the geometry. This is important to extract an appropriate + // wireframe in vtkPVRecoverGeometryWireframe. Also, at the time of this + // writing vtkDataSetSurfaceFilter only properly subdivides 2D cells past + // level 1. + VTK_CREATE(vtkUnstructuredGrid, inputClone); + inputClone->ShallowCopy(input); + this->UnstructuredGridGeometryFilter->SetInput(inputClone); + + // Let the vtkUnstructuredGridGeometryFilter record from which point and + // cell each face comes from in the standard vtkOriginalCellIds array. + this->UnstructuredGridGeometryFilter->SetPassThroughCellIds( + this->PassThroughCellIds); + this->UnstructuredGridGeometryFilter->SetPassThroughPointIds( + this->PassThroughPointIds); + + // Observe the progress of the internal filter. + // TODO: Make the consecutive internal filter execution have monotonically + // increasing progress rather than restarting for every internal filter. + this->UnstructuredGridGeometryFilter->AddObserver( + vtkCommand::ProgressEvent, + this->InternalProgressObserver); + this->UnstructuredGridGeometryFilter->Update(); + // The internal filter finished. Remove the observer. + this->UnstructuredGridGeometryFilter->RemoveObserver( + this->InternalProgressObserver); + + this->UnstructuredGridGeometryFilter->SetInput(NULL); + + // Feed the extracted surface as the input to the rest of the processing. + input->ShallowCopy(this->UnstructuredGridGeometryFilter->GetOutput()); + + // Keep a handle to the vtkOriginalPointIds array. We might need it. + facePtIds2OriginalPtIds = vtkIdTypeArray::SafeDownCast( + input->GetPointData()->GetArray("vtkOriginalPointIds")); + + // Flag the data set surface filter to record original cell ids, but do it + // in a specially named array that vtkPVRecoverGeometryWireframe will + // recognize. Note that because the data set comes from + // UnstructuredGridGeometryFilter, the ids will represent the faces rather + // than the original cells, which is important. + this->DataSetSurfaceFilter->PassThroughCellIdsOn(); + this->DataSetSurfaceFilter->SetOriginalCellIdsName( + vtkPVRecoverGeometryWireframe::ORIGINAL_FACE_IDS()); + + if (this->PassThroughPointIds) + { + if (this->NonlinearSubdivisionLevel <= 1) + { + // Do not allow the vtkDataSetSurfaceFilter create an array of + // original cell ids; it will overwrite the correct array from the + // vtkUnstructuredGridGeometryFilter. + this->DataSetSurfaceFilter->PassThroughPointIdsOff(); + } + else + { + // vtkDataSetSurfaceFilter is going to strip the vtkOriginalPointIds + // created by the vtkPVUnstructuredGridGeometryFilter because it + // cannot interpolate the ids. Make the vtkDataSetSurfaceFilter make + // its own original ids array. We will resolve them later. + this->DataSetSurfaceFilter->PassThroughPointIdsOn(); + } + } + } + this->DataSetSurfaceExecute(input, output); + + if (handleSubdivision) + { + // Restore state of DataSetSurfaceFilter. + this->DataSetSurfaceFilter->SetPassThroughCellIds( + this->PassThroughCellIds); + this->DataSetSurfaceFilter->SetOriginalCellIdsName(NULL); + this->DataSetSurfaceFilter->SetPassThroughPointIds( + this->PassThroughPointIds); + + // Now use vtkPVRecoverGeometryWireframe to create an edge flag attribute + // that will cause the wireframe to be rendered correctly. + VTK_CREATE(vtkPolyData, nextStageInput); + nextStageInput->ShallowCopy(output); // Yes output is correct. + this->RecoverWireframeFilter->SetInput(nextStageInput); + + // Observe the progress of the internal filter. + // TODO: Make the consecutive internal filter execution have monotonically + // increasing progress rather than restarting for every internal filter. + this->RecoverWireframeFilter->AddObserver( + vtkCommand::ProgressEvent, + this->InternalProgressObserver); + this->RecoverWireframeFilter->Update(); + // The internal filter finished. Remove the observer. + this->RecoverWireframeFilter->RemoveObserver( + this->InternalProgressObserver); + + this->RecoverWireframeFilter->SetInput(NULL); + + // Get what should be the final output. + output->ShallowCopy(this->RecoverWireframeFilter->GetOutput()); + + if (this->PassThroughPointIds && (this->NonlinearSubdivisionLevel > 1)) + { + // The output currently has a vtkOriginalPointIds array that maps points + // to the data containing only the faces. Correct this to point to the + // original data set. + vtkIdTypeArray *polyPtIds2FacePtIds = vtkIdTypeArray::SafeDownCast( + output->GetPointData()->GetArray("vtkOriginalPointIds")); + if (!facePtIds2OriginalPtIds || !polyPtIds2FacePtIds) + { + vtkErrorMacro(<< "Missing original point id arrays."); + return; + } + vtkIdType numPts = polyPtIds2FacePtIds->GetNumberOfTuples(); + VTK_CREATE(vtkIdTypeArray, polyPtIds2OriginalPtIds); + polyPtIds2OriginalPtIds->SetName("vtkOriginalPointIds"); + polyPtIds2OriginalPtIds->SetNumberOfComponents(1); + polyPtIds2OriginalPtIds->SetNumberOfTuples(numPts); + for (vtkIdType polyPtId = 0; polyPtId < numPts; polyPtId++) + { + vtkIdType facePtId = polyPtIds2FacePtIds->GetValue(polyPtId); + vtkIdType originalPtId = -1; + if (facePtId >= 0) + { + originalPtId = facePtIds2OriginalPtIds->GetValue(facePtId); + } + polyPtIds2OriginalPtIds->SetValue(polyPtId, originalPtId); + } + output->GetPointData()->AddArray(polyPtIds2OriginalPtIds); + } + } + return; } @@ -1151,6 +1328,10 @@ void vtkPVGeometryFilter::ReportReferences(vtkGarbageCollector* collector) "DataSetSurfaceFilter"); vtkGarbageCollectorReport(collector, this->GenericGeometryFilter, "GenericGeometryFilter"); + vtkGarbageCollectorReport(collector, this->UnstructuredGridGeometryFilter, + "UnstructuredGridGeometryFilter"); + vtkGarbageCollectorReport(collector, this->RecoverWireframeFilter, + "RecoverWireframeFilter"); } //---------------------------------------------------------------------------- @@ -1171,6 +1352,8 @@ void vtkPVGeometryFilter::PrintSelf(ostream& os, vtkIndent indent) os << indent << "UseStrips: " << (this->UseStrips?"on":"off") << endl; os << indent << "GenerateCellNormals: " << (this->GenerateCellNormals?"on":"off") << endl; + os << indent << "NonlinearSubdivisionLevel: " + << this->NonlinearSubdivisionLevel << endl; os << indent << "Controller: " << this->Controller << endl; os << indent << "PassThroughCellIds: " @@ -1264,3 +1447,20 @@ void vtkPVGeometryFilter::RemoveGhostCells(vtkPolyData* output) output->RemoveGhostCells(1); } } + +//----------------------------------------------------------------------------- +void vtkPVGeometryFilter::SetNonlinearSubdivisionLevel(int newvalue) +{ + if (this->NonlinearSubdivisionLevel != newvalue) + { + this->NonlinearSubdivisionLevel = newvalue; + + if (this->DataSetSurfaceFilter) + { + this->DataSetSurfaceFilter->SetNonlinearSubdivisionLevel( + this->NonlinearSubdivisionLevel); + } + + this->Modified(); + } +} diff --git a/Servers/Filters/vtkPVGeometryFilter.h b/Servers/Filters/vtkPVGeometryFilter.h index b846d73..7ed9118 100644 --- a/Servers/Filters/vtkPVGeometryFilter.h +++ b/Servers/Filters/vtkPVGeometryFilter.h @@ -35,9 +35,11 @@ class vtkInformationVector; class vtkCompositeDataSet; class vtkMultiProcessController; class vtkOutlineSource; +class vtkPVRecoverGeometryWireframe; class vtkRectilinearGrid; class vtkStructuredGrid; class vtkUnstructuredGrid; +class vtkUnstructuredGridGeometryFilter; class VTK_EXPORT vtkPVGeometryFilter : public vtkPolyDataAlgorithm { @@ -80,6 +82,15 @@ public: vtkBooleanMacro(GenerateCellNormals, int); // Description: + // Nonlinear faces are approximated with flat polygons. This parameter + // controls how many times to subdivide nonlinear surface cells. Higher + // subdivisions generate closer approximations but take more memory and + // rendering time. Subdivision is recursive, so the number of output polygons + // can grow exponentially with this parameter. + virtual void SetNonlinearSubdivisionLevel(int); + vtkGetMacro(NonlinearSubdivisionLevel, int); + + // Description: // Set and get the controller. virtual void SetController(vtkMultiProcessController*); vtkGetObjectMacro(Controller, vtkMultiProcessController); @@ -159,11 +170,14 @@ protected: int UseOutline; int UseStrips; int GenerateCellNormals; + int NonlinearSubdivisionLevel; vtkMultiProcessController* Controller; vtkOutlineSource *OutlineSource; vtkDataSetSurfaceFilter* DataSetSurfaceFilter; vtkGenericGeometryFilter *GenericGeometryFilter; + vtkUnstructuredGridGeometryFilter *UnstructuredGridGeometryFilter; + vtkPVRecoverGeometryWireframe *RecoverWireframeFilter; int CheckAttributes(vtkDataObject* input); diff --git a/Servers/Filters/vtkPVRecoverGeometryWireframe.cxx b/Servers/Filters/vtkPVRecoverGeometryWireframe.cxx new file mode 100644 index 0000000..acc35f3 --- /dev/null +++ b/Servers/Filters/vtkPVRecoverGeometryWireframe.cxx @@ -0,0 +1,308 @@ +// -*- c++ -*- +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: pqBlotDialog.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*------------------------------------------------------------------------- + Copyright 2009 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, + the U.S. Government retains certain rights in this software. +-------------------------------------------------------------------------*/ + +#include "vtkPVRecoverGeometryWireframe.h" + +#include "vtkCellArray.h" +#include "vtkCellData.h" +#include "vtkIdTypeArray.h" +#include "vtkObjectFactory.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" +#include "vtkUnsignedCharArray.h" + +#include "vtkSmartPointer.h" +#define VTK_CREATE(type, name) \ + vtkSmartPointer<type> name = vtkSmartPointer<type>::New() + +#include <vtkstd/algorithm> +#include <vtkstd/vector> +#include <vtksys/hash_map.hxx> + +static const unsigned char NO_EDGE_FLAG = static_cast<unsigned char >(-1); + +//============================================================================= +namespace vtkPVRecoverGeometryWireframeNamespace +{ + // Description: + // Simple class used internally to define an edge based on the endpoints. The + // endpoints are canonically identified by the lower and higher values. + class EdgeEndpoints + { + public: + EdgeEndpoints() : MinEndPoint(-1), MaxEndPoint(-1) {} + EdgeEndpoints(vtkIdType endpointA, vtkIdType endpointB) + : MinEndPoint((endpointA < endpointB) ? endpointA : endpointB), + MaxEndPoint((endpointA < endpointB) ? endpointB : endpointA) + {} + const vtkIdType MinEndPoint; + const vtkIdType MaxEndPoint; + inline bool operator==(const EdgeEndpoints &other) const { + return ( (this->MinEndPoint == other.MinEndPoint) + && (this->MaxEndPoint == other.MaxEndPoint) ); + } + }; + struct EdgeEndpointsHash { + public: + size_t operator()(const EdgeEndpoints &edge) const { + return static_cast<size_t>(edge.MinEndPoint + edge.MaxEndPoint); + } + }; + + // Description: + // Holds the information necessary for the facet this edge came from. + class EdgeInformation + { + public: + vtkIdType OriginalFaceId; + vtkIdType *StartPointIdP; + }; + + // Description: + // A map from edge endpoints to the information about that edge. + typedef vtksys::hash_map<EdgeEndpoints, EdgeInformation, EdgeEndpointsHash> + EdgeMapType; + + void RecordEdgeFlag(vtkPolyData *output, const EdgeInformation &edgeInfo, + vtkUnsignedCharArray *edgeFlagArray, unsigned char flag, + vtkIdType *duplicatePointMap) + { + vtkIdType pt = edgeInfo.StartPointIdP[0]; + if (edgeFlagArray->GetValue(pt) == flag) + { + // Edge flag already set correctly. Nothing to do. + return; + } + if (edgeFlagArray->GetValue(pt) == NO_EDGE_FLAG) + { + // Nothing has set the edge flag yet. Just set it and return. + edgeFlagArray->SetValue(pt, flag); + return; + } + + // If we are here then some other cell has already put a flag on this + // point different than ours. We have to adjust our cell topology to + // use a duplicate point. + if (duplicatePointMap[pt] == -1) + { + // No duplicate made. We need to make one. + vtkPoints *points = output->GetPoints(); + double coords[3]; + points->GetPoint(pt, coords); + vtkIdType newPt = points->InsertNextPoint(coords); + duplicatePointMap[pt] = newPt; + // Copying attributes from yourself seems weird, but is valid. + vtkPointData *pd = output->GetPointData(); + pd->CopyData(pd, pt, newPt); + edgeFlagArray->InsertValue(newPt, flag); + } + edgeInfo.StartPointIdP[0] = duplicatePointMap[pt]; + } +} +using namespace vtkPVRecoverGeometryWireframeNamespace; + +//============================================================================= +vtkCxxRevisionMacro(vtkPVRecoverGeometryWireframe, "$Revision$"); +vtkStandardNewMacro(vtkPVRecoverGeometryWireframe); + +//----------------------------------------------------------------------------- +vtkPVRecoverGeometryWireframe::vtkPVRecoverGeometryWireframe() +{ +} + +vtkPVRecoverGeometryWireframe::~vtkPVRecoverGeometryWireframe() +{ +} + +void vtkPVRecoverGeometryWireframe::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +//----------------------------------------------------------------------------- +int vtkPVRecoverGeometryWireframe::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + vtkPolyData *input = vtkPolyData::GetData(inputVector[0]); + vtkPolyData *output = vtkPolyData::GetData(outputVector); + + vtkIdType npts, *pts; + vtkstd::vector<vtkIdType> originalPts; + + if (!input->GetCellData()->HasArray(ORIGINAL_FACE_IDS())) + { + // Did not find the field used to identify the face each linear patch comes + // from. The original data was probably linear so using all the edges + // should be OK (and is at least the best we can do), so just pass the data. + output->ShallowCopy(input); + return 1; + } + + vtkIdTypeArray *faceIds = vtkIdTypeArray::SafeDownCast( + input->GetCellData()->GetAbstractArray(ORIGINAL_FACE_IDS())); + if (!faceIds) + { + vtkErrorMacro(<< ORIGINAL_FACE_IDS() << " array is not of expected type."); + return 0; + } + + // Shallow copy the cell data. All the cells get copied to output. + output->GetCellData()->PassData(input->GetCellData()); + + // Deep copy the point information and be ready to add points. + VTK_CREATE(vtkPoints, points); + points->DeepCopy(input->GetPoints()); + output->SetPoints(points); + vtkPointData *inputPD = input->GetPointData(); + vtkPointData *outputPD = output->GetPointData(); + outputPD->CopyAllocate(inputPD); + vtkIdType numOriginalPoints = points->GetNumberOfPoints(); + for (vtkIdType i = 0; i < numOriginalPoints; i++) + { + outputPD->CopyData(inputPD, i, i); + } + + // Create an edge flag array. + VTK_CREATE(vtkUnsignedCharArray, edgeflags); + edgeflags->SetName("vtkEdgeFlags"); + outputPD->AddArray(edgeflags); + outputPD->SetActiveAttribute("vtkEdgeFlags", vtkDataSetAttributes::EDGEFLAG); + edgeflags->SetNumberOfComponents(1); + edgeflags->SetNumberOfTuples(numOriginalPoints); + vtkstd::fill(edgeflags->GetPointer(0), + edgeflags->GetPointer(numOriginalPoints), NO_EDGE_FLAG); + + // Some (probably many) points will have to be duplicated because different + // cells will need different edge flags. This array maps the original + // point id to the duplicate id. + vtkstd::vector<vtkIdType> duplicatePointMap(numOriginalPoints); + vtkstd::fill(duplicatePointMap.begin(), duplicatePointMap.end(), -1); + + // Shallow copy the verts. Set the edge flags to true. + vtkCellArray *inputVerts = input->GetVerts(); + output->SetVerts(inputVerts); + for (inputVerts->InitTraversal(); inputVerts->GetNextCell(npts, pts); ) + { + for (vtkIdType i = 0; i < npts; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Shallow copy the lines. Set the edge flags to true. + vtkCellArray *inputLines = input->GetLines(); + output->SetLines(inputLines); + for (inputLines->InitTraversal(); inputLines->GetNextCell(npts, pts); ) + { + // No need to set edge flag for last index. + for (vtkIdType i = 0; i < npts-1; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Shallow copy the triangle strips. Set the edge flags to true. + vtkCellArray *inputStrips = input->GetStrips(); + output->SetStrips(inputStrips); + for (inputStrips->InitTraversal(); inputStrips->GetNextCell(npts, pts); ) + { + for (vtkIdType i = 0; i < npts; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Deep copy the polygons because we will be changing some indices when we + // duplicate points. + VTK_CREATE(vtkCellArray, outputPolys); + outputPolys->DeepCopy(input->GetPolys()); + output->SetPolys(outputPolys); + + // Iterate over all the input facets and see which edge interfaces belonged to + // different faces. We do that by recording the original face id in a map. + // When we find a pair of edges, we turn on the appropriate edge flag if they + // came from different faces, or turn it off if they came from the same face. + EdgeMapType edgeMap; + vtkIdType inputCellId + = inputVerts->GetNumberOfCells() + inputLines->GetNumberOfCells(); + for (outputPolys->InitTraversal(); outputPolys->GetNextCell(npts, pts); + inputCellId++) + { + if ((inputCellId%1000) == 0) + { + this->UpdateProgress(static_cast<double>(inputCellId) + /input->GetNumberOfCells()); + if (this->GetAbortExecute()) return 0; + } + // Record the original points of the polygon. As we iterate over edges, + // we may change the indices, but we allways compare edges by the original + // indices. + originalPts.resize(npts); + vtkstd::copy(pts, pts+npts, originalPts.begin()); + vtkIdType originalFace = faceIds->GetValue(inputCellId); + for (vtkIdType i = 0; i < npts; i++) + { + EdgeEndpoints edge(originalPts[i], originalPts[(i+1)%npts]); + EdgeInformation edgeInfo; + edgeInfo.OriginalFaceId = originalFace; + edgeInfo.StartPointIdP = &pts[i]; + + EdgeMapType::iterator edgeMatch = edgeMap.find(edge); + if (edgeMatch == edgeMap.end()) + { + // Not encountered yet. Add to the map. + edgeMap.insert(vtkstd::make_pair(edge, edgeInfo)); + } + else + { + // The edge flag is true if the edge connects two different faces. + unsigned char eflag = static_cast<unsigned char>( + edgeMatch->second.OriginalFaceId != originalFace); + RecordEdgeFlag(output, edgeMatch->second, edgeflags, eflag, + &duplicatePointMap.at(0)); + RecordEdgeFlag(output, edgeInfo, edgeflags, eflag, + &duplicatePointMap.at(0)); + // Remove the edge from the map since we already found the pair. + edgeMap.erase(edgeMatch); + } + } // For each edge + } // For each cell. + + // Everything left in the edge map has no match. It must necessarily be + // on the outside of a face. + for (EdgeMapType::iterator iter = edgeMap.begin(); + iter != edgeMap.end(); iter++) + { + RecordEdgeFlag(output, iter->second, edgeflags, 1, + &duplicatePointMap.at(0)); + } + + // If any points are unmarked, set some edge flag on them (although they + // are probably not referenced by any cell). + for (vtkIdType i = 0; i < numOriginalPoints; i++) + { + if (edgeflags->GetValue(i) == NO_EDGE_FLAG) edgeflags->SetValue(i, 1); + } + + return 1; +} diff --git a/Servers/Filters/vtkPVRecoverGeometryWireframe.h b/Servers/Filters/vtkPVRecoverGeometryWireframe.h new file mode 100644 index 0000000..6d1d569 --- /dev/null +++ b/Servers/Filters/vtkPVRecoverGeometryWireframe.h @@ -0,0 +1,73 @@ +// -*- c++ -*- +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: pqBlotDialog.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*------------------------------------------------------------------------- + Copyright 2009 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, + the U.S. Government retains certain rights in this software. +-------------------------------------------------------------------------*/ + +// .NAME vtkPVRecoverGeometryWireframe - Get corrected wireframe from tesselated facets +// +// .SECTION Description +// +// When vtkPVGeometryFilter tessellates nonlinear faces into linear +// approximations, it introduces edges in the middle of the facets of the +// original mesh (as any valid tessellation would). To correct for this, +// vtkPVGeometryFilter also writes out some fields that allows use to identify +// the edges that are actually part of the original mesh. This filter works in +// conjunction with vtkPVGeometryFilter by taking its output, adding an edge +// flag and making the appropriate adjustments so that rendering with line +// fill mode will make the correct wireframe. +// +// .SECTION See Also +// vtkPVGeometryFilter +// + +#ifndef __vtkPVRecoverGeometryWireframe_h +#define __vtkPVRecoverGeometryWireframe_h + +#include "vtkPolyDataAlgorithm.h" + +class VTK_EXPORT vtkPVRecoverGeometryWireframe : public vtkPolyDataAlgorithm +{ +public: + vtkTypeRevisionMacro(vtkPVRecoverGeometryWireframe, vtkPolyDataAlgorithm); + static vtkPVRecoverGeometryWireframe *New(); + virtual void PrintSelf(ostream &os, vtkIndent indent); + + // Description: + // In order to determine which edges existed in the original data, we need an + // identifier on each cell determining which face (not cell) it originally + // came from. The ids should be put in a cell data array with this name. The + // existance of this field is also a signal that this wireframe extraction is + // necessary. + static const char *ORIGINAL_FACE_IDS() + { return "vtkPVRecoverWireframeOriginalFaceIds"; } + +protected: + vtkPVRecoverGeometryWireframe(); + ~vtkPVRecoverGeometryWireframe(); + + virtual int RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + +private: + vtkPVRecoverGeometryWireframe(const vtkPVRecoverGeometryWireframe &); // Not implemented + void operator=(const vtkPVRecoverGeometryWireframe &); // Not implemented +}; + +#endif //__vtkPVRecoverGeometryWireframe_h diff --git a/Servers/ServerManager/Resources/filters.xml b/Servers/ServerManager/Resources/filters.xml index 273154a..315c2c7 100644 --- a/Servers/ServerManager/Resources/filters.xml +++ b/Servers/ServerManager/Resources/filters.xml @@ -1545,6 +1545,26 @@ The Extract Surface filter extracts the polygons forming the outer surface of th If the value of this property is set to 1, internal surfaces along process boundaries will be removed. NOTE: Enabling this option might cause multiple executions of the data source because more information is needed to remove internal surfaces. </Documentation> </IntVectorProperty> + + <IntVectorProperty name="NonlinearSubdivisionLevel" + command="SetNonlinearSubdivisionLevel" + number_of_elements="1" + default_values="1"> + <IntRangeDomain name="range" min="0" max="4" /> + <Documentation> + If the input is an unstructured grid with nonlinear faces, this + parameter determines how many times the face is subdivided into + linear faces. If 0, the output is the equivalent of its linear + couterpart (and the midpoints determining the nonlinear + interpolation are discarded). If 1, the nonlinear face is + triangulated based on the midpoints. If greater than 1, the + triangulated pieces are recursively subdivided to reach the + desired subdivision. Setting the value to greater than 1 may + cause some point data to not be passed even if no quadratic faces + exist. This option has no effect if the input is not an + unstructured grid. + </Documentation> + </IntVectorProperty> <!-- End DataSetSurfaceFilter --> </SourceProxy> @@ -7337,6 +7357,20 @@ Tessellate a higher-order dataset. Toggle whether to generate an outline or a surface. </Documentation> </IntVectorProperty> + <IntVectorProperty name="NonlinearSubdivisionLevel" + command="SetNonlinearSubdivisionLevel" + number_of_elements="1" + default_values="1"> + <IntRangeDomain name="range" min="0" max="4" /> + <Documentation> + Nonlinear faces are approximated with flat polygons. This + parameter controls how many times to subdivide nonlinear surface + cells. Higher subdivisions generate closer approximations but + take more memory and rendering time. Subdivision is recursive, + so the number of output polygons can grow exponentially with this + parameter. + </Documentation> + </IntVectorProperty> <IntVectorProperty name="PassThroughIds" command="SetPassThroughCellIds" diff --git a/Servers/ServerManager/Resources/rendering.xml b/Servers/ServerManager/Resources/rendering.xml index 9c0aa9a..393567e 100644 --- a/Servers/ServerManager/Resources/rendering.xml +++ b/Servers/ServerManager/Resources/rendering.xml @@ -6680,7 +6680,7 @@ <SubProxy> <!-- - Geometry filter is used to conver non-polydata input to polydata. + Geometry filter is used to convert non-polydata input to polydata. It is also used to convert poly data to triangle strips when requested. --> @@ -6689,6 +6689,7 @@ <ExposedProperties> <Property name="UseStrips" /> <Property name="ForceStrips" /> + <Property name="NonlinearSubdivisionLevel" /> </ExposedProperties> </SubProxy> @@ -7529,6 +7530,7 @@ <!-- Geometry Filter properties --> <Property name="UseStrips" /> <Property name="ForceStrips" /> + <Property name="NonlinearSubdivisionLevel" /> <!-- Mapper properties --> <Property name="LookupTable" /> diff --git a/VTK/Filtering/vtkCellType.h b/VTK/Filtering/vtkCellType.h index 568dd1f..222b765 100644 --- a/VTK/Filtering/vtkCellType.h +++ b/VTK/Filtering/vtkCellType.h @@ -29,7 +29,8 @@ // GetCell() and vtkGenericCell::SetCellType(). Also, to do the job right, // you'll also have to modify some filters (vtkGeometryFilter...) and // regression tests (example scripts) to reflect the new cell addition. -// Also, make sure to update vtkCellTypesStrings in vtkCellTypes.cxx. +// Also, make sure to update vtkCellTypesStrings in vtkCellTypes.cxx +// and the vtkCellTypes::IsLinear method in vtkCellTypes.h. // .SECTION Caveats // An unstructured grid stores the types of its cells as a diff --git a/VTK/Filtering/vtkCellTypes.h b/VTK/Filtering/vtkCellTypes.h index 3abbf79..6e44570 100644 --- a/VTK/Filtering/vtkCellTypes.h +++ b/VTK/Filtering/vtkCellTypes.h @@ -118,6 +118,13 @@ public: // defined in vtkCellType.h) static int GetTypeIdFromClassName(const char* classname); + // Description: + // This convenience method is a fast check to determine if a cell type + // represents a linear or nonlinear cell. This is generally much more + // efficient than getting the appropriate vtkCell and checking its IsLinear + // method. + static int IsLinear(unsigned char type); + protected: vtkCellTypes(); ~vtkCellTypes(); @@ -148,5 +155,11 @@ inline int vtkCellTypes::IsType(unsigned char type) return 0; } +//----------------------------------------------------------------------------- +inline int vtkCellTypes::IsLinear(unsigned char type) +{ + return ((type <= 20) || (type == VTK_CONVEX_POINT_SET)); +} + #endif diff --git a/VTK/Filtering/vtkDataSetAttributes.cxx b/VTK/Filtering/vtkDataSetAttributes.cxx index 319c9ea..2a4e9c3 100644 --- a/VTK/Filtering/vtkDataSetAttributes.cxx +++ b/VTK/Filtering/vtkDataSetAttributes.cxx @@ -45,7 +45,9 @@ const char vtkDataSetAttributes "TCoords", "Tensors", "GlobalIds", - "PedigreeIds" }; + "PedigreeIds", + "EdgeFlag" +}; const char vtkDataSetAttributes ::LongAttributeNames[vtkDataSetAttributes::NUM_ATTRIBUTES][35] = @@ -55,7 +57,9 @@ const char vtkDataSetAttributes "vtkDataSetAttributes::TCOORDS", "vtkDataSetAttributes::TENSORS", "vtkDataSetAttributes::GLOBALIDS", - "vtkDataSetAttributes::PEDIGREEIDS" }; + "vtkDataSetAttributes::PEDIGREEIDS", + "vtkDataSetAttributes::EDGEFLAG" +}; //-------------------------------------------------------------------------- // Construct object with copying turned on for all data. @@ -1066,6 +1070,7 @@ const int vtkDataSetAttributes 3, 9, 1, + 1, 1}; //-------------------------------------------------------------------------- @@ -1078,6 +1083,7 @@ const int vtkDataSetAttributes MAX, EXACT, EXACT, + EXACT, EXACT}; //-------------------------------------------------------------------------- diff --git a/VTK/Filtering/vtkDataSetAttributes.h b/VTK/Filtering/vtkDataSetAttributes.h index 2ddb8f0..1a0812a 100644 --- a/VTK/Filtering/vtkDataSetAttributes.h +++ b/VTK/Filtering/vtkDataSetAttributes.h @@ -90,6 +90,7 @@ public: TENSORS=4, GLOBALIDS=5, PEDIGREEIDS=6, + EDGEFLAG=7, NUM_ATTRIBUTES }; @@ -165,6 +166,7 @@ public: // vtkDataSetAttributes::TENSORS = 4 // vtkDataSetAttributes::GLOBALIDS = 5 // vtkDataSetAttributes::PEDIGREEIDS = 6 + // vtkDataSetAttributes::EDGEFLAG = 7 // Returns the index of the array if succesful, -1 if the array // is not in the list of arrays. int SetActiveAttribute(const char* name, int attributeType); diff --git a/VTK/Graphics/vtkDataSetSurfaceFilter.cxx b/VTK/Graphics/vtkDataSetSurfaceFilter.cxx index 3cd9010..c8c7337 100644 --- a/VTK/Graphics/vtkDataSetSurfaceFilter.cxx +++ b/VTK/Graphics/vtkDataSetSurfaceFilter.cxx @@ -16,8 +16,10 @@ #include "vtkCellArray.h" #include "vtkCellData.h" +#include "vtkDoubleArray.h" #include "vtkGenericCell.h" #include "vtkHexahedron.h" +#include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMergePoints.h" @@ -26,18 +28,19 @@ #include "vtkPolyData.h" #include "vtkPyramid.h" #include "vtkRectilinearGrid.h" -#include "vtkStructuredGrid.h" -#include "vtkUniformGrid.h" #include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkStructuredGrid.h" #include "vtkStructuredGridGeometryFilter.h" #include "vtkStructuredPoints.h" #include "vtkTetra.h" +#include "vtkUniformGrid.h" #include "vtkUnsignedCharArray.h" #include "vtkUnstructuredGrid.h" #include "vtkVoxel.h" #include "vtkWedge.h" -#include "vtkIdTypeArray.h" +#include <vtkstd/algorithm> +#include <vtksys/hash_map.hxx> static int sizeofFastQuad(int numPts) { @@ -45,6 +48,40 @@ static int sizeofFastQuad(int numPts) return static_cast<int>(sizeof(vtkFastGeomQuad)+(numPts-4)*sizeof(vtkIdType)); } + +class vtkDataSetSurfaceFilter::vtkEdgeInterpolationMap +{ +public: + void AddEdge(vtkIdType endpoint1, vtkIdType endpoint2, vtkIdType midpoint) { + if (endpoint1 > endpoint2) vtkstd::swap(endpoint1, endpoint2); + Map.insert(vtkstd::make_pair(vtkstd::make_pair(endpoint1, endpoint2), + midpoint)); + } + vtkIdType FindEdge(vtkIdType endpoint1, vtkIdType endpoint2) { + if (endpoint1 > endpoint2) vtkstd::swap(endpoint1, endpoint2); + MapType::iterator iter = Map.find(vtkstd::make_pair(endpoint1, endpoint2)); + if (iter != Map.end()) + { + return iter->second; + } + else + { + return -1; + } + } + +protected: + struct HashFunction { + public: + size_t operator()(vtkstd::pair<vtkIdType,vtkIdType> edge) const { + return static_cast<size_t>(edge.first + edge.second); + } + }; + typedef vtksys::hash_map<vtkstd::pair<vtkIdType, vtkIdType>, vtkIdType, + HashFunction> MapType; + MapType Map; +}; + vtkCxxRevisionMacro(vtkDataSetSurfaceFilter, "$Revision$"); vtkStandardNewMacro(vtkDataSetSurfaceFilter); @@ -53,6 +90,7 @@ vtkDataSetSurfaceFilter::vtkDataSetSurfaceFilter() { this->QuadHash = NULL; this->PointMap = NULL; + this->EdgeMap = NULL; this->QuadHashLength = 0; this->UseStrips = 0; this->NumberOfNewCells = 0; @@ -70,6 +108,10 @@ vtkDataSetSurfaceFilter::vtkDataSetSurfaceFilter() this->PassThroughPointIds = 0; this->OriginalCellIds = NULL; this->OriginalPointIds = NULL; + this->OriginalCellIdsName = NULL; + this->OriginalPointIdsName = NULL; + + this->NonlinearSubdivisionLevel = 1; } //---------------------------------------------------------------------------- @@ -84,6 +126,8 @@ vtkDataSetSurfaceFilter::~vtkDataSetSurfaceFilter() this->OriginalCellIds->Delete(); this->OriginalCellIds = NULL; } + this->SetOriginalCellIdsName(NULL); + this->SetOriginalPointIdsName(NULL); } //---------------------------------------------------------------------------- @@ -179,7 +223,7 @@ int vtkDataSetSurfaceFilter::RequestData( { //make a 1:1 mapping this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); vtkCellData *outputCD = output->GetCellData(); outputCD->AddArray(this->OriginalCellIds); @@ -196,7 +240,7 @@ int vtkDataSetSurfaceFilter::RequestData( { //make a 1:1 mapping this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); vtkPointData *outputPD = output->GetPointData(); outputPD->AddArray(this->OriginalPointIds); @@ -348,14 +392,14 @@ int vtkDataSetSurfaceFilter::StructuredExecute(vtkDataSet *input, if (this->PassThroughCellIds) { this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); output->GetCellData()->AddArray(this->OriginalCellIds); } if (this->PassThroughPointIds) { this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); output->GetPointData()->AddArray(this->OriginalPointIds); } @@ -916,6 +960,11 @@ void vtkDataSetSurfaceFilter::PrintSelf(ostream& os, vtkIndent indent) os << indent << "PassThroughCellIds: " << (this->PassThroughCellIds ? "On\n" : "Off\n"); os << indent << "PassThroughPointIds: " << (this->PassThroughPointIds ? "On\n" : "Off\n"); + os << indent << "OriginalCellIdsName: " << this->GetOriginalCellIdsName() << endl; + os << indent << "OriginalPointIdsName: " << this->GetOriginalPointIdsName() << endl; + + os << indent << "NonlinearSubdivisionLevel: " + << this->NonlinearSubdivisionLevel << endl; } //======================================================================== @@ -949,7 +998,6 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, vtkCellData *cd = input->GetCellData(); vtkPointData *outputPD = output->GetPointData(); vtkCellData *outputCD = output->GetCellData(); - vtkIdType outPts[6]; vtkFastGeomQuad *q; unsigned char* cellTypes = input->GetCellTypesArray()->GetPointer(0); @@ -958,9 +1006,19 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, vtkPoints *coords; vtkCell *face; int flag2D = 0; + + // These are for subdividing quadratic cells + vtkDoubleArray *parametricCoords; + vtkDoubleArray *parametricCoords2; + vtkIdList *outPts; + vtkIdList *outPts2; pts = vtkIdList::New(); coords = vtkPoints::New(); + parametricCoords = vtkDoubleArray::New(); + parametricCoords2 = vtkDoubleArray::New(); + outPts = vtkIdList::New(); + outPts2 = vtkIdList::New(); // might not be necessary to set the data type for coords // but certainly safer to do so coords->SetDataType(input->GetPoints()->GetData()->GetDataType()); @@ -979,21 +1037,28 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, newVerts = vtkCellArray::New(); newLines = vtkCellArray::New(); - outputPD->CopyGlobalIdsOn(); - outputPD->CopyAllocate(inputPD, numPts, numPts/2); + if (this->NonlinearSubdivisionLevel <= 1) + { + outputPD->CopyGlobalIdsOn(); + outputPD->CopyAllocate(inputPD, numPts, numPts/2); + } + else + { + outputPD->InterpolateAllocate(inputPD, numPts, numPts/2); + } outputCD->CopyGlobalIdsOn(); outputCD->CopyAllocate(inputCD, numCells, numCells/2); if (this->PassThroughCellIds) { this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); } if (this->PassThroughPointIds) { this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); } @@ -1201,14 +1266,40 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, if ( cellIds->GetNumberOfIds() <= 0) { // FIXME: Face could not be consistent. vtkOrderedTriangulator is a better option - face->Triangulate(0,pts,coords); - for (i=0; i < pts->GetNumberOfIds(); i+=3) + if (this->NonlinearSubdivisionLevel >= 1) { - this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1), - pts->GetId(i+2), cellId); + // TODO: Handle NonlinearSubdivisionLevel > 1 correctly. + face->Triangulate(0,pts,coords); + for (i=0; i < pts->GetNumberOfIds(); i+=3) + { + this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1), + pts->GetId(i+2), cellId); + } } - } - } + else + { + switch (face->GetCellType()) + { + case VTK_QUADRATIC_TRIANGLE: + this->InsertTriInHash(face->PointIds->GetId(0), + face->PointIds->GetId(1), + face->PointIds->GetId(2), cellId); + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + case VTK_QUADRATIC_LINEAR_QUAD: + this->InsertQuadInHash(face->PointIds->GetId(0), + face->PointIds->GetId(1), + face->PointIds->GetId(2), + face->PointIds->GetId(3), cellId); + break; + default: + vtkWarningMacro(<< "Encountered unknown nonlinear face."); + break; + } // switch cell type + } // subdivision level + } // cell has ids + } // for faces cellIds->Delete(); } //3d cell } //nonlinear cell @@ -1232,6 +1323,25 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, // Move to the next cell. cellPointer += (1 + *cellPointer); + // If we have a quadratic face and our subdivision level is zero, just treat + // it as a linear cell. This should work so long as the first points of the + // quadratic cell correspond to all those of the equivalent linear cell + // (which all the current definitions do). + if (this->NonlinearSubdivisionLevel < 1) + { + switch (cellType) + { + case VTK_QUADRATIC_TRIANGLE: + cellType = VTK_TRIANGLE; numCellPts = 3; + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + case VTK_QUADRATIC_LINEAR_QUAD: + cellType = VTK_POLYGON; numCellPts = 4; + break; + } + } + // A couple of common cases to see if things go faster. if (cellType == VTK_PIXEL) { // Do we really want to insert the 2D cells into a hash? @@ -1283,14 +1393,99 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, || cellType == VTK_BIQUADRATIC_QUAD || cellType == VTK_QUADRATIC_LINEAR_QUAD) { + // Note: we should not be here if this->NonlinearSubdivisionLevel is less + // than 1. See the check above. input->GetCell( cellId, cell ); cell->Triangulate( 0, pts, coords ); - for ( i=0; i < pts->GetNumberOfIds(); i+=3 ) + // Copy the level 1 subdivision points (which also exist in the input and + // can therefore just be copied over. Note that the output of Triangulate + // records triangles in pts where each 3 points defines a triangle. We + // will keep this invariant and also keep the same invariant in + // parametericCoords and outPts later. + outPts->Reset(); + for ( i=0; i < pts->GetNumberOfIds(); i++ ) { - outPts[0] = this->GetOutputPointId( pts->GetId(i), input, newPts, outputPD ); - outPts[1] = this->GetOutputPointId( pts->GetId(i+1), input, newPts, outputPD ); - outPts[2] = this->GetOutputPointId( pts->GetId(i+2), input, newPts, outputPD ); - newPolys->InsertNextCell( 3, outPts ); + vtkIdType op; + op = this->GetOutputPointId(pts->GetId(i), input, newPts, outputPD); + outPts->InsertNextId(op); + } + // Do any further subdivision if necessary. + if (this->NonlinearSubdivisionLevel > 1) + { + // We are going to need parametric coordinates to further subdivide. + double *pc = cell->GetParametricCoords(); + parametricCoords->Reset(); + parametricCoords->SetNumberOfComponents(3); + for (i = 0; i < pts->GetNumberOfIds(); i++) + { + vtkIdType ptId = pts->GetId(i); + vtkIdType cellPtId; + for (cellPtId = 0; cell->GetPointId(cellPtId) != ptId; cellPtId++); + parametricCoords->InsertNextTupleValue(pc + 3*cellPtId); + } + // Subdivide these triangles as many more times as necessary. Remember + // that we have already done the first subdivision. + for (j = 1; j < this->NonlinearSubdivisionLevel; j++) + { + parametricCoords2->Reset(); + parametricCoords2->SetNumberOfComponents(3); + outPts2->Reset(); + // Each triangle will be split into 4 triangles. + for (i = 0; i < outPts->GetNumberOfIds(); i += 3) + { + // Hold the input point ids and parametric coordinates. First 3 + // indices are the original points. Second three are the midpoints + // in the edges (0,1), (1,2) and (2,0), respectively (see comment + // below). + vtkIdType inPts[6]; + double inParamCoords[6][3]; + int k; + for (k = 0; k < 3; k++) + { + inPts[k] = outPts->GetId(i+k); + parametricCoords->GetTupleValue(i+k, inParamCoords[k]); + } + for (k = 3; k < 6; k++) + { + int pt1 = k-3; + int pt2 = (pt1 < 2) ? (pt1 + 1) : 0; + inParamCoords[k][0] = 0.5*(inParamCoords[pt1][0] + inParamCoords[pt2][0]); + inParamCoords[k][1] = 0.5*(inParamCoords[pt1][1] + inParamCoords[pt2][1]); + inParamCoords[k][2] = 0.5*(inParamCoords[pt1][2] + inParamCoords[pt2][2]); + inPts[k] = GetInterpolatedPointId(inPts[pt1], inPts[pt2], + input, cell, + inParamCoords[k], newPts, + outputPD); + } + // * 0 + // / \ Use the 6 points recorded + // / \ in inPts and inParamCoords + // 3 *-----* 5 to create the 4 triangles + // / \ / \ shown here. + // / \ / \ . + // *-----*-----* + // 1 4 2 + const int subtriangles[12] = {0,3,5, 3,1,4, 3,4,5, 5,4,2}; + for (k = 0; k < 12; k++) + { + int localId = subtriangles[k]; + outPts2->InsertNextId(inPts[localId]); + parametricCoords2->InsertNextTupleValue(inParamCoords[localId]); + } + } // Iterate over triangles + // Now that we have recorded the subdivided triangles in outPts2 and + // parametricCoords2, swap them with outPts and parametricCoords to + // make them the current ones. + vtkstd::swap(outPts, outPts2); + vtkstd::swap(parametricCoords, parametricCoords2); + } // Iterate over subdivision levels + } // If further subdivision + + // Now that we have done all the subdivisions and created all of the + // points, record the triangles. + for (i = 0; i < outPts->GetNumberOfIds(); i += 3) + { + newPolys->InsertNextCell(3, outPts->GetPointer(i)); this->RecordOrigCellId(this->NumberOfNewCells, cellId); outputCD->CopyData(cd, cellId, this->NumberOfNewCells++); } @@ -1326,6 +1521,10 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, cell->Delete(); coords->Delete(); pts->Delete(); + parametricCoords->Delete(); + parametricCoords2->Delete(); + outPts->Delete(); + outPts2->Delete(); output->SetPoints(newPts); newPts->Delete(); @@ -1387,6 +1586,7 @@ void vtkDataSetSurfaceFilter::InitializeQuadHash(vtkIdType numPoints) this->QuadHash[i] = NULL; this->PointMap[i] = -1; } + this->EdgeMap = new vtkEdgeInterpolationMap; } //---------------------------------------------------------------------------- @@ -1406,6 +1606,8 @@ void vtkDataSetSurfaceFilter::DeleteQuadHash() this->QuadHashLength = 0; delete [] this->PointMap; this->PointMap = NULL; + delete this->EdgeMap; + this->EdgeMap = NULL; } //---------------------------------------------------------------------------- @@ -1801,6 +2003,34 @@ vtkIdType vtkDataSetSurfaceFilter::GetOutputPointId(vtkIdType inPtId, return outPtId; } +//----------------------------------------------------------------------------- +vtkIdType vtkDataSetSurfaceFilter::GetInterpolatedPointId(vtkIdType edgePtA, + vtkIdType edgePtB, + vtkDataSet *input, + vtkCell *cell, + double pcoords[3], + vtkPoints *outPts, + vtkPointData *outPD) +{ + vtkIdType outPtId; + + outPtId = this->EdgeMap->FindEdge(edgePtA, edgePtB); + if (outPtId == -1) + { + int subId = -1; + double wcoords[3]; + double weights[100]; // Any reason to need more? + cell->EvaluateLocation(subId, pcoords, wcoords, weights); + outPtId = outPts->InsertNextPoint(wcoords); + outPD->InterpolatePoint(input->GetPointData(), outPtId, + cell->GetPointIds(), weights); + this->RecordOrigPointId(outPtId, -1); + this->EdgeMap->AddEdge(edgePtA, edgePtB, outPtId); + } + + return outPtId; +} + //---------------------------------------------------------------------------- void vtkDataSetSurfaceFilter::RecordOrigCellId(vtkIdType destIndex, vtkIdType originalId) diff --git a/VTK/Graphics/vtkDataSetSurfaceFilter.h b/VTK/Graphics/vtkDataSetSurfaceFilter.h index 0e6117a..412ff5b 100644 --- a/VTK/Graphics/vtkDataSetSurfaceFilter.h +++ b/VTK/Graphics/vtkDataSetSurfaceFilter.h @@ -80,6 +80,35 @@ public: vtkGetMacro(PassThroughPointIds,int); vtkBooleanMacro(PassThroughPointIds,int); + // Description: + // If PassThroughCellIds or PassThroughPointIds is on, then these ivars + // control the name given to the field in which the ids are written into. If + // set to NULL, then vtkOriginalCellIds or vtkOriginalPointIds (the default) + // is used, respectively. + vtkSetStringMacro(OriginalCellIdsName); + virtual const char *GetOriginalCellIdsName() { + return ( this->OriginalCellIdsName + ? this->OriginalCellIdsName : "vtkOriginalCellIds"); + } + vtkSetStringMacro(OriginalPointIdsName); + virtual const char *GetOriginalPointIdsName() { + return ( this->OriginalPointIdsName + ? this->OriginalPointIdsName : "vtkOriginalPointIds"); + } + + // Description: + // If the input is an unstructured grid with nonlinear faces, this parameter + // determines how many times the face is subdivided into linear faces. If 0, + // the output is the equivalent of its linear couterpart (and the midpoints + // determining the nonlinear interpolation are discarded). If 1 (the + // default), the nonlinear face is triangulated based on the midpoints. If + // greater than 1, the triangulated pieces are recursively subdivided to reach + // the desired subdivision. Setting the value to greater than 1 may cause + // some point data to not be passed even if no nonlinear faces exist. This + // option has no effect if the input is not an unstructured grid. + vtkSetMacro(NonlinearSubdivisionLevel, int); + vtkGetMacro(NonlinearSubdivisionLevel, int); + protected: vtkDataSetSurfaceFilter(); ~vtkDataSetSurfaceFilter(); @@ -124,6 +153,14 @@ protected: vtkIdType *PointMap; vtkIdType GetOutputPointId(vtkIdType inPtId, vtkDataSet *input, vtkPoints *outPts, vtkPointData *outPD); +//BTX + class vtkEdgeInterpolationMap; +//ETX + vtkEdgeInterpolationMap *EdgeMap; + vtkIdType GetInterpolatedPointId(vtkIdType edgePtA, vtkIdType edgePtB, + vtkDataSet *input, vtkCell *cell, + double pcoords[3], vtkPoints *outPts, + vtkPointData *outPD); vtkIdType NumberOfNewCells; @@ -145,10 +182,14 @@ protected: void RecordOrigCellId(vtkIdType newIndex, vtkIdType origId); virtual void RecordOrigCellId(vtkIdType newIndex, vtkFastGeomQuad *quad); vtkIdTypeArray *OriginalCellIds; + char *OriginalCellIdsName; int PassThroughPointIds; void RecordOrigPointId(vtkIdType newIndex, vtkIdType origId); vtkIdTypeArray *OriginalPointIds; + char *OriginalPointIdsName; + + int NonlinearSubdivisionLevel; private: vtkDataSetSurfaceFilter(const vtkDataSetSurfaceFilter&); // Not implemented. diff --git a/VTK/Graphics/vtkUnstructuredGridGeometryFilter.cxx b/VTK/Graphics/vtkUnstructuredGridGeometryFilter.cxx index 3383eda..4876314 100644 --- a/VTK/Graphics/vtkUnstructuredGridGeometryFilter.cxx +++ b/VTK/Graphics/vtkUnstructuredGridGeometryFilter.cxx @@ -27,6 +27,7 @@ #include "vtkPolyData.h" #include "vtkPyramid.h" #include "vtkPentagonalPrism.h" +#include "vtkSmartPointer.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkStructuredGrid.h" #include "vtkTetra.h" @@ -699,6 +700,11 @@ vtkUnstructuredGridGeometryFilter::vtkUnstructuredGridGeometryFilter() this->CellClipping = 0; this->ExtentClipping = 0; + this->PassThroughCellIds = 0; + this->PassThroughPointIds = 0; + this->OriginalCellIdsName = NULL; + this->OriginalPointIdsName = NULL; + this->Merging = 1; this->Locator = NULL; @@ -713,6 +719,9 @@ vtkUnstructuredGridGeometryFilter::~vtkUnstructuredGridGeometryFilter() this->Locator->UnRegister(this); this->Locator = NULL; } + + this->SetOriginalCellIdsName(NULL); + this->SetOriginalPointIdsName(NULL); } //----------------------------------------------------------------------------- @@ -886,8 +895,24 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPts->Allocate(numPts); output->Allocate(numCells); outputPD->CopyAllocate(pd,numPts,numPts/2); + vtkSmartPointer<vtkIdTypeArray> originalPointIds; + if (this->PassThroughPointIds) + { + originalPointIds = vtkSmartPointer<vtkIdTypeArray>::New(); + originalPointIds->SetName(this->GetOriginalPointIdsName()); + originalPointIds->SetNumberOfComponents(1); + originalPointIds->Allocate(numPts, numPts/2); + } outputCD->CopyAllocate(cd,numCells,numCells/2); + vtkSmartPointer<vtkIdTypeArray> originalCellIds; + if (this->PassThroughCellIds) + { + originalCellIds = vtkSmartPointer<vtkIdTypeArray>::New(); + originalCellIds->SetName(this->GetOriginalCellIdsName()); + originalCellIds->SetNumberOfComponents(1); + originalCellIds->Allocate(numCells, numCells/2); + } vtkIdType *pointMap=0; @@ -959,6 +984,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( if ( this->Locator->InsertUniquePoint(x, newPtId) ) { outputPD->CopyData(pd,ptId,newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(newPtId); } @@ -973,6 +1002,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPtId=newPts->InsertNextPoint(inPts->GetPoint(ptId)); pointMap[ptId]=newPtId; outputPD->CopyData(pd, ptId, newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(pointMap[ptId]); } @@ -980,6 +1013,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newCellId = output->InsertNextCell(cellType,cellIds); outputCD->CopyData(cd, cellId, newCellId); + if (this->PassThroughCellIds) + { + originalCellIds->InsertValue(newCellId, cellId); + } } else // added the faces to the hashtable { @@ -1358,6 +1395,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( if ( this->Locator->InsertUniquePoint(x, newPtId) ) { outputPD->CopyData(pd,ptId,newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(newPtId); } @@ -1372,6 +1413,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPtId=newPts->InsertNextPoint(inPts->GetPoint(ptId)); pointMap[ptId]=newPtId; outputPD->CopyData(pd, ptId, newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(pointMap[ptId]); } @@ -1379,6 +1424,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newCellId = output->InsertNextCell(cellType,cellIds); outputCD->CopyData(cd, cellId, newCellId); + if (this->PassThroughCellIds) + { + originalCellIds->InsertValue(newCellId, cellId); + } } cursor.Next(); } @@ -1396,6 +1445,15 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPts->Delete(); // output->SetCells(types,locs,conn); + + if (this->PassThroughPointIds) + { + outputPD->AddArray(originalPointIds); + } + if (this->PassThroughCellIds) + { + outputCD->AddArray(originalCellIds); + } if(!this->Merging && this->Locator) { @@ -1471,6 +1529,12 @@ void vtkUnstructuredGridGeometryFilter::PrintSelf(ostream& os, os << indent << "CellClipping: " << (this->CellClipping ? "On\n" : "Off\n"); os << indent << "ExtentClipping: " << (this->ExtentClipping ? "On\n" : "Off\n"); + os << indent << "PassThroughCellIds: " << this->PassThroughCellIds << endl; + os << indent << "PassThroughPointIds: " << this->PassThroughPointIds << endl; + + os << indent << "OriginalCellIdsName: " << this->GetOriginalCellIdsName() << endl; + os << indent << "OriginalPointIdsName: " << this->GetOriginalPointIdsName() << endl; + os << indent << "Merging: " << (this->Merging ? "On\n" : "Off\n"); if ( this->Locator ) { diff --git a/VTK/Graphics/vtkUnstructuredGridGeometryFilter.h b/VTK/Graphics/vtkUnstructuredGridGeometryFilter.h index eeffb82..ff64e4e 100644 --- a/VTK/Graphics/vtkUnstructuredGridGeometryFilter.h +++ b/VTK/Graphics/vtkUnstructuredGridGeometryFilter.h @@ -107,6 +107,36 @@ public: vtkBooleanMacro(Merging,int); // Description: + // If on, the output polygonal dataset will have a celldata array that + // holds the cell index of the original 3D cell that produced each output + // cell. This is useful for cell picking. The default is off to conserve + // memory. Note that PassThroughCellIds will be ignored if UseStrips is on, + // since in that case each tringle strip can represent more than on of the + // input cells. + vtkSetMacro(PassThroughCellIds,int); + vtkGetMacro(PassThroughCellIds,int); + vtkBooleanMacro(PassThroughCellIds,int); + vtkSetMacro(PassThroughPointIds,int); + vtkGetMacro(PassThroughPointIds,int); + vtkBooleanMacro(PassThroughPointIds,int); + + // Description: + // If PassThroughCellIds or PassThroughPointIds is on, then these ivars + // control the name given to the field in which the ids are written into. If + // set to NULL, then vtkOriginalCellIds or vtkOriginalPointIds (the default) + // is used, respectively. + vtkSetStringMacro(OriginalCellIdsName); + virtual const char *GetOriginalCellIdsName() { + return ( this->OriginalCellIdsName + ? this->OriginalCellIdsName : "vtkOriginalCellIds"); + } + vtkSetStringMacro(OriginalPointIdsName); + virtual const char *GetOriginalPointIdsName() { + return ( this->OriginalPointIdsName + ? this->OriginalPointIdsName : "vtkOriginalPointIds"); + } + + // Description: // Set / get a spatial locator for merging points. By // default an instance of vtkMergePoints is used. void SetLocator(vtkIncrementalPointLocator *locator); @@ -138,6 +168,11 @@ protected: int CellClipping; int ExtentClipping; + int PassThroughCellIds; + int PassThroughPointIds; + char *OriginalCellIdsName; + char *OriginalPointIdsName; + int Merging; vtkIncrementalPointLocator *Locator; diff --git a/VTK/IO/vtkSLACReader.cxx b/VTK/IO/vtkSLACReader.cxx index aca4c0c..9defeea 100644 --- a/VTK/IO/vtkSLACReader.cxx +++ b/VTK/IO/vtkSLACReader.cxx @@ -1315,13 +1315,6 @@ int vtkSLACReader::ReadMidpointCoordinates( int vtkSLACReader::ReadMidpointData(int meshFD, vtkMultiBlockDataSet *output, MidpointIdMap &midpointIds) { - static bool GaveMidpointWarning = false; - if (!GaveMidpointWarning) - { - vtkWarningMacro(<< "Quadratic elements not displayed entirely correctly yet. Quadratic triangles are drawn as 4 linear triangles."); - GaveMidpointWarning = true; - } - // Get the point information from the data. vtkPoints *points = vtkPoints::SafeDownCast( output->GetInformation()->Get(vtkSLACReader::POINTS())); diff --git a/VTK/Rendering/vtkChooserPainter.cxx b/VTK/Rendering/vtkChooserPainter.cxx index cf11de4..f73e4e9 100644 --- a/VTK/Rendering/vtkChooserPainter.cxx +++ b/VTK/Rendering/vtkChooserPainter.cxx @@ -20,6 +20,7 @@ #include "vtkInformation.h" #include "vtkLinesPainter.h" #include "vtkObjectFactory.h" +#include "vtkPointData.h" #include "vtkPointsPainter.h" #include "vtkPolyData.h" #include "vtkPolygonsPainter.h" @@ -338,7 +339,9 @@ void vtkChooserPainter::RenderInternal(vtkRenderer* renderer, vtkActor* actor, if ( this->UseLinesPainterForWireframes && (actor->GetProperty()->GetRepresentation() == VTK_WIREFRAME) && !actor->GetProperty()->GetBackfaceCulling() - && !actor->GetProperty()->GetFrontfaceCulling() ) + && !actor->GetProperty()->GetFrontfaceCulling() + && !this->GetInputAsPolyData()->GetPointData()->GetAttribute( + vtkDataSetAttributes::EDGEFLAG) ) { this->LinePainter->Render(renderer, actor, vtkPainter::POLYS, forceCompileOnly); diff --git a/VTK/Rendering/vtkLinesPainter.cxx b/VTK/Rendering/vtkLinesPainter.cxx index e58d811..8bf7d6b 100644 --- a/VTK/Rendering/vtkLinesPainter.cxx +++ b/VTK/Rendering/vtkLinesPainter.cxx @@ -131,6 +131,9 @@ int vtkLinesPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, // we just ignore the flag. idx &= (~VTK_PDM_FIELD_COLORS); + // Also ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + // draw all the elements, use fast path if available switch (idx) { diff --git a/VTK/Rendering/vtkOpenGLPainterDeviceAdapter.cxx b/VTK/Rendering/vtkOpenGLPainterDeviceAdapter.cxx index 3745b42..f62fb33 100644 --- a/VTK/Rendering/vtkOpenGLPainterDeviceAdapter.cxx +++ b/VTK/Rendering/vtkOpenGLPainterDeviceAdapter.cxx @@ -259,6 +259,7 @@ int vtkOpenGLPainterDeviceAdapter::IsAttributesSupported(int attribute) case vtkDataSetAttributes::NORMALS: case vtkDataSetAttributes::SCALARS: case vtkDataSetAttributes::TCOORDS: + case vtkDataSetAttributes::EDGEFLAG: return 1; } return 0; @@ -534,6 +535,18 @@ void vtkOpenGLPainterDeviceAdapter::SendAttribute(int index, int numcomp, return; } break; + case vtkDataSetAttributes::EDGEFLAG: // Edge Flag + if (numcomp != 1) + { + vtkErrorMacro("Bad number of components."); + return; + } + switch (type) + { + vtkTemplateMacro(glEdgeFlag(static_cast<GLboolean>( + reinterpret_cast<const VTK_TT*>(attribute)[offset]))); + } + break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -715,6 +728,33 @@ void vtkOpenGLPainterDeviceAdapter::SetAttributePointer(int index, } glTexCoordPointer(numcomponents, gltype, stride, pointer); break; + case vtkDataSetAttributes::EDGEFLAG: // Edge flag + if (numcomponents != 1) + { + vtkErrorMacro("Edge flag must have one component."); + return; + } + // Flag must be conformant to GLboolean + if ((type == VTK_FLOAT) || (type == GL_DOUBLE)) + { + vtkErrorMacro("Unsupported type for edge flag: " << type); + return; + } + // Thus is an unfriendly way to force the array to be conformant to + // a GLboolean array. At the very least there should be some indication + // in VTK outside of OpenGL to determine which VTK type to use. + switch (type) + { + vtkTemplateMacro(if (sizeof(VTK_TT) != sizeof(GLboolean)) + { + vtkErrorMacro(<< "Unsupported tyep for edge flag: " + << type); + return; + } + ); + } + glEdgeFlagPointer(stride, pointer); + break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -735,6 +775,8 @@ void vtkOpenGLPainterDeviceAdapter::EnableAttributeArray(int index) glEnableClientState(GL_COLOR_ARRAY); break; case vtkDataSetAttributes::TCOORDS: glEnableClientState(GL_TEXTURE_COORD_ARRAY); break; + case vtkDataSetAttributes::EDGEFLAG: + glEnableClientState(GL_EDGE_FLAG_ARRAY); break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -753,6 +795,8 @@ void vtkOpenGLPainterDeviceAdapter::DisableAttributeArray(int index) glDisableClientState(GL_COLOR_ARRAY); break; case vtkDataSetAttributes::TCOORDS: glDisableClientState(GL_TEXTURE_COORD_ARRAY); break; + case vtkDataSetAttributes::EDGEFLAG: + glDisableClientState(GL_EDGE_FLAG_ARRAY); break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; diff --git a/VTK/Rendering/vtkPointsPainter.cxx b/VTK/Rendering/vtkPointsPainter.cxx index fd78a9c..7a2bd28 100644 --- a/VTK/Rendering/vtkPointsPainter.cxx +++ b/VTK/Rendering/vtkPointsPainter.cxx @@ -107,6 +107,10 @@ int vtkPointsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, // since this painter does not deal with field colors specially, // we just ignore the flag. idx &= (~VTK_PDM_FIELD_COLORS); + + // Also ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + switch (idx) { case 0://no cell/point attribs are present. diff --git a/VTK/Rendering/vtkPolygonsPainter.cxx b/VTK/Rendering/vtkPolygonsPainter.cxx index 61fe013..cf14987 100644 --- a/VTK/Rendering/vtkPolygonsPainter.cxx +++ b/VTK/Rendering/vtkPolygonsPainter.cxx @@ -181,6 +181,8 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, pd->GetLines()->GetNumberOfCells(); vtkIdType cellNumStart = cellNum; vtkIdType totalCells = ca->GetNumberOfCells(); + vtkUnsignedCharArray *ef = vtkUnsignedCharArray::SafeDownCast( + pd->GetPointData()->GetAttribute(vtkDataSetAttributes::EDGEFLAG)); vtkPainterDeviceAdapter* device = ren->GetRenderWindow()-> GetPainterDeviceAdapter(); @@ -188,6 +190,7 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, void *normals = 0; void *tcoords = 0; unsigned char *colors = 0; + unsigned char *edgeflags = 0; int primitive = VTK_POLYGON; if (ca->GetNumberOfCells() == 0) @@ -211,12 +214,17 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, { tcoords = t->GetVoidPointer(0); } + if (ef) + { + edgeflags = ef->GetPointer(0); + } vtkIdType *ptIds = ca->GetPointer(); vtkIdType *endPtIds = ptIds + ca->GetNumberOfConnectivityEntries(); int ptype = p->GetDataType(); int ntype = (n)? n->GetDataType() : 0; int ttype = (t)? t->GetDataType() : 0; int tcomps = (t)? t->GetNumberOfComponents() : 0; + int eftype = (ef)? ef->GetDataType() : 0; int celloffset = 0; // since this painter does not deal with field colors specially, @@ -412,9 +420,266 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, VTK_UNSIGNED_CHAR, colors); colors += 4;, celloffset = cellNum;); break; + + case VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, ;,;); + } + break; + + case VTK_PDM_NORMALS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + + case VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, 1, + ttype, tcoords, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, colors); + colors += 4;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, colors); + colors += 4;,;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++; + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, colors); + colors += 4;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++; + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, colors); + colors += 4;, + celloffset = cellNum;); + break; + default: return 0; // let the delegate painter handle it. } + + if (idx & VTK_PDM_EDGEFLAGS) + { + // Reset the edge flag to 1 so that if the next thing rendered does not + // have an edge flag, it will have all edges on. + unsigned char edgeflag = 1; + device->SendAttribute(vtkPointData::EDGEFLAG, 1, VTK_UNSIGNED_CHAR, + &edgeflag, 0); + } + return 1; } diff --git a/VTK/Rendering/vtkPrimitivePainter.cxx b/VTK/Rendering/vtkPrimitivePainter.cxx index e911425..d3a2cad 100644 --- a/VTK/Rendering/vtkPrimitivePainter.cxx +++ b/VTK/Rendering/vtkPrimitivePainter.cxx @@ -159,6 +159,7 @@ void vtkPrimitivePainter::RenderInternal(vtkRenderer* renderer, vtkUnsignedCharArray *c=NULL; vtkDataArray *n; vtkDataArray *t; + vtkDataArray *ef; int tDim; vtkPolyData *input = this->GetInputAsPolyData(); int cellNormals; @@ -269,6 +270,28 @@ void vtkPrimitivePainter::RenderInternal(vtkRenderer* renderer, idx |= VTK_PDM_TCOORDS; } + // Edge flag + ef = input->GetPointData()->GetAttribute(vtkDataSetAttributes::EDGEFLAG); + if (ef) + { + if (ef->GetNumberOfComponents() != 1) + { + vtkDebugMacro(<< "Currently only 1d edge flags are supported."); + ef = NULL; + } + if (!ef->IsA("vtkUnsignedCharArray")) + { + vtkDebugMacro(<< "Currently only unsigned char edge flags are suported."); + ef = NULL; + } + } + + // Set the flags + if (ef) + { + idx |= VTK_PDM_EDGEFLAGS; + } + if (!act) { vtkErrorMacro("No actor"); diff --git a/VTK/Rendering/vtkPrimitivePainter.h b/VTK/Rendering/vtkPrimitivePainter.h index 91f4d85..5ef39ea 100644 --- a/VTK/Rendering/vtkPrimitivePainter.h +++ b/VTK/Rendering/vtkPrimitivePainter.h @@ -49,14 +49,15 @@ protected: //BTX enum { - VTK_PDM_NORMALS = 0x01, - VTK_PDM_COLORS = 0x02, - VTK_PDM_TCOORDS = 0x04, - VTK_PDM_CELL_COLORS = 0x08, - VTK_PDM_CELL_NORMALS = 0x10, - VTK_PDM_OPAQUE_COLORS = 0x20, - VTK_PDM_FIELD_COLORS = 0x40, - VTK_PDM_GENERIC_VERTEX_ATTRIBUTES =0x80 + VTK_PDM_NORMALS = 0x001, + VTK_PDM_COLORS = 0x002, + VTK_PDM_TCOORDS = 0x004, + VTK_PDM_CELL_COLORS = 0x008, + VTK_PDM_CELL_NORMALS = 0x010, + VTK_PDM_OPAQUE_COLORS = 0x020, + VTK_PDM_FIELD_COLORS = 0x040, + VTK_PDM_EDGEFLAGS = 0x080, + VTK_PDM_GENERIC_VERTEX_ATTRIBUTES = 0x100 }; //ETX diff --git a/VTK/Rendering/vtkTStripsPainter.cxx b/VTK/Rendering/vtkTStripsPainter.cxx index faea55c..16114f3 100644 --- a/VTK/Rendering/vtkTStripsPainter.cxx +++ b/VTK/Rendering/vtkTStripsPainter.cxx @@ -189,6 +189,9 @@ int vtkTStripsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, int ttype = (t)? t->GetDataType() : 0; int tcomps = (t)? t->GetNumberOfComponents() : 0; + // Ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + // draw all the elements, use fast path if available switch (idx) { ![]() diff --git a/Filtering/vtkCellType.h b/Filtering/vtkCellType.h index 4633f74..0661685 100644 --- a/Filtering/vtkCellType.h +++ b/Filtering/vtkCellType.h @@ -29,7 +29,8 @@ // GetCell() and vtkGenericCell::SetCellType(). Also, to do the job right, // you'll also have to modify some filters (vtkGeometryFilter...) and // regression tests (example scripts) to reflect the new cell addition. -// Also, make sure to update vtkCellTypesStrings in vtkCellTypes.cxx. +// Also, make sure to update vtkCellTypesStrings in vtkCellTypes.cxx +// and the vtkCellTypes::IsLinear method in vtkCellTypes.h. // .SECTION Caveats // An unstructured grid stores the types of its cells as a diff --git a/Filtering/vtkCellTypes.h b/Filtering/vtkCellTypes.h index 08015d2..b56132c 100644 --- a/Filtering/vtkCellTypes.h +++ b/Filtering/vtkCellTypes.h @@ -118,6 +118,13 @@ public: // defined in vtkCellType.h) static int GetTypeIdFromClassName(const char* classname); + // Description: + // This convenience method is a fast check to determine if a cell type + // represents a linear or nonlinear cell. This is generally much more + // efficient than getting the appropriate vtkCell and checking its IsLinear + // method. + static int IsLinear(unsigned char type); + protected: vtkCellTypes(); ~vtkCellTypes(); @@ -148,5 +155,11 @@ inline int vtkCellTypes::IsType(unsigned char type) return 0; } +//----------------------------------------------------------------------------- +inline int vtkCellTypes::IsLinear(unsigned char type) +{ + return ((type <= 20) || (type == VTK_CONVEX_POINT_SET)); +} + #endif diff --git a/Filtering/vtkDataSetAttributes.cxx b/Filtering/vtkDataSetAttributes.cxx index d5739b0..67505f7 100644 --- a/Filtering/vtkDataSetAttributes.cxx +++ b/Filtering/vtkDataSetAttributes.cxx @@ -51,7 +51,9 @@ const char vtkDataSetAttributes "TCoords", "Tensors", "GlobalIds", - "PedigreeIds" }; + "PedigreeIds", + "EdgeFlag" +}; const char vtkDataSetAttributes ::LongAttributeNames[vtkDataSetAttributes::NUM_ATTRIBUTES][35] = @@ -61,7 +63,9 @@ const char vtkDataSetAttributes "vtkDataSetAttributes::TCOORDS", "vtkDataSetAttributes::TENSORS", "vtkDataSetAttributes::GLOBALIDS", - "vtkDataSetAttributes::PEDIGREEIDS" }; + "vtkDataSetAttributes::PEDIGREEIDS", + "vtkDataSetAttributes::EDGEFLAG" +}; //-------------------------------------------------------------------------- // Construct object with copying turned on for all data. @@ -1073,6 +1077,7 @@ const int vtkDataSetAttributes 3, 9, 1, + 1, 1}; //-------------------------------------------------------------------------- @@ -1085,6 +1090,7 @@ const int vtkDataSetAttributes MAX, EXACT, EXACT, + EXACT, EXACT}; //-------------------------------------------------------------------------- diff --git a/Filtering/vtkDataSetAttributes.h b/Filtering/vtkDataSetAttributes.h index 33051cc..187fe54 100644 --- a/Filtering/vtkDataSetAttributes.h +++ b/Filtering/vtkDataSetAttributes.h @@ -90,6 +90,7 @@ public: TENSORS=4, GLOBALIDS=5, PEDIGREEIDS=6, + EDGEFLAG=7, NUM_ATTRIBUTES }; @@ -165,6 +166,7 @@ public: // vtkDataSetAttributes::TENSORS = 4 // vtkDataSetAttributes::GLOBALIDS = 5 // vtkDataSetAttributes::PEDIGREEIDS = 6 + // vtkDataSetAttributes::EDGEFLAG = 7 // Returns the index of the array if succesful, -1 if the array // is not in the list of arrays. int SetActiveAttribute(const char* name, int attributeType); diff --git a/Graphics/vtkDataSetSurfaceFilter.cxx b/Graphics/vtkDataSetSurfaceFilter.cxx index 18c7c0a..d4f189d 100644 --- a/Graphics/vtkDataSetSurfaceFilter.cxx +++ b/Graphics/vtkDataSetSurfaceFilter.cxx @@ -16,8 +16,10 @@ #include "vtkCellArray.h" #include "vtkCellData.h" +#include "vtkDoubleArray.h" #include "vtkGenericCell.h" #include "vtkHexahedron.h" +#include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMergePoints.h" @@ -26,18 +28,19 @@ #include "vtkPolyData.h" #include "vtkPyramid.h" #include "vtkRectilinearGrid.h" -#include "vtkStructuredGrid.h" -#include "vtkUniformGrid.h" #include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkStructuredGrid.h" #include "vtkStructuredGridGeometryFilter.h" #include "vtkStructuredPoints.h" #include "vtkTetra.h" +#include "vtkUniformGrid.h" #include "vtkUnsignedCharArray.h" #include "vtkUnstructuredGrid.h" #include "vtkVoxel.h" #include "vtkWedge.h" -#include "vtkIdTypeArray.h" +#include <vtkstd/algorithm> +#include <vtksys/hash_map.hxx> static int sizeofFastQuad(int numPts) { @@ -45,6 +48,40 @@ static int sizeofFastQuad(int numPts) return static_cast<int>(sizeof(vtkFastGeomQuad)+(numPts-4)*sizeof(vtkIdType)); } + +class vtkDataSetSurfaceFilter::vtkEdgeInterpolationMap +{ +public: + void AddEdge(vtkIdType endpoint1, vtkIdType endpoint2, vtkIdType midpoint) { + if (endpoint1 > endpoint2) vtkstd::swap(endpoint1, endpoint2); + Map.insert(vtkstd::make_pair(vtkstd::make_pair(endpoint1, endpoint2), + midpoint)); + } + vtkIdType FindEdge(vtkIdType endpoint1, vtkIdType endpoint2) { + if (endpoint1 > endpoint2) vtkstd::swap(endpoint1, endpoint2); + MapType::iterator iter = Map.find(vtkstd::make_pair(endpoint1, endpoint2)); + if (iter != Map.end()) + { + return iter->second; + } + else + { + return -1; + } + } + +protected: + struct HashFunction { + public: + size_t operator()(vtkstd::pair<vtkIdType,vtkIdType> edge) const { + return static_cast<size_t>(edge.first + edge.second); + } + }; + typedef vtksys::hash_map<vtkstd::pair<vtkIdType, vtkIdType>, vtkIdType, + HashFunction> MapType; + MapType Map; +}; + vtkCxxRevisionMacro(vtkDataSetSurfaceFilter, "1.75"); vtkStandardNewMacro(vtkDataSetSurfaceFilter); @@ -53,6 +90,7 @@ vtkDataSetSurfaceFilter::vtkDataSetSurfaceFilter() { this->QuadHash = NULL; this->PointMap = NULL; + this->EdgeMap = NULL; this->QuadHashLength = 0; this->UseStrips = 0; this->NumberOfNewCells = 0; @@ -70,6 +108,10 @@ vtkDataSetSurfaceFilter::vtkDataSetSurfaceFilter() this->PassThroughPointIds = 0; this->OriginalCellIds = NULL; this->OriginalPointIds = NULL; + this->OriginalCellIdsName = NULL; + this->OriginalPointIdsName = NULL; + + this->NonlinearSubdivisionLevel = 1; } //---------------------------------------------------------------------------- @@ -84,6 +126,8 @@ vtkDataSetSurfaceFilter::~vtkDataSetSurfaceFilter() this->OriginalCellIds->Delete(); this->OriginalCellIds = NULL; } + this->SetOriginalCellIdsName(NULL); + this->SetOriginalPointIdsName(NULL); } //---------------------------------------------------------------------------- @@ -175,7 +219,7 @@ int vtkDataSetSurfaceFilter::RequestData( { //make a 1:1 mapping this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); vtkCellData *outputCD = output->GetCellData(); outputCD->AddArray(this->OriginalCellIds); @@ -192,7 +236,7 @@ int vtkDataSetSurfaceFilter::RequestData( { //make a 1:1 mapping this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); vtkPointData *outputPD = output->GetPointData(); outputPD->AddArray(this->OriginalPointIds); @@ -335,14 +379,14 @@ int vtkDataSetSurfaceFilter::StructuredExecute(vtkDataSet *input, if (this->PassThroughCellIds) { this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); output->GetCellData()->AddArray(this->OriginalCellIds); } if (this->PassThroughPointIds) { this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); output->GetPointData()->AddArray(this->OriginalPointIds); } @@ -894,6 +938,11 @@ void vtkDataSetSurfaceFilter::PrintSelf(ostream& os, vtkIndent indent) os << indent << "PassThroughCellIds: " << (this->PassThroughCellIds ? "On\n" : "Off\n"); os << indent << "PassThroughPointIds: " << (this->PassThroughPointIds ? "On\n" : "Off\n"); + os << indent << "OriginalCellIdsName: " << this->GetOriginalCellIdsName() << endl; + os << indent << "OriginalPointIdsName: " << this->GetOriginalPointIdsName() << endl; + + os << indent << "NonlinearSubdivisionLevel: " + << this->NonlinearSubdivisionLevel << endl; } //======================================================================== @@ -927,7 +976,6 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, vtkCellData *cd = input->GetCellData(); vtkPointData *outputPD = output->GetPointData(); vtkCellData *outputCD = output->GetCellData(); - vtkIdType outPts[6]; vtkFastGeomQuad *q; unsigned char* cellTypes = input->GetCellTypesArray()->GetPointer(0); @@ -936,9 +984,19 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, vtkPoints *coords; vtkCell *face; int flag2D = 0; + + // These are for subdividing quadratic cells + vtkDoubleArray *parametricCoords; + vtkDoubleArray *parametricCoords2; + vtkIdList *outPts; + vtkIdList *outPts2; pts = vtkIdList::New(); coords = vtkPoints::New(); + parametricCoords = vtkDoubleArray::New(); + parametricCoords2 = vtkDoubleArray::New(); + outPts = vtkIdList::New(); + outPts2 = vtkIdList::New(); // might not be necessary to set the data type for coords // but certainly safer to do so coords->SetDataType(input->GetPoints()->GetData()->GetDataType()); @@ -957,21 +1015,28 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, newVerts = vtkCellArray::New(); newLines = vtkCellArray::New(); - outputPD->CopyGlobalIdsOn(); - outputPD->CopyAllocate(inputPD, numPts, numPts/2); + if (this->NonlinearSubdivisionLevel <= 1) + { + outputPD->CopyGlobalIdsOn(); + outputPD->CopyAllocate(inputPD, numPts, numPts/2); + } + else + { + outputPD->InterpolateAllocate(inputPD, numPts, numPts/2); + } outputCD->CopyGlobalIdsOn(); outputCD->CopyAllocate(inputCD, numCells, numCells/2); if (this->PassThroughCellIds) { this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); } if (this->PassThroughPointIds) { this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); } @@ -1180,14 +1245,40 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, if ( cellIds->GetNumberOfIds() <= 0) { // FIXME: Face could not be consistent. vtkOrderedTriangulator is a better option - face->Triangulate(0,pts,coords); - for (i=0; i < pts->GetNumberOfIds(); i+=3) + if (this->NonlinearSubdivisionLevel >= 1) { - this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1), - pts->GetId(i+2), cellId); + // TODO: Handle NonlinearSubdivisionLevel > 1 correctly. + face->Triangulate(0,pts,coords); + for (i=0; i < pts->GetNumberOfIds(); i+=3) + { + this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1), + pts->GetId(i+2), cellId); + } } - } - } + else + { + switch (face->GetCellType()) + { + case VTK_QUADRATIC_TRIANGLE: + this->InsertTriInHash(face->PointIds->GetId(0), + face->PointIds->GetId(1), + face->PointIds->GetId(2), cellId); + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + case VTK_QUADRATIC_LINEAR_QUAD: + this->InsertQuadInHash(face->PointIds->GetId(0), + face->PointIds->GetId(1), + face->PointIds->GetId(2), + face->PointIds->GetId(3), cellId); + break; + default: + vtkWarningMacro(<< "Encountered unknown nonlinear face."); + break; + } // switch cell type + } // subdivision level + } // cell has ids + } // for faces cellIds->Delete(); } //3d cell } //nonlinear cell @@ -1211,6 +1302,25 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, // Move to the next cell. cellPointer += (1 + *cellPointer); + // If we have a quadratic face and our subdivision level is zero, just treat + // it as a linear cell. This should work so long as the first points of the + // quadratic cell correspond to all those of the equivalent linear cell + // (which all the current definitions do). + if (this->NonlinearSubdivisionLevel < 1) + { + switch (cellType) + { + case VTK_QUADRATIC_TRIANGLE: + cellType = VTK_TRIANGLE; numCellPts = 3; + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + case VTK_QUADRATIC_LINEAR_QUAD: + cellType = VTK_POLYGON; numCellPts = 4; + break; + } + } + // A couple of common cases to see if things go faster. if (cellType == VTK_PIXEL) { // Do we really want to insert the 2D cells into a hash? @@ -1263,14 +1373,99 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, || cellType == VTK_BIQUADRATIC_QUAD || cellType == VTK_QUADRATIC_LINEAR_QUAD) { + // Note: we should not be here if this->NonlinearSubdivisionLevel is less + // than 1. See the check above. input->GetCell( cellId, cell ); cell->Triangulate( 0, pts, coords ); - for ( i=0; i < pts->GetNumberOfIds(); i+=3 ) + // Copy the level 1 subdivision points (which also exist in the input and + // can therefore just be copied over. Note that the output of Triangulate + // records triangles in pts where each 3 points defines a triangle. We + // will keep this invariant and also keep the same invariant in + // parametericCoords and outPts later. + outPts->Reset(); + for ( i=0; i < pts->GetNumberOfIds(); i++ ) + { + vtkIdType op; + op = this->GetOutputPointId(pts->GetId(i), input, newPts, outputPD); + outPts->InsertNextId(op); + } + // Do any further subdivision if necessary. + if (this->NonlinearSubdivisionLevel > 1) + { + // We are going to need parametric coordinates to further subdivide. + double *pc = cell->GetParametricCoords(); + parametricCoords->Reset(); + parametricCoords->SetNumberOfComponents(3); + for (i = 0; i < pts->GetNumberOfIds(); i++) + { + vtkIdType ptId = pts->GetId(i); + vtkIdType cellPtId; + for (cellPtId = 0; cell->GetPointId(cellPtId) != ptId; cellPtId++); + parametricCoords->InsertNextTupleValue(pc + 3*cellPtId); + } + // Subdivide these triangles as many more times as necessary. Remember + // that we have already done the first subdivision. + for (j = 1; j < this->NonlinearSubdivisionLevel; j++) + { + parametricCoords2->Reset(); + parametricCoords2->SetNumberOfComponents(3); + outPts2->Reset(); + // Each triangle will be split into 4 triangles. + for (i = 0; i < outPts->GetNumberOfIds(); i += 3) + { + // Hold the input point ids and parametric coordinates. First 3 + // indices are the original points. Second three are the midpoints + // in the edges (0,1), (1,2) and (2,0), respectively (see comment + // below). + vtkIdType inPts[6]; + double inParamCoords[6][3]; + int k; + for (k = 0; k < 3; k++) + { + inPts[k] = outPts->GetId(i+k); + parametricCoords->GetTupleValue(i+k, inParamCoords[k]); + } + for (k = 3; k < 6; k++) + { + int pt1 = k-3; + int pt2 = (pt1 < 2) ? (pt1 + 1) : 0; + inParamCoords[k][0] = 0.5*(inParamCoords[pt1][0] + inParamCoords[pt2][0]); + inParamCoords[k][1] = 0.5*(inParamCoords[pt1][1] + inParamCoords[pt2][1]); + inParamCoords[k][2] = 0.5*(inParamCoords[pt1][2] + inParamCoords[pt2][2]); + inPts[k] = GetInterpolatedPointId(inPts[pt1], inPts[pt2], + input, cell, + inParamCoords[k], newPts, + outputPD); + } + // * 0 + // / \ Use the 6 points recorded + // / \ in inPts and inParamCoords + // 3 *-----* 5 to create the 4 triangles + // / \ / \ shown here. + // / \ / \ . + // *-----*-----* + // 1 4 2 + const int subtriangles[12] = {0,3,5, 3,1,4, 3,4,5, 5,4,2}; + for (k = 0; k < 12; k++) + { + int localId = subtriangles[k]; + outPts2->InsertNextId(inPts[localId]); + parametricCoords2->InsertNextTupleValue(inParamCoords[localId]); + } + } // Iterate over triangles + // Now that we have recorded the subdivided triangles in outPts2 and + // parametricCoords2, swap them with outPts and parametricCoords to + // make them the current ones. + vtkstd::swap(outPts, outPts2); + vtkstd::swap(parametricCoords, parametricCoords2); + } // Iterate over subdivision levels + } // If further subdivision + + // Now that we have done all the subdivisions and created all of the + // points, record the triangles. + for (i = 0; i < outPts->GetNumberOfIds(); i += 3) { - outPts[0] = this->GetOutputPointId( pts->GetId(i), input, newPts, outputPD ); - outPts[1] = this->GetOutputPointId( pts->GetId(i+1), input, newPts, outputPD ); - outPts[2] = this->GetOutputPointId( pts->GetId(i+2), input, newPts, outputPD ); - newPolys->InsertNextCell( 3, outPts ); + newPolys->InsertNextCell(3, outPts->GetPointer(i)); this->RecordOrigCellId(this->NumberOfNewCells, cellId); outputCD->CopyData(cd, cellId, this->NumberOfNewCells++); } @@ -1306,6 +1501,10 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, cell->Delete(); coords->Delete(); pts->Delete(); + parametricCoords->Delete(); + parametricCoords2->Delete(); + outPts->Delete(); + outPts2->Delete(); output->SetPoints(newPts); newPts->Delete(); @@ -1367,6 +1566,7 @@ void vtkDataSetSurfaceFilter::InitializeQuadHash(vtkIdType numPoints) this->QuadHash[i] = NULL; this->PointMap[i] = -1; } + this->EdgeMap = new vtkEdgeInterpolationMap; } //---------------------------------------------------------------------------- @@ -1386,6 +1586,8 @@ void vtkDataSetSurfaceFilter::DeleteQuadHash() this->QuadHashLength = 0; delete [] this->PointMap; this->PointMap = NULL; + delete this->EdgeMap; + this->EdgeMap = NULL; } //---------------------------------------------------------------------------- @@ -1781,6 +1983,34 @@ vtkIdType vtkDataSetSurfaceFilter::GetOutputPointId(vtkIdType inPtId, return outPtId; } +//----------------------------------------------------------------------------- +vtkIdType vtkDataSetSurfaceFilter::GetInterpolatedPointId(vtkIdType edgePtA, + vtkIdType edgePtB, + vtkDataSet *input, + vtkCell *cell, + double pcoords[3], + vtkPoints *outPts, + vtkPointData *outPD) +{ + vtkIdType outPtId; + + outPtId = this->EdgeMap->FindEdge(edgePtA, edgePtB); + if (outPtId == -1) + { + int subId = -1; + double wcoords[3]; + double weights[100]; // Any reason to need more? + cell->EvaluateLocation(subId, pcoords, wcoords, weights); + outPtId = outPts->InsertNextPoint(wcoords); + outPD->InterpolatePoint(input->GetPointData(), outPtId, + cell->GetPointIds(), weights); + this->RecordOrigPointId(outPtId, -1); + this->EdgeMap->AddEdge(edgePtA, edgePtB, outPtId); + } + + return outPtId; +} + //---------------------------------------------------------------------------- void vtkDataSetSurfaceFilter::RecordOrigCellId(vtkIdType destIndex, vtkIdType originalId) diff --git a/Graphics/vtkDataSetSurfaceFilter.h b/Graphics/vtkDataSetSurfaceFilter.h index f089c97..80a41c4 100644 --- a/Graphics/vtkDataSetSurfaceFilter.h +++ b/Graphics/vtkDataSetSurfaceFilter.h @@ -80,6 +80,34 @@ public: vtkGetMacro(PassThroughPointIds,int); vtkBooleanMacro(PassThroughPointIds,int); + // Description: + // If PassThroughCellIds or PassThroughPointIds is on, then these ivars + // control the name given to the field in which the ids are written into. If + // set to NULL, then vtkOriginalCellIds or vtkOriginalPointIds (the default) + // is used, respectively. + vtkSetStringMacro(OriginalCellIdsName); + virtual const char *GetOriginalCellIdsName() { + return ( this->OriginalCellIdsName + ? this->OriginalCellIdsName : "vtkOriginalCellIds"); + } + vtkSetStringMacro(OriginalPointIdsName); + virtual const char *GetOriginalPointIdsName() { + return ( this->OriginalPointIdsName + ? this->OriginalPointIdsName : "vtkOriginalPointIds"); + } + + // Description: + // If the input is an unstructured grid with nonlinear faces, this parameter + // determines how many times the face is subdivided into linear faces. If 0, + // the output is the equivalent of its linear couterpart (and the midpoints + // determining the nonlinear interpolation are discarded). If 1 (the + // default), the nonlinear face is triangulated based on the midpoints. If + // greater than 1, the triangulated pieces are recursively subdivided to reach + // the desired subdivision. Setting the value to greater than 1 may cause + // some point data to not be passed even if no nonlinear faces exist. This + // option has no effect if the input is not an unstructured grid. + vtkSetMacro(NonlinearSubdivisionLevel, int); + vtkGetMacro(NonlinearSubdivisionLevel, int); // Description: // Direct access methods that can be used to use the this class as an @@ -143,6 +171,14 @@ protected: vtkIdType *PointMap; vtkIdType GetOutputPointId(vtkIdType inPtId, vtkDataSet *input, vtkPoints *outPts, vtkPointData *outPD); +//BTX + class vtkEdgeInterpolationMap; +//ETX + vtkEdgeInterpolationMap *EdgeMap; + vtkIdType GetInterpolatedPointId(vtkIdType edgePtA, vtkIdType edgePtB, + vtkDataSet *input, vtkCell *cell, + double pcoords[3], vtkPoints *outPts, + vtkPointData *outPD); vtkIdType NumberOfNewCells; @@ -164,10 +200,14 @@ protected: void RecordOrigCellId(vtkIdType newIndex, vtkIdType origId); virtual void RecordOrigCellId(vtkIdType newIndex, vtkFastGeomQuad *quad); vtkIdTypeArray *OriginalCellIds; + char *OriginalCellIdsName; int PassThroughPointIds; void RecordOrigPointId(vtkIdType newIndex, vtkIdType origId); vtkIdTypeArray *OriginalPointIds; + char *OriginalPointIdsName; + + int NonlinearSubdivisionLevel; private: vtkDataSetSurfaceFilter(const vtkDataSetSurfaceFilter&); // Not implemented. diff --git a/Graphics/vtkUnstructuredGridGeometryFilter.cxx b/Graphics/vtkUnstructuredGridGeometryFilter.cxx index d6ffb0a..7065491 100644 --- a/Graphics/vtkUnstructuredGridGeometryFilter.cxx +++ b/Graphics/vtkUnstructuredGridGeometryFilter.cxx @@ -27,6 +27,7 @@ #include "vtkPolyData.h" #include "vtkPyramid.h" #include "vtkPentagonalPrism.h" +#include "vtkSmartPointer.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkStructuredGrid.h" #include "vtkTetra.h" @@ -718,6 +719,11 @@ vtkUnstructuredGridGeometryFilter::vtkUnstructuredGridGeometryFilter() this->CellClipping = 0; this->ExtentClipping = 0; + this->PassThroughCellIds = 0; + this->PassThroughPointIds = 0; + this->OriginalCellIdsName = NULL; + this->OriginalPointIdsName = NULL; + this->Merging = 1; this->Locator = NULL; @@ -732,6 +738,9 @@ vtkUnstructuredGridGeometryFilter::~vtkUnstructuredGridGeometryFilter() this->Locator->UnRegister(this); this->Locator = NULL; } + + this->SetOriginalCellIdsName(NULL); + this->SetOriginalPointIdsName(NULL); } //----------------------------------------------------------------------------- @@ -905,8 +914,24 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPts->Allocate(numPts); output->Allocate(numCells); outputPD->CopyAllocate(pd,numPts,numPts/2); + vtkSmartPointer<vtkIdTypeArray> originalPointIds; + if (this->PassThroughPointIds) + { + originalPointIds = vtkSmartPointer<vtkIdTypeArray>::New(); + originalPointIds->SetName(this->GetOriginalPointIdsName()); + originalPointIds->SetNumberOfComponents(1); + originalPointIds->Allocate(numPts, numPts/2); + } outputCD->CopyAllocate(cd,numCells,numCells/2); + vtkSmartPointer<vtkIdTypeArray> originalCellIds; + if (this->PassThroughCellIds) + { + originalCellIds = vtkSmartPointer<vtkIdTypeArray>::New(); + originalCellIds->SetName(this->GetOriginalCellIdsName()); + originalCellIds->SetNumberOfComponents(1); + originalCellIds->Allocate(numCells, numCells/2); + } vtkIdType *pointMap=0; @@ -979,6 +1004,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( if ( this->Locator->InsertUniquePoint(x, newPtId) ) { outputPD->CopyData(pd,ptId,newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(newPtId); } @@ -993,6 +1022,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPtId=newPts->InsertNextPoint(inPts->GetPoint(ptId)); pointMap[ptId]=newPtId; outputPD->CopyData(pd, ptId, newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(pointMap[ptId]); } @@ -1000,6 +1033,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newCellId = output->InsertNextCell(cellType,cellIds); outputCD->CopyData(cd, cellId, newCellId); + if (this->PassThroughCellIds) + { + originalCellIds->InsertValue(newCellId, cellId); + } } else // added the faces to the hashtable { @@ -1378,6 +1415,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( if ( this->Locator->InsertUniquePoint(x, newPtId) ) { outputPD->CopyData(pd,ptId,newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(newPtId); } @@ -1392,6 +1433,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPtId=newPts->InsertNextPoint(inPts->GetPoint(ptId)); pointMap[ptId]=newPtId; outputPD->CopyData(pd, ptId, newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(pointMap[ptId]); } @@ -1399,6 +1444,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newCellId = output->InsertNextCell(cellType,cellIds); outputCD->CopyData(cd, cellId, newCellId); + if (this->PassThroughCellIds) + { + originalCellIds->InsertValue(newCellId, cellId); + } } cursor.Next(); } @@ -1416,6 +1465,15 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPts->Delete(); // output->SetCells(types,locs,conn); + + if (this->PassThroughPointIds) + { + outputPD->AddArray(originalPointIds); + } + if (this->PassThroughCellIds) + { + outputCD->AddArray(originalCellIds); + } if(!this->Merging && this->Locator) { @@ -1491,6 +1549,12 @@ void vtkUnstructuredGridGeometryFilter::PrintSelf(ostream& os, os << indent << "CellClipping: " << (this->CellClipping ? "On\n" : "Off\n"); os << indent << "ExtentClipping: " << (this->ExtentClipping ? "On\n" : "Off\n"); + os << indent << "PassThroughCellIds: " << this->PassThroughCellIds << endl; + os << indent << "PassThroughPointIds: " << this->PassThroughPointIds << endl; + + os << indent << "OriginalCellIdsName: " << this->GetOriginalCellIdsName() << endl; + os << indent << "OriginalPointIdsName: " << this->GetOriginalPointIdsName() << endl; + os << indent << "Merging: " << (this->Merging ? "On\n" : "Off\n"); if ( this->Locator ) { diff --git a/Graphics/vtkUnstructuredGridGeometryFilter.h b/Graphics/vtkUnstructuredGridGeometryFilter.h index 66b28d8..4d73db9 100644 --- a/Graphics/vtkUnstructuredGridGeometryFilter.h +++ b/Graphics/vtkUnstructuredGridGeometryFilter.h @@ -107,6 +107,36 @@ public: vtkBooleanMacro(Merging,int); // Description: + // If on, the output polygonal dataset will have a celldata array that + // holds the cell index of the original 3D cell that produced each output + // cell. This is useful for cell picking. The default is off to conserve + // memory. Note that PassThroughCellIds will be ignored if UseStrips is on, + // since in that case each tringle strip can represent more than on of the + // input cells. + vtkSetMacro(PassThroughCellIds,int); + vtkGetMacro(PassThroughCellIds,int); + vtkBooleanMacro(PassThroughCellIds,int); + vtkSetMacro(PassThroughPointIds,int); + vtkGetMacro(PassThroughPointIds,int); + vtkBooleanMacro(PassThroughPointIds,int); + + // Description: + // If PassThroughCellIds or PassThroughPointIds is on, then these ivars + // control the name given to the field in which the ids are written into. If + // set to NULL, then vtkOriginalCellIds or vtkOriginalPointIds (the default) + // is used, respectively. + vtkSetStringMacro(OriginalCellIdsName); + virtual const char *GetOriginalCellIdsName() { + return ( this->OriginalCellIdsName + ? this->OriginalCellIdsName : "vtkOriginalCellIds"); + } + vtkSetStringMacro(OriginalPointIdsName); + virtual const char *GetOriginalPointIdsName() { + return ( this->OriginalPointIdsName + ? this->OriginalPointIdsName : "vtkOriginalPointIds"); + } + + // Description: // Set / get a spatial locator for merging points. By // default an instance of vtkMergePoints is used. void SetLocator(vtkIncrementalPointLocator *locator); @@ -138,6 +168,11 @@ protected: int CellClipping; int ExtentClipping; + int PassThroughCellIds; + int PassThroughPointIds; + char *OriginalCellIdsName; + char *OriginalPointIdsName; + int Merging; vtkIncrementalPointLocator *Locator; diff --git a/IO/vtkSLACReader.cxx b/IO/vtkSLACReader.cxx index 68ec746..4db8a03 100644 --- a/IO/vtkSLACReader.cxx +++ b/IO/vtkSLACReader.cxx @@ -1315,13 +1315,6 @@ int vtkSLACReader::ReadMidpointCoordinates( int vtkSLACReader::ReadMidpointData(int meshFD, vtkMultiBlockDataSet *output, MidpointIdMap &midpointIds) { - static bool GaveMidpointWarning = false; - if (!GaveMidpointWarning) - { - vtkWarningMacro(<< "Quadratic elements not displayed entirely correctly yet. Quadratic triangles are drawn as 4 linear triangles."); - GaveMidpointWarning = true; - } - // Get the point information from the data. vtkPoints *points = vtkPoints::SafeDownCast( output->GetInformation()->Get(vtkSLACReader::POINTS())); diff --git a/IO/vtkXMLReader.h b/IO/vtkXMLReader.h index 1a262fc..c910902 100644 --- a/IO/vtkXMLReader.h +++ b/IO/vtkXMLReader.h @@ -95,6 +95,10 @@ public: vtkGetVector2Macro(TimeStepRange, int); vtkSetVector2Macro(TimeStepRange, int); + virtual int ProcessRequest(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + protected: vtkXMLReader(); ~vtkXMLReader(); @@ -218,10 +222,7 @@ protected: virtual void SetProgressRange(float* range, int curStep, float* fractions); virtual void UpdateProgressDiscrete(float progress); float ProgressRange[2]; - - virtual int ProcessRequest(vtkInformation *request, - vtkInformationVector **inputVector, - vtkInformationVector *outputVector); + virtual int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector); diff --git a/Infovis/vtkTreeLayoutStrategy.cxx b/Infovis/vtkTreeLayoutStrategy.cxx index bc9621f..d1a0aac 100644 --- a/Infovis/vtkTreeLayoutStrategy.cxx +++ b/Infovis/vtkTreeLayoutStrategy.cxx @@ -33,6 +33,7 @@ #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkSmartPointer.h" +#include "vtkTransform.h" #include "vtkTree.h" #include "vtkTreeDFSIterator.h" @@ -46,6 +47,7 @@ vtkTreeLayoutStrategy::vtkTreeLayoutStrategy() this->LogSpacingValue = 1.0; this->LeafSpacing = 0.9; this->DistanceArrayName = NULL; + this->Rotation = 0.0; } vtkTreeLayoutStrategy::~vtkTreeLayoutStrategy() @@ -336,6 +338,21 @@ void vtkTreeLayoutStrategy::Layout() } newPoints->SetPoint(vertex, x, y, 0.0); } + + // Rotate coordinates + if (this->Rotation != 0.0) + { + vtkSmartPointer<vtkTransform> t = vtkSmartPointer<vtkTransform>::New(); + t->RotateZ(this->Rotation); + double x[3]; + double y[3]; + for (vtkIdType p = 0; p < newPoints->GetNumberOfPoints(); ++p) + { + newPoints->GetPoint(p, x); + t->MultiplyPoint(x, y); + newPoints->SetPoint(p, y); + } + } // Copy coordinates back into the original graph if (vtkTree::SafeDownCast(this->Graph)) @@ -377,7 +394,8 @@ void vtkTreeLayoutStrategy::PrintSelf(ostream& os, vtkIndent indent) os << indent << "Radial: " << (this->Radial ? "true" : "false") << endl; os << indent << "LogSpacingValue: " << this->LogSpacingValue << endl; os << indent << "LeafSpacing: " << this->LeafSpacing << endl; - os << indent << "DistanceArrayName: " + os << indent << "Rotation: " << this->Rotation << endl; + os << indent << "DistanceArrayName: " << (this->DistanceArrayName ? this->DistanceArrayName : "(null)") << endl; } diff --git a/Infovis/vtkTreeLayoutStrategy.h b/Infovis/vtkTreeLayoutStrategy.h index fb98dcc..2c3a437 100644 --- a/Infovis/vtkTreeLayoutStrategy.h +++ b/Infovis/vtkTreeLayoutStrategy.h @@ -87,6 +87,12 @@ public: vtkSetStringMacro(DistanceArrayName); vtkGetStringMacro(DistanceArrayName); + // Description: + // The amount of counter-clockwise rotation to apply after the + // layout. + vtkSetMacro(Rotation, double); + vtkGetMacro(Rotation, double); + protected: vtkTreeLayoutStrategy(); ~vtkTreeLayoutStrategy(); @@ -96,6 +102,7 @@ protected: double LogSpacingValue; double LeafSpacing; char *DistanceArrayName; + double Rotation; private: diff --git a/Rendering/vtkChooserPainter.cxx b/Rendering/vtkChooserPainter.cxx index a215b0f..11bcbe2 100644 --- a/Rendering/vtkChooserPainter.cxx +++ b/Rendering/vtkChooserPainter.cxx @@ -20,6 +20,7 @@ #include "vtkInformation.h" #include "vtkLinesPainter.h" #include "vtkObjectFactory.h" +#include "vtkPointData.h" #include "vtkPointsPainter.h" #include "vtkPolyData.h" #include "vtkPolygonsPainter.h" @@ -338,7 +339,9 @@ void vtkChooserPainter::RenderInternal(vtkRenderer* renderer, vtkActor* actor, if ( this->UseLinesPainterForWireframes && (actor->GetProperty()->GetRepresentation() == VTK_WIREFRAME) && !actor->GetProperty()->GetBackfaceCulling() - && !actor->GetProperty()->GetFrontfaceCulling() ) + && !actor->GetProperty()->GetFrontfaceCulling() + && !this->GetInputAsPolyData()->GetPointData()->GetAttribute( + vtkDataSetAttributes::EDGEFLAG) ) { this->LinePainter->Render(renderer, actor, vtkPainter::POLYS, forceCompileOnly); diff --git a/Rendering/vtkLinesPainter.cxx b/Rendering/vtkLinesPainter.cxx index ca9fc8a..877e075 100644 --- a/Rendering/vtkLinesPainter.cxx +++ b/Rendering/vtkLinesPainter.cxx @@ -131,6 +131,9 @@ int vtkLinesPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, // we just ignore the flag. idx &= (~VTK_PDM_FIELD_COLORS); + // Also ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + // draw all the elements, use fast path if available switch (idx) { diff --git a/Rendering/vtkOpenGLPainterDeviceAdapter.cxx b/Rendering/vtkOpenGLPainterDeviceAdapter.cxx index 0c0eb91..9328a3c 100644 --- a/Rendering/vtkOpenGLPainterDeviceAdapter.cxx +++ b/Rendering/vtkOpenGLPainterDeviceAdapter.cxx @@ -259,6 +259,7 @@ int vtkOpenGLPainterDeviceAdapter::IsAttributesSupported(int attribute) case vtkDataSetAttributes::NORMALS: case vtkDataSetAttributes::SCALARS: case vtkDataSetAttributes::TCOORDS: + case vtkDataSetAttributes::EDGEFLAG: return 1; } return 0; @@ -534,6 +535,18 @@ void vtkOpenGLPainterDeviceAdapter::SendAttribute(int index, int numcomp, return; } break; + case vtkDataSetAttributes::EDGEFLAG: // Edge Flag + if (numcomp != 1) + { + vtkErrorMacro("Bad number of components."); + return; + } + switch (type) + { + vtkTemplateMacro(glEdgeFlag(static_cast<GLboolean>( + reinterpret_cast<const VTK_TT*>(attribute)[offset]))); + } + break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -715,6 +728,33 @@ void vtkOpenGLPainterDeviceAdapter::SetAttributePointer(int index, } glTexCoordPointer(numcomponents, gltype, stride, pointer); break; + case vtkDataSetAttributes::EDGEFLAG: // Edge flag + if (numcomponents != 1) + { + vtkErrorMacro("Edge flag must have one component."); + return; + } + // Flag must be conformant to GLboolean + if ((type == VTK_FLOAT) || (type == GL_DOUBLE)) + { + vtkErrorMacro("Unsupported type for edge flag: " << type); + return; + } + // Thus is an unfriendly way to force the array to be conformant to + // a GLboolean array. At the very least there should be some indication + // in VTK outside of OpenGL to determine which VTK type to use. + switch (type) + { + vtkTemplateMacro(if (sizeof(VTK_TT) != sizeof(GLboolean)) + { + vtkErrorMacro(<< "Unsupported tyep for edge flag: " + << type); + return; + } + ); + } + glEdgeFlagPointer(stride, pointer); + break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -735,6 +775,8 @@ void vtkOpenGLPainterDeviceAdapter::EnableAttributeArray(int index) glEnableClientState(GL_COLOR_ARRAY); break; case vtkDataSetAttributes::TCOORDS: glEnableClientState(GL_TEXTURE_COORD_ARRAY); break; + case vtkDataSetAttributes::EDGEFLAG: + glEnableClientState(GL_EDGE_FLAG_ARRAY); break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -753,6 +795,8 @@ void vtkOpenGLPainterDeviceAdapter::DisableAttributeArray(int index) glDisableClientState(GL_COLOR_ARRAY); break; case vtkDataSetAttributes::TCOORDS: glDisableClientState(GL_TEXTURE_COORD_ARRAY); break; + case vtkDataSetAttributes::EDGEFLAG: + glDisableClientState(GL_EDGE_FLAG_ARRAY); break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; diff --git a/Rendering/vtkPointsPainter.cxx b/Rendering/vtkPointsPainter.cxx index 97d1613..ce64eb6 100644 --- a/Rendering/vtkPointsPainter.cxx +++ b/Rendering/vtkPointsPainter.cxx @@ -107,6 +107,10 @@ int vtkPointsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, // since this painter does not deal with field colors specially, // we just ignore the flag. idx &= (~VTK_PDM_FIELD_COLORS); + + // Also ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + switch (idx) { case 0://no cell/point attribs are present. diff --git a/Rendering/vtkPolygonsPainter.cxx b/Rendering/vtkPolygonsPainter.cxx index 62ed003..3f02deb 100644 --- a/Rendering/vtkPolygonsPainter.cxx +++ b/Rendering/vtkPolygonsPainter.cxx @@ -181,6 +181,8 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, pd->GetLines()->GetNumberOfCells(); vtkIdType cellNumStart = cellNum; vtkIdType totalCells = ca->GetNumberOfCells(); + vtkUnsignedCharArray *ef = vtkUnsignedCharArray::SafeDownCast( + pd->GetPointData()->GetAttribute(vtkDataSetAttributes::EDGEFLAG)); vtkPainterDeviceAdapter* device = ren->GetRenderWindow()-> GetPainterDeviceAdapter(); @@ -188,6 +190,7 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, void *normals = 0; void *tcoords = 0; unsigned char *colors = 0; + unsigned char *edgeflags = 0; int primitive = VTK_POLYGON; if (ca->GetNumberOfCells() == 0) @@ -211,12 +214,17 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, { tcoords = t->GetVoidPointer(0); } + if (ef) + { + edgeflags = ef->GetPointer(0); + } vtkIdType *ptIds = ca->GetPointer(); vtkIdType *endPtIds = ptIds + ca->GetNumberOfConnectivityEntries(); int ptype = p->GetDataType(); int ntype = (n)? n->GetDataType() : 0; int ttype = (t)? t->GetDataType() : 0; int tcomps = (t)? t->GetNumberOfComponents() : 0; + int eftype = (ef)? ef->GetDataType() : 0; int celloffset = 0; // since this painter does not deal with field colors specially, @@ -412,9 +420,266 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, VTK_UNSIGNED_CHAR, colors); colors += 4;, celloffset = cellNum;); break; + + case VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, ;,;); + } + break; + + case VTK_PDM_NORMALS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + + case VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, 1, + ttype, tcoords, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, colors); + colors += 4;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, colors); + colors += 4;,;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++; + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, colors); + colors += 4;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++; + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, colors); + colors += 4;, + celloffset = cellNum;); + break; + default: return 0; // let the delegate painter handle it. } + + if (idx & VTK_PDM_EDGEFLAGS) + { + // Reset the edge flag to 1 so that if the next thing rendered does not + // have an edge flag, it will have all edges on. + unsigned char edgeflag = 1; + device->SendAttribute(vtkPointData::EDGEFLAG, 1, VTK_UNSIGNED_CHAR, + &edgeflag, 0); + } + return 1; } diff --git a/Rendering/vtkPrimitivePainter.cxx b/Rendering/vtkPrimitivePainter.cxx index df859e9..d6253cd 100644 --- a/Rendering/vtkPrimitivePainter.cxx +++ b/Rendering/vtkPrimitivePainter.cxx @@ -159,6 +159,7 @@ void vtkPrimitivePainter::RenderInternal(vtkRenderer* renderer, vtkUnsignedCharArray *c=NULL; vtkDataArray *n; vtkDataArray *t; + vtkDataArray *ef; int tDim; vtkPolyData *input = this->GetInputAsPolyData(); int cellNormals; @@ -269,6 +270,28 @@ void vtkPrimitivePainter::RenderInternal(vtkRenderer* renderer, idx |= VTK_PDM_TCOORDS; } + // Edge flag + ef = input->GetPointData()->GetAttribute(vtkDataSetAttributes::EDGEFLAG); + if (ef) + { + if (ef->GetNumberOfComponents() != 1) + { + vtkDebugMacro(<< "Currently only 1d edge flags are supported."); + ef = NULL; + } + if (!ef->IsA("vtkUnsignedCharArray")) + { + vtkDebugMacro(<< "Currently only unsigned char edge flags are suported."); + ef = NULL; + } + } + + // Set the flags + if (ef) + { + idx |= VTK_PDM_EDGEFLAGS; + } + if (!act) { vtkErrorMacro("No actor"); diff --git a/Rendering/vtkPrimitivePainter.h b/Rendering/vtkPrimitivePainter.h index 100cc22..2ca46a7 100644 --- a/Rendering/vtkPrimitivePainter.h +++ b/Rendering/vtkPrimitivePainter.h @@ -49,14 +49,15 @@ protected: //BTX enum { - VTK_PDM_NORMALS = 0x01, - VTK_PDM_COLORS = 0x02, - VTK_PDM_TCOORDS = 0x04, - VTK_PDM_CELL_COLORS = 0x08, - VTK_PDM_CELL_NORMALS = 0x10, - VTK_PDM_OPAQUE_COLORS = 0x20, - VTK_PDM_FIELD_COLORS = 0x40, - VTK_PDM_GENERIC_VERTEX_ATTRIBUTES =0x80 + VTK_PDM_NORMALS = 0x001, + VTK_PDM_COLORS = 0x002, + VTK_PDM_TCOORDS = 0x004, + VTK_PDM_CELL_COLORS = 0x008, + VTK_PDM_CELL_NORMALS = 0x010, + VTK_PDM_OPAQUE_COLORS = 0x020, + VTK_PDM_FIELD_COLORS = 0x040, + VTK_PDM_EDGEFLAGS = 0x080, + VTK_PDM_GENERIC_VERTEX_ATTRIBUTES = 0x100 }; //ETX diff --git a/Rendering/vtkTStripsPainter.cxx b/Rendering/vtkTStripsPainter.cxx index 101070f..f326981 100644 --- a/Rendering/vtkTStripsPainter.cxx +++ b/Rendering/vtkTStripsPainter.cxx @@ -189,6 +189,9 @@ int vtkTStripsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, int ttype = (t)? t->GetDataType() : 0; int tcomps = (t)? t->GetNumberOfComponents() : 0; + // Ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + // draw all the elements, use fast path if available switch (idx) { diff --git a/Utilities/kwsys/ProcessUNIX.c b/Utilities/kwsys/ProcessUNIX.c index 57f7b16..b368901 100644 --- a/Utilities/kwsys/ProcessUNIX.c +++ b/Utilities/kwsys/ProcessUNIX.c @@ -2374,7 +2374,7 @@ static pid_t kwsysProcessFork(kwsysProcess* cp, corresponding parsing format string. The parsing format should have two integers to store: the pid and then the ppid. */ #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) \ - || defined(__FreeBSD_kernel__) + || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) # define KWSYSPE_PS_COMMAND "ps axo pid,ppid" # define KWSYSPE_PS_FORMAT "%d %d\n" #elif defined(__hpux) || defined(__sun__) || defined(__sgi) || defined(_AIX) \ diff --git a/Utilities/kwsys/SharedForward.h.in b/Utilities/kwsys/SharedForward.h.in index da62d84..8521099 100644 --- a/Utilities/kwsys/SharedForward.h.in +++ b/Utilities/kwsys/SharedForward.h.in @@ -201,6 +201,12 @@ static const char kwsys_shared_forward_path_slash[2] = {KWSYS_SHARED_FORWARD_PAT # define KWSYS_SHARED_FORWARD_LDD_N 1 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +/* OpenBSD */ +#elif defined(__OpenBSD__) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" + /* OSX */ #elif defined(__APPLE__) # define KWSYS_SHARED_FORWARD_LDD "otool", "-L" diff --git a/Utilities/kwsys/kwsysDateStamp.cmake b/Utilities/kwsys/kwsysDateStamp.cmake index 9a5e9e9..9ccf63d 100644 --- a/Utilities/kwsys/kwsysDateStamp.cmake +++ b/Utilities/kwsys/kwsysDateStamp.cmake @@ -18,4 +18,4 @@ SET(KWSYS_DATE_STAMP_YEAR 2010) SET(KWSYS_DATE_STAMP_MONTH 04) # KWSys version date day component. Format is DD. -SET(KWSYS_DATE_STAMP_DAY 19) +SET(KWSYS_DATE_STAMP_DAY 21) ![]() diff --git a/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui b/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui index 1d0bf2c..2f7c5c7 100644 --- a/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui +++ b/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui @@ -581,13 +581,43 @@ </spacer> </item> <item row="7" column="0"> - <widget class="QLabel" name="label_19"> + <widget class="QLabel" name="label_17"> <property name="text"> + <string>Subdivision</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QSpinBox" name="NonlinearSubdivisionLevel"> + <property name="toolTip"> + <string>Nonlinear faces are approximated with flat polygons. This parameter controls how many times to subdivide nonlinear surface cells. Higher subdivisions generate closer approximations but take more memory and rendering time. Subdivision is recursive, so the number of output polygons can grow exponentially with this parameter.</string> + </property> + <property name="maximum"> + <number>4</number> + </property> + </widget> + </item> + <item row="7" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="8" column="0" > + <widget class="QLabel" name="label_19" > + <property name="text" > <string>Volume mapper</string> </property> </widget> </item> - <item row="7" column="1" colspan="2"> + <item row="8" column="1" colspan="2"> <widget class="QComboBox" name="SelectedMapperIndex"> <property name="toolTip"> <string><html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:Sans Serif; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Choose the mapper to use for volume rendering.</p></body></html></string> @@ -1123,6 +1153,7 @@ <tabstop>StylePointSize</tabstop> <tabstop>StyleLineWidth</tabstop> <tabstop>Opacity</tabstop> + <tabstop>NonlinearSubdivisionLevel</tabstop> <tabstop>SelectedMapperIndex</tabstop> <tabstop>EdgeColor</tabstop> <tabstop>SpecularIntensity</tabstop> diff --git a/Qt/Components/pqDisplayProxyEditor.cxx b/Qt/Components/pqDisplayProxyEditor.cxx index 64cfa25..bc3f83b 100644 --- a/Qt/Components/pqDisplayProxyEditor.cxx +++ b/Qt/Components/pqDisplayProxyEditor.cxx @@ -390,6 +390,15 @@ void pqDisplayProxyEditor::setRepresentation(pqPipelineRepresentation* repr) "value", SIGNAL(editingFinished()), reprProxy, reprProxy->GetProperty("Opacity")); + // setup of nonlinear subdivision + if (reprProxy->GetProperty("NonlinearSubdivisionLevel")) + { + this->Internal->Links->addPropertyLink( + this->Internal->NonlinearSubdivisionLevel, + "value", SIGNAL(valueChanged(int)), + reprProxy, reprProxy->GetProperty("NonlinearSubdivisionLevel")); + } + // setup for map scalars this->Internal->Links->addPropertyLink( this->Internal->ColorMapScalars, "checked", SIGNAL(stateChanged(int)), diff --git a/Servers/Filters/CMakeLists.txt b/Servers/Filters/CMakeLists.txt index 13cd94f..2adaebd 100644 --- a/Servers/Filters/CMakeLists.txt +++ b/Servers/Filters/CMakeLists.txt @@ -129,6 +129,7 @@ SET(Filters_SRCS vtkPVMain.cxx vtkPVMergeTables.cxx vtkPVNullSource.cxx + vtkPVRecoverGeometryWireframe.cxx vtkPVRenderViewProxy.cxx vtkPVScalarBarActor.cxx vtkPVSelectionSource.cxx diff --git a/Servers/Filters/vtkPVGeometryFilter.cxx b/Servers/Filters/vtkPVGeometryFilter.cxx index 13a956f..47d7333 100644 --- a/Servers/Filters/vtkPVGeometryFilter.cxx +++ b/Servers/Filters/vtkPVGeometryFilter.cxx @@ -14,10 +14,12 @@ =========================================================================*/ #include "vtkPVGeometryFilter.h" +#include "vtkAlgorithmOutput.h" #include "vtkAppendPolyData.h" #include "vtkCallbackCommand.h" #include "vtkCellArray.h" #include "vtkCellData.h" +#include "vtkCellTypes.h" #include "vtkCleanArrays.h" #include "vtkCommand.h" #include "vtkCompositeDataIterator.h" @@ -42,6 +44,7 @@ #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkPolygon.h" +#include "vtkPVRecoverGeometryWireframe.h" #include "vtkRectilinearGrid.h" #include "vtkRectilinearGridOutlineFilter.h" #include "vtkSmartPointer.h" @@ -52,14 +55,17 @@ #include "vtkTimerLog.h" #include "vtkUnsignedCharArray.h" #include "vtkUnsignedIntArray.h" -#include "vtkAlgorithmOutput.h" #include "vtkUnstructuredGrid.h" +#include "vtkUnstructuredGridGeometryFilter.h" #include <vtkstd/map> #include <vtkstd/vector> #include <vtkstd/string> #include <assert.h> +#define VTK_CREATE(type, name) \ + vtkSmartPointer<type> name = vtkSmartPointer<type>::New() + vtkCxxRevisionMacro(vtkPVGeometryFilter, "1.105"); vtkStandardNewMacro(vtkPVGeometryFilter); @@ -131,10 +137,13 @@ vtkPVGeometryFilter::vtkPVGeometryFilter () this->UseOutline = 1; this->UseStrips = 0; this->GenerateCellNormals = 1; + this->NonlinearSubdivisionLevel = 1; this->DataSetSurfaceFilter = vtkDataSetSurfaceFilter::New(); this->GenericGeometryFilter=vtkGenericGeometryFilter::New(); - + this->UnstructuredGridGeometryFilter=vtkUnstructuredGridGeometryFilter::New(); + this->RecoverWireframeFilter = vtkPVRecoverGeometryWireframe::New(); + // Setup a callback for the internal readers to report progress. this->InternalProgressObserver = vtkCallbackCommand::New(); this->InternalProgressObserver->SetCallback( @@ -162,13 +171,31 @@ vtkPVGeometryFilter::vtkPVGeometryFilter () //---------------------------------------------------------------------------- vtkPVGeometryFilter::~vtkPVGeometryFilter () { - if(this->DataSetSurfaceFilter) + // Be careful how you delete these so that you don't foul up the garbage + // collector. + if (this->DataSetSurfaceFilter) { - this->DataSetSurfaceFilter->Delete(); + vtkDataSetSurfaceFilter *tmp = this->DataSetSurfaceFilter; + this->DataSetSurfaceFilter = NULL; + tmp->Delete(); } - if(this->GenericGeometryFilter!=0) + if (this->GenericGeometryFilter) { - this->GenericGeometryFilter->Delete(); + vtkGenericGeometryFilter *tmp = this->GenericGeometryFilter; + this->GenericGeometryFilter = NULL; + tmp->Delete(); + } + if (this->UnstructuredGridGeometryFilter) + { + vtkUnstructuredGridGeometryFilter *tmp=this->UnstructuredGridGeometryFilter; + this->UnstructuredGridGeometryFilter = NULL; + tmp->Delete(); + } + if (this->RecoverWireframeFilter) + { + vtkPVRecoverGeometryWireframe *tmp = this->RecoverWireframeFilter; + this->RecoverWireframeFilter = NULL; + tmp->Delete(); } this->OutlineSource->Delete(); this->InternalProgressObserver->Delete(); @@ -1067,10 +1094,160 @@ void vtkPVGeometryFilter::UnstructuredGridExecute( if (!this->UseOutline) { this->OutlineFlag = 0; + + bool handleSubdivision = false; + if (this->NonlinearSubdivisionLevel > 0) + { + // Check to see if the data actually has nonlinear cells. Handling + // nonlinear cells adds unnecessary work if we only have linear cells. + vtkUnsignedCharArray *types = input->GetCellTypesArray(); + vtkIdType numCells = input->GetNumberOfCells(); + for (vtkIdType i = 0; i < numCells; i++) + { + if (!vtkCellTypes::IsLinear(types->GetValue(i))) + { + handleSubdivision = true; + break; + } + } + } + + vtkSmartPointer<vtkIdTypeArray> facePtIds2OriginalPtIds; + + if (handleSubdivision) + { + // Use the vtkUnstructuredGridGeometryFilter to extract 2D surface cells + // from the geometry. This is important to extract an appropriate + // wireframe in vtkPVRecoverGeometryWireframe. Also, at the time of this + // writing vtkDataSetSurfaceFilter only properly subdivides 2D cells past + // level 1. + VTK_CREATE(vtkUnstructuredGrid, inputClone); + inputClone->ShallowCopy(input); + this->UnstructuredGridGeometryFilter->SetInput(inputClone); + + // Let the vtkUnstructuredGridGeometryFilter record from which point and + // cell each face comes from in the standard vtkOriginalCellIds array. + this->UnstructuredGridGeometryFilter->SetPassThroughCellIds( + this->PassThroughCellIds); + this->UnstructuredGridGeometryFilter->SetPassThroughPointIds( + this->PassThroughPointIds); + + // Observe the progress of the internal filter. + // TODO: Make the consecutive internal filter execution have monotonically + // increasing progress rather than restarting for every internal filter. + this->UnstructuredGridGeometryFilter->AddObserver( + vtkCommand::ProgressEvent, + this->InternalProgressObserver); + this->UnstructuredGridGeometryFilter->Update(); + // The internal filter finished. Remove the observer. + this->UnstructuredGridGeometryFilter->RemoveObserver( + this->InternalProgressObserver); + + this->UnstructuredGridGeometryFilter->SetInput(NULL); + + // Feed the extracted surface as the input to the rest of the processing. + input->ShallowCopy(this->UnstructuredGridGeometryFilter->GetOutput()); + + // Keep a handle to the vtkOriginalPointIds array. We might need it. + facePtIds2OriginalPtIds = vtkIdTypeArray::SafeDownCast( + input->GetPointData()->GetArray("vtkOriginalPointIds")); + + // Flag the data set surface filter to record original cell ids, but do it + // in a specially named array that vtkPVRecoverGeometryWireframe will + // recognize. Note that because the data set comes from + // UnstructuredGridGeometryFilter, the ids will represent the faces rather + // than the original cells, which is important. + this->DataSetSurfaceFilter->PassThroughCellIdsOn(); + this->DataSetSurfaceFilter->SetOriginalCellIdsName( + vtkPVRecoverGeometryWireframe::ORIGINAL_FACE_IDS()); + + if (this->PassThroughPointIds) + { + if (this->NonlinearSubdivisionLevel <= 1) + { + // Do not allow the vtkDataSetSurfaceFilter create an array of + // original cell ids; it will overwrite the correct array from the + // vtkUnstructuredGridGeometryFilter. + this->DataSetSurfaceFilter->PassThroughPointIdsOff(); + } + else + { + // vtkDataSetSurfaceFilter is going to strip the vtkOriginalPointIds + // created by the vtkPVUnstructuredGridGeometryFilter because it + // cannot interpolate the ids. Make the vtkDataSetSurfaceFilter make + // its own original ids array. We will resolve them later. + this->DataSetSurfaceFilter->PassThroughPointIdsOn(); + } + } + } + if (input->GetNumberOfCells() > 0) { this->DataSetSurfaceFilter->UnstructuredGridExecute(input, output); } + + if (handleSubdivision) + { + // Restore state of DataSetSurfaceFilter. + this->DataSetSurfaceFilter->SetPassThroughCellIds( + this->PassThroughCellIds); + this->DataSetSurfaceFilter->SetOriginalCellIdsName(NULL); + this->DataSetSurfaceFilter->SetPassThroughPointIds( + this->PassThroughPointIds); + + // Now use vtkPVRecoverGeometryWireframe to create an edge flag attribute + // that will cause the wireframe to be rendered correctly. + VTK_CREATE(vtkPolyData, nextStageInput); + nextStageInput->ShallowCopy(output); // Yes output is correct. + this->RecoverWireframeFilter->SetInput(nextStageInput); + + // Observe the progress of the internal filter. + // TODO: Make the consecutive internal filter execution have monotonically + // increasing progress rather than restarting for every internal filter. + this->RecoverWireframeFilter->AddObserver( + vtkCommand::ProgressEvent, + this->InternalProgressObserver); + this->RecoverWireframeFilter->Update(); + // The internal filter finished. Remove the observer. + this->RecoverWireframeFilter->RemoveObserver( + this->InternalProgressObserver); + + this->RecoverWireframeFilter->SetInput(NULL); + + // Get what should be the final output. + output->ShallowCopy(this->RecoverWireframeFilter->GetOutput()); + + if (this->PassThroughPointIds && (this->NonlinearSubdivisionLevel > 1)) + { + // The output currently has a vtkOriginalPointIds array that maps points + // to the data containing only the faces. Correct this to point to the + // original data set. + vtkIdTypeArray *polyPtIds2FacePtIds = vtkIdTypeArray::SafeDownCast( + output->GetPointData()->GetArray("vtkOriginalPointIds")); + if (!facePtIds2OriginalPtIds || !polyPtIds2FacePtIds) + { + vtkErrorMacro(<< "Missing original point id arrays."); + return; + } + vtkIdType numPts = polyPtIds2FacePtIds->GetNumberOfTuples(); + VTK_CREATE(vtkIdTypeArray, polyPtIds2OriginalPtIds); + polyPtIds2OriginalPtIds->SetName("vtkOriginalPointIds"); + polyPtIds2OriginalPtIds->SetNumberOfComponents(1); + polyPtIds2OriginalPtIds->SetNumberOfTuples(numPts); + for (vtkIdType polyPtId = 0; polyPtId < numPts; polyPtId++) + { + vtkIdType facePtId = polyPtIds2FacePtIds->GetValue(polyPtId); + vtkIdType originalPtId = -1; + if (facePtId >= 0) + { + originalPtId = facePtIds2OriginalPtIds->GetValue(facePtId); + } + polyPtIds2OriginalPtIds->SetValue(polyPtId, originalPtId); + } + output->GetPointData()->AddArray(polyPtIds2OriginalPtIds); + } + } + return; } @@ -1193,6 +1370,10 @@ void vtkPVGeometryFilter::ReportReferences(vtkGarbageCollector* collector) "DataSetSurfaceFilter"); vtkGarbageCollectorReport(collector, this->GenericGeometryFilter, "GenericGeometryFilter"); + vtkGarbageCollectorReport(collector, this->UnstructuredGridGeometryFilter, + "UnstructuredGridGeometryFilter"); + vtkGarbageCollectorReport(collector, this->RecoverWireframeFilter, + "RecoverWireframeFilter"); } //---------------------------------------------------------------------------- @@ -1213,6 +1394,8 @@ void vtkPVGeometryFilter::PrintSelf(ostream& os, vtkIndent indent) os << indent << "UseStrips: " << (this->UseStrips?"on":"off") << endl; os << indent << "GenerateCellNormals: " << (this->GenerateCellNormals?"on":"off") << endl; + os << indent << "NonlinearSubdivisionLevel: " + << this->NonlinearSubdivisionLevel << endl; os << indent << "Controller: " << this->Controller << endl; os << indent << "PassThroughCellIds: " @@ -1306,3 +1489,20 @@ void vtkPVGeometryFilter::RemoveGhostCells(vtkPolyData* output) output->RemoveGhostCells(1); } } + +//----------------------------------------------------------------------------- +void vtkPVGeometryFilter::SetNonlinearSubdivisionLevel(int newvalue) +{ + if (this->NonlinearSubdivisionLevel != newvalue) + { + this->NonlinearSubdivisionLevel = newvalue; + + if (this->DataSetSurfaceFilter) + { + this->DataSetSurfaceFilter->SetNonlinearSubdivisionLevel( + this->NonlinearSubdivisionLevel); + } + + this->Modified(); + } +} diff --git a/Servers/Filters/vtkPVGeometryFilter.h b/Servers/Filters/vtkPVGeometryFilter.h index f9e4485..9fb7be2 100644 --- a/Servers/Filters/vtkPVGeometryFilter.h +++ b/Servers/Filters/vtkPVGeometryFilter.h @@ -34,9 +34,11 @@ class vtkInformationVector; class vtkCompositeDataSet; class vtkMultiProcessController; class vtkOutlineSource; +class vtkPVRecoverGeometryWireframe; class vtkRectilinearGrid; class vtkStructuredGrid; class vtkUnstructuredGrid; +class vtkUnstructuredGridGeometryFilter; class VTK_EXPORT vtkPVGeometryFilter : public vtkPolyDataAlgorithm { @@ -79,6 +81,15 @@ public: vtkBooleanMacro(GenerateCellNormals, int); // Description: + // Nonlinear faces are approximated with flat polygons. This parameter + // controls how many times to subdivide nonlinear surface cells. Higher + // subdivisions generate closer approximations but take more memory and + // rendering time. Subdivision is recursive, so the number of output polygons + // can grow exponentially with this parameter. + virtual void SetNonlinearSubdivisionLevel(int); + vtkGetMacro(NonlinearSubdivisionLevel, int); + + // Description: // Set and get the controller. virtual void SetController(vtkMultiProcessController*); vtkGetObjectMacro(Controller, vtkMultiProcessController); @@ -159,11 +170,14 @@ protected: int UseOutline; int UseStrips; int GenerateCellNormals; + int NonlinearSubdivisionLevel; vtkMultiProcessController* Controller; vtkOutlineSource *OutlineSource; vtkDataSetSurfaceFilter* DataSetSurfaceFilter; vtkGenericGeometryFilter *GenericGeometryFilter; + vtkUnstructuredGridGeometryFilter *UnstructuredGridGeometryFilter; + vtkPVRecoverGeometryWireframe *RecoverWireframeFilter; int CheckAttributes(vtkDataObject* input); diff --git a/Servers/Filters/vtkPVRecoverGeometryWireframe.cxx b/Servers/Filters/vtkPVRecoverGeometryWireframe.cxx new file mode 100644 index 0000000..acc35f3 --- /dev/null +++ b/Servers/Filters/vtkPVRecoverGeometryWireframe.cxx @@ -0,0 +1,308 @@ +// -*- c++ -*- +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: pqBlotDialog.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*------------------------------------------------------------------------- + Copyright 2009 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, + the U.S. Government retains certain rights in this software. +-------------------------------------------------------------------------*/ + +#include "vtkPVRecoverGeometryWireframe.h" + +#include "vtkCellArray.h" +#include "vtkCellData.h" +#include "vtkIdTypeArray.h" +#include "vtkObjectFactory.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" +#include "vtkUnsignedCharArray.h" + +#include "vtkSmartPointer.h" +#define VTK_CREATE(type, name) \ + vtkSmartPointer<type> name = vtkSmartPointer<type>::New() + +#include <vtkstd/algorithm> +#include <vtkstd/vector> +#include <vtksys/hash_map.hxx> + +static const unsigned char NO_EDGE_FLAG = static_cast<unsigned char >(-1); + +//============================================================================= +namespace vtkPVRecoverGeometryWireframeNamespace +{ + // Description: + // Simple class used internally to define an edge based on the endpoints. The + // endpoints are canonically identified by the lower and higher values. + class EdgeEndpoints + { + public: + EdgeEndpoints() : MinEndPoint(-1), MaxEndPoint(-1) {} + EdgeEndpoints(vtkIdType endpointA, vtkIdType endpointB) + : MinEndPoint((endpointA < endpointB) ? endpointA : endpointB), + MaxEndPoint((endpointA < endpointB) ? endpointB : endpointA) + {} + const vtkIdType MinEndPoint; + const vtkIdType MaxEndPoint; + inline bool operator==(const EdgeEndpoints &other) const { + return ( (this->MinEndPoint == other.MinEndPoint) + && (this->MaxEndPoint == other.MaxEndPoint) ); + } + }; + struct EdgeEndpointsHash { + public: + size_t operator()(const EdgeEndpoints &edge) const { + return static_cast<size_t>(edge.MinEndPoint + edge.MaxEndPoint); + } + }; + + // Description: + // Holds the information necessary for the facet this edge came from. + class EdgeInformation + { + public: + vtkIdType OriginalFaceId; + vtkIdType *StartPointIdP; + }; + + // Description: + // A map from edge endpoints to the information about that edge. + typedef vtksys::hash_map<EdgeEndpoints, EdgeInformation, EdgeEndpointsHash> + EdgeMapType; + + void RecordEdgeFlag(vtkPolyData *output, const EdgeInformation &edgeInfo, + vtkUnsignedCharArray *edgeFlagArray, unsigned char flag, + vtkIdType *duplicatePointMap) + { + vtkIdType pt = edgeInfo.StartPointIdP[0]; + if (edgeFlagArray->GetValue(pt) == flag) + { + // Edge flag already set correctly. Nothing to do. + return; + } + if (edgeFlagArray->GetValue(pt) == NO_EDGE_FLAG) + { + // Nothing has set the edge flag yet. Just set it and return. + edgeFlagArray->SetValue(pt, flag); + return; + } + + // If we are here then some other cell has already put a flag on this + // point different than ours. We have to adjust our cell topology to + // use a duplicate point. + if (duplicatePointMap[pt] == -1) + { + // No duplicate made. We need to make one. + vtkPoints *points = output->GetPoints(); + double coords[3]; + points->GetPoint(pt, coords); + vtkIdType newPt = points->InsertNextPoint(coords); + duplicatePointMap[pt] = newPt; + // Copying attributes from yourself seems weird, but is valid. + vtkPointData *pd = output->GetPointData(); + pd->CopyData(pd, pt, newPt); + edgeFlagArray->InsertValue(newPt, flag); + } + edgeInfo.StartPointIdP[0] = duplicatePointMap[pt]; + } +} +using namespace vtkPVRecoverGeometryWireframeNamespace; + +//============================================================================= +vtkCxxRevisionMacro(vtkPVRecoverGeometryWireframe, "$Revision$"); +vtkStandardNewMacro(vtkPVRecoverGeometryWireframe); + +//----------------------------------------------------------------------------- +vtkPVRecoverGeometryWireframe::vtkPVRecoverGeometryWireframe() +{ +} + +vtkPVRecoverGeometryWireframe::~vtkPVRecoverGeometryWireframe() +{ +} + +void vtkPVRecoverGeometryWireframe::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +//----------------------------------------------------------------------------- +int vtkPVRecoverGeometryWireframe::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + vtkPolyData *input = vtkPolyData::GetData(inputVector[0]); + vtkPolyData *output = vtkPolyData::GetData(outputVector); + + vtkIdType npts, *pts; + vtkstd::vector<vtkIdType> originalPts; + + if (!input->GetCellData()->HasArray(ORIGINAL_FACE_IDS())) + { + // Did not find the field used to identify the face each linear patch comes + // from. The original data was probably linear so using all the edges + // should be OK (and is at least the best we can do), so just pass the data. + output->ShallowCopy(input); + return 1; + } + + vtkIdTypeArray *faceIds = vtkIdTypeArray::SafeDownCast( + input->GetCellData()->GetAbstractArray(ORIGINAL_FACE_IDS())); + if (!faceIds) + { + vtkErrorMacro(<< ORIGINAL_FACE_IDS() << " array is not of expected type."); + return 0; + } + + // Shallow copy the cell data. All the cells get copied to output. + output->GetCellData()->PassData(input->GetCellData()); + + // Deep copy the point information and be ready to add points. + VTK_CREATE(vtkPoints, points); + points->DeepCopy(input->GetPoints()); + output->SetPoints(points); + vtkPointData *inputPD = input->GetPointData(); + vtkPointData *outputPD = output->GetPointData(); + outputPD->CopyAllocate(inputPD); + vtkIdType numOriginalPoints = points->GetNumberOfPoints(); + for (vtkIdType i = 0; i < numOriginalPoints; i++) + { + outputPD->CopyData(inputPD, i, i); + } + + // Create an edge flag array. + VTK_CREATE(vtkUnsignedCharArray, edgeflags); + edgeflags->SetName("vtkEdgeFlags"); + outputPD->AddArray(edgeflags); + outputPD->SetActiveAttribute("vtkEdgeFlags", vtkDataSetAttributes::EDGEFLAG); + edgeflags->SetNumberOfComponents(1); + edgeflags->SetNumberOfTuples(numOriginalPoints); + vtkstd::fill(edgeflags->GetPointer(0), + edgeflags->GetPointer(numOriginalPoints), NO_EDGE_FLAG); + + // Some (probably many) points will have to be duplicated because different + // cells will need different edge flags. This array maps the original + // point id to the duplicate id. + vtkstd::vector<vtkIdType> duplicatePointMap(numOriginalPoints); + vtkstd::fill(duplicatePointMap.begin(), duplicatePointMap.end(), -1); + + // Shallow copy the verts. Set the edge flags to true. + vtkCellArray *inputVerts = input->GetVerts(); + output->SetVerts(inputVerts); + for (inputVerts->InitTraversal(); inputVerts->GetNextCell(npts, pts); ) + { + for (vtkIdType i = 0; i < npts; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Shallow copy the lines. Set the edge flags to true. + vtkCellArray *inputLines = input->GetLines(); + output->SetLines(inputLines); + for (inputLines->InitTraversal(); inputLines->GetNextCell(npts, pts); ) + { + // No need to set edge flag for last index. + for (vtkIdType i = 0; i < npts-1; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Shallow copy the triangle strips. Set the edge flags to true. + vtkCellArray *inputStrips = input->GetStrips(); + output->SetStrips(inputStrips); + for (inputStrips->InitTraversal(); inputStrips->GetNextCell(npts, pts); ) + { + for (vtkIdType i = 0; i < npts; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Deep copy the polygons because we will be changing some indices when we + // duplicate points. + VTK_CREATE(vtkCellArray, outputPolys); + outputPolys->DeepCopy(input->GetPolys()); + output->SetPolys(outputPolys); + + // Iterate over all the input facets and see which edge interfaces belonged to + // different faces. We do that by recording the original face id in a map. + // When we find a pair of edges, we turn on the appropriate edge flag if they + // came from different faces, or turn it off if they came from the same face. + EdgeMapType edgeMap; + vtkIdType inputCellId + = inputVerts->GetNumberOfCells() + inputLines->GetNumberOfCells(); + for (outputPolys->InitTraversal(); outputPolys->GetNextCell(npts, pts); + inputCellId++) + { + if ((inputCellId%1000) == 0) + { + this->UpdateProgress(static_cast<double>(inputCellId) + /input->GetNumberOfCells()); + if (this->GetAbortExecute()) return 0; + } + // Record the original points of the polygon. As we iterate over edges, + // we may change the indices, but we allways compare edges by the original + // indices. + originalPts.resize(npts); + vtkstd::copy(pts, pts+npts, originalPts.begin()); + vtkIdType originalFace = faceIds->GetValue(inputCellId); + for (vtkIdType i = 0; i < npts; i++) + { + EdgeEndpoints edge(originalPts[i], originalPts[(i+1)%npts]); + EdgeInformation edgeInfo; + edgeInfo.OriginalFaceId = originalFace; + edgeInfo.StartPointIdP = &pts[i]; + + EdgeMapType::iterator edgeMatch = edgeMap.find(edge); + if (edgeMatch == edgeMap.end()) + { + // Not encountered yet. Add to the map. + edgeMap.insert(vtkstd::make_pair(edge, edgeInfo)); + } + else + { + // The edge flag is true if the edge connects two different faces. + unsigned char eflag = static_cast<unsigned char>( + edgeMatch->second.OriginalFaceId != originalFace); + RecordEdgeFlag(output, edgeMatch->second, edgeflags, eflag, + &duplicatePointMap.at(0)); + RecordEdgeFlag(output, edgeInfo, edgeflags, eflag, + &duplicatePointMap.at(0)); + // Remove the edge from the map since we already found the pair. + edgeMap.erase(edgeMatch); + } + } // For each edge + } // For each cell. + + // Everything left in the edge map has no match. It must necessarily be + // on the outside of a face. + for (EdgeMapType::iterator iter = edgeMap.begin(); + iter != edgeMap.end(); iter++) + { + RecordEdgeFlag(output, iter->second, edgeflags, 1, + &duplicatePointMap.at(0)); + } + + // If any points are unmarked, set some edge flag on them (although they + // are probably not referenced by any cell). + for (vtkIdType i = 0; i < numOriginalPoints; i++) + { + if (edgeflags->GetValue(i) == NO_EDGE_FLAG) edgeflags->SetValue(i, 1); + } + + return 1; +} diff --git a/Servers/Filters/vtkPVRecoverGeometryWireframe.h b/Servers/Filters/vtkPVRecoverGeometryWireframe.h new file mode 100644 index 0000000..6d1d569 --- /dev/null +++ b/Servers/Filters/vtkPVRecoverGeometryWireframe.h @@ -0,0 +1,73 @@ +// -*- c++ -*- +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: pqBlotDialog.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*------------------------------------------------------------------------- + Copyright 2009 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, + the U.S. Government retains certain rights in this software. +-------------------------------------------------------------------------*/ + +// .NAME vtkPVRecoverGeometryWireframe - Get corrected wireframe from tesselated facets +// +// .SECTION Description +// +// When vtkPVGeometryFilter tessellates nonlinear faces into linear +// approximations, it introduces edges in the middle of the facets of the +// original mesh (as any valid tessellation would). To correct for this, +// vtkPVGeometryFilter also writes out some fields that allows use to identify +// the edges that are actually part of the original mesh. This filter works in +// conjunction with vtkPVGeometryFilter by taking its output, adding an edge +// flag and making the appropriate adjustments so that rendering with line +// fill mode will make the correct wireframe. +// +// .SECTION See Also +// vtkPVGeometryFilter +// + +#ifndef __vtkPVRecoverGeometryWireframe_h +#define __vtkPVRecoverGeometryWireframe_h + +#include "vtkPolyDataAlgorithm.h" + +class VTK_EXPORT vtkPVRecoverGeometryWireframe : public vtkPolyDataAlgorithm +{ +public: + vtkTypeRevisionMacro(vtkPVRecoverGeometryWireframe, vtkPolyDataAlgorithm); + static vtkPVRecoverGeometryWireframe *New(); + virtual void PrintSelf(ostream &os, vtkIndent indent); + + // Description: + // In order to determine which edges existed in the original data, we need an + // identifier on each cell determining which face (not cell) it originally + // came from. The ids should be put in a cell data array with this name. The + // existance of this field is also a signal that this wireframe extraction is + // necessary. + static const char *ORIGINAL_FACE_IDS() + { return "vtkPVRecoverWireframeOriginalFaceIds"; } + +protected: + vtkPVRecoverGeometryWireframe(); + ~vtkPVRecoverGeometryWireframe(); + + virtual int RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + +private: + vtkPVRecoverGeometryWireframe(const vtkPVRecoverGeometryWireframe &); // Not implemented + void operator=(const vtkPVRecoverGeometryWireframe &); // Not implemented +}; + +#endif //__vtkPVRecoverGeometryWireframe_h diff --git a/Servers/ServerManager/Resources/filters.xml b/Servers/ServerManager/Resources/filters.xml index 70289ad..efd7835 100644 --- a/Servers/ServerManager/Resources/filters.xml +++ b/Servers/ServerManager/Resources/filters.xml @@ -1545,6 +1545,26 @@ The Extract Surface filter extracts the polygons forming the outer surface of th If the value of this property is set to 1, internal surfaces along process boundaries will be removed. NOTE: Enabling this option might cause multiple executions of the data source because more information is needed to remove internal surfaces. </Documentation> </IntVectorProperty> + + <IntVectorProperty name="NonlinearSubdivisionLevel" + command="SetNonlinearSubdivisionLevel" + number_of_elements="1" + default_values="1"> + <IntRangeDomain name="range" min="0" max="4" /> + <Documentation> + If the input is an unstructured grid with nonlinear faces, this + parameter determines how many times the face is subdivided into + linear faces. If 0, the output is the equivalent of its linear + couterpart (and the midpoints determining the nonlinear + interpolation are discarded). If 1, the nonlinear face is + triangulated based on the midpoints. If greater than 1, the + triangulated pieces are recursively subdivided to reach the + desired subdivision. Setting the value to greater than 1 may + cause some point data to not be passed even if no quadratic faces + exist. This option has no effect if the input is not an + unstructured grid. + </Documentation> + </IntVectorProperty> <!-- End DataSetSurfaceFilter --> </SourceProxy> @@ -7365,6 +7385,20 @@ Tessellate a higher-order dataset. Toggle whether to generate an outline or a surface. </Documentation> </IntVectorProperty> + <IntVectorProperty name="NonlinearSubdivisionLevel" + command="SetNonlinearSubdivisionLevel" + number_of_elements="1" + default_values="1"> + <IntRangeDomain name="range" min="0" max="4" /> + <Documentation> + Nonlinear faces are approximated with flat polygons. This + parameter controls how many times to subdivide nonlinear surface + cells. Higher subdivisions generate closer approximations but + take more memory and rendering time. Subdivision is recursive, + so the number of output polygons can grow exponentially with this + parameter. + </Documentation> + </IntVectorProperty> <IntVectorProperty name="PassThroughIds" command="SetPassThroughCellIds" diff --git a/Servers/ServerManager/Resources/rendering.xml b/Servers/ServerManager/Resources/rendering.xml index c5cf4eb..8d019f7 100644 --- a/Servers/ServerManager/Resources/rendering.xml +++ b/Servers/ServerManager/Resources/rendering.xml @@ -7118,7 +7118,7 @@ <SubProxy> <!-- - Geometry filter is used to conver non-polydata input to polydata. + Geometry filter is used to convert non-polydata input to polydata. It is also used to convert poly data to triangle strips when requested. --> @@ -7127,6 +7127,7 @@ <ExposedProperties> <Property name="UseStrips" /> <Property name="ForceStrips" /> + <Property name="NonlinearSubdivisionLevel" /> </ExposedProperties> </SubProxy> @@ -7992,6 +7993,7 @@ <!-- Geometry Filter properties --> <Property name="UseStrips" /> <Property name="ForceStrips" /> + <Property name="NonlinearSubdivisionLevel" /> <!-- Mapper properties --> <Property name="LookupTable" /> diff --git a/VTK b/VTK index 8920140..18f5783 160000 --- a/VTK +++ b/VTK @@ -1 +1 @@ -Subproject commit 892014037f07ac668979c85b85112fc850515b94 +Subproject commit 18f57839105fff9ca30c172e14f730af4f7a39c2 ![]() diff --git a/Filtering/vtkCellType.h b/Filtering/vtkCellType.h index 4633f74..7f7816f 100644 --- a/Filtering/vtkCellType.h +++ b/Filtering/vtkCellType.h @@ -29,7 +29,8 @@ // GetCell() and vtkGenericCell::SetCellType(). Also, to do the job right, // you'll also have to modify some filters (vtkGeometryFilter...) and // regression tests (example scripts) to reflect the new cell addition. -// Also, make sure to update vtkCellTypesStrings in vtkCellTypes.cxx. +// Also, make sure to update vtkCellTypesStrings in vtkCellTypes.cxx +// and the vtkCellTypes::IsLinear method in vtkCellTypes.h. // .SECTION Caveats // An unstructured grid stores the types of its cells as a @@ -78,6 +79,9 @@ typedef enum { // Special class of cells formed by convex group of points VTK_CONVEX_POINT_SET = 41, + // Polyhedron cell (consisting of polygonal faces) + VTK_POLYHEDRON = 42, + // Higher order cells in parametric form VTK_PARAMETRIC_CURVE = 51, VTK_PARAMETRIC_SURFACE = 52, diff --git a/Filtering/vtkCellTypes.h b/Filtering/vtkCellTypes.h index 08015d2..8e0498c 100644 --- a/Filtering/vtkCellTypes.h +++ b/Filtering/vtkCellTypes.h @@ -118,6 +118,13 @@ public: // defined in vtkCellType.h) static int GetTypeIdFromClassName(const char* classname); + // Description: + // This convenience method is a fast check to determine if a cell type + // represents a linear or nonlinear cell. This is generally much more + // efficient than getting the appropriate vtkCell and checking its IsLinear + // method. + static int IsLinear(unsigned char type); + protected: vtkCellTypes(); ~vtkCellTypes(); @@ -148,5 +155,13 @@ inline int vtkCellTypes::IsType(unsigned char type) return 0; } +//----------------------------------------------------------------------------- +inline int vtkCellTypes::IsLinear(unsigned char type) +{ + return ( (type <= 20) + || (type == VTK_CONVEX_POINT_SET) + || (type == VTK_POLYHEDRON) ); +} + #endif diff --git a/Filtering/vtkDataSetAttributes.cxx b/Filtering/vtkDataSetAttributes.cxx index d5739b0..67505f7 100644 --- a/Filtering/vtkDataSetAttributes.cxx +++ b/Filtering/vtkDataSetAttributes.cxx @@ -51,7 +51,9 @@ const char vtkDataSetAttributes "TCoords", "Tensors", "GlobalIds", - "PedigreeIds" }; + "PedigreeIds", + "EdgeFlag" +}; const char vtkDataSetAttributes ::LongAttributeNames[vtkDataSetAttributes::NUM_ATTRIBUTES][35] = @@ -61,7 +63,9 @@ const char vtkDataSetAttributes "vtkDataSetAttributes::TCOORDS", "vtkDataSetAttributes::TENSORS", "vtkDataSetAttributes::GLOBALIDS", - "vtkDataSetAttributes::PEDIGREEIDS" }; + "vtkDataSetAttributes::PEDIGREEIDS", + "vtkDataSetAttributes::EDGEFLAG" +}; //-------------------------------------------------------------------------- // Construct object with copying turned on for all data. @@ -1073,6 +1077,7 @@ const int vtkDataSetAttributes 3, 9, 1, + 1, 1}; //-------------------------------------------------------------------------- @@ -1085,6 +1090,7 @@ const int vtkDataSetAttributes MAX, EXACT, EXACT, + EXACT, EXACT}; //-------------------------------------------------------------------------- diff --git a/Filtering/vtkDataSetAttributes.h b/Filtering/vtkDataSetAttributes.h index 33051cc..187fe54 100644 --- a/Filtering/vtkDataSetAttributes.h +++ b/Filtering/vtkDataSetAttributes.h @@ -90,6 +90,7 @@ public: TENSORS=4, GLOBALIDS=5, PEDIGREEIDS=6, + EDGEFLAG=7, NUM_ATTRIBUTES }; @@ -165,6 +166,7 @@ public: // vtkDataSetAttributes::TENSORS = 4 // vtkDataSetAttributes::GLOBALIDS = 5 // vtkDataSetAttributes::PEDIGREEIDS = 6 + // vtkDataSetAttributes::EDGEFLAG = 7 // Returns the index of the array if succesful, -1 if the array // is not in the list of arrays. int SetActiveAttribute(const char* name, int attributeType); diff --git a/Graphics/vtkDataSetSurfaceFilter.cxx b/Graphics/vtkDataSetSurfaceFilter.cxx index 18c7c0a..d4f189d 100644 --- a/Graphics/vtkDataSetSurfaceFilter.cxx +++ b/Graphics/vtkDataSetSurfaceFilter.cxx @@ -16,8 +16,10 @@ #include "vtkCellArray.h" #include "vtkCellData.h" +#include "vtkDoubleArray.h" #include "vtkGenericCell.h" #include "vtkHexahedron.h" +#include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMergePoints.h" @@ -26,18 +28,19 @@ #include "vtkPolyData.h" #include "vtkPyramid.h" #include "vtkRectilinearGrid.h" -#include "vtkStructuredGrid.h" -#include "vtkUniformGrid.h" #include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkStructuredGrid.h" #include "vtkStructuredGridGeometryFilter.h" #include "vtkStructuredPoints.h" #include "vtkTetra.h" +#include "vtkUniformGrid.h" #include "vtkUnsignedCharArray.h" #include "vtkUnstructuredGrid.h" #include "vtkVoxel.h" #include "vtkWedge.h" -#include "vtkIdTypeArray.h" +#include <vtkstd/algorithm> +#include <vtksys/hash_map.hxx> static int sizeofFastQuad(int numPts) { @@ -45,6 +48,40 @@ static int sizeofFastQuad(int numPts) return static_cast<int>(sizeof(vtkFastGeomQuad)+(numPts-4)*sizeof(vtkIdType)); } + +class vtkDataSetSurfaceFilter::vtkEdgeInterpolationMap +{ +public: + void AddEdge(vtkIdType endpoint1, vtkIdType endpoint2, vtkIdType midpoint) { + if (endpoint1 > endpoint2) vtkstd::swap(endpoint1, endpoint2); + Map.insert(vtkstd::make_pair(vtkstd::make_pair(endpoint1, endpoint2), + midpoint)); + } + vtkIdType FindEdge(vtkIdType endpoint1, vtkIdType endpoint2) { + if (endpoint1 > endpoint2) vtkstd::swap(endpoint1, endpoint2); + MapType::iterator iter = Map.find(vtkstd::make_pair(endpoint1, endpoint2)); + if (iter != Map.end()) + { + return iter->second; + } + else + { + return -1; + } + } + +protected: + struct HashFunction { + public: + size_t operator()(vtkstd::pair<vtkIdType,vtkIdType> edge) const { + return static_cast<size_t>(edge.first + edge.second); + } + }; + typedef vtksys::hash_map<vtkstd::pair<vtkIdType, vtkIdType>, vtkIdType, + HashFunction> MapType; + MapType Map; +}; + vtkCxxRevisionMacro(vtkDataSetSurfaceFilter, "1.75"); vtkStandardNewMacro(vtkDataSetSurfaceFilter); @@ -53,6 +90,7 @@ vtkDataSetSurfaceFilter::vtkDataSetSurfaceFilter() { this->QuadHash = NULL; this->PointMap = NULL; + this->EdgeMap = NULL; this->QuadHashLength = 0; this->UseStrips = 0; this->NumberOfNewCells = 0; @@ -70,6 +108,10 @@ vtkDataSetSurfaceFilter::vtkDataSetSurfaceFilter() this->PassThroughPointIds = 0; this->OriginalCellIds = NULL; this->OriginalPointIds = NULL; + this->OriginalCellIdsName = NULL; + this->OriginalPointIdsName = NULL; + + this->NonlinearSubdivisionLevel = 1; } //---------------------------------------------------------------------------- @@ -84,6 +126,8 @@ vtkDataSetSurfaceFilter::~vtkDataSetSurfaceFilter() this->OriginalCellIds->Delete(); this->OriginalCellIds = NULL; } + this->SetOriginalCellIdsName(NULL); + this->SetOriginalPointIdsName(NULL); } //---------------------------------------------------------------------------- @@ -175,7 +219,7 @@ int vtkDataSetSurfaceFilter::RequestData( { //make a 1:1 mapping this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); vtkCellData *outputCD = output->GetCellData(); outputCD->AddArray(this->OriginalCellIds); @@ -192,7 +236,7 @@ int vtkDataSetSurfaceFilter::RequestData( { //make a 1:1 mapping this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); vtkPointData *outputPD = output->GetPointData(); outputPD->AddArray(this->OriginalPointIds); @@ -335,14 +379,14 @@ int vtkDataSetSurfaceFilter::StructuredExecute(vtkDataSet *input, if (this->PassThroughCellIds) { this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); output->GetCellData()->AddArray(this->OriginalCellIds); } if (this->PassThroughPointIds) { this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); output->GetPointData()->AddArray(this->OriginalPointIds); } @@ -894,6 +938,11 @@ void vtkDataSetSurfaceFilter::PrintSelf(ostream& os, vtkIndent indent) os << indent << "PassThroughCellIds: " << (this->PassThroughCellIds ? "On\n" : "Off\n"); os << indent << "PassThroughPointIds: " << (this->PassThroughPointIds ? "On\n" : "Off\n"); + os << indent << "OriginalCellIdsName: " << this->GetOriginalCellIdsName() << endl; + os << indent << "OriginalPointIdsName: " << this->GetOriginalPointIdsName() << endl; + + os << indent << "NonlinearSubdivisionLevel: " + << this->NonlinearSubdivisionLevel << endl; } //======================================================================== @@ -927,7 +976,6 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, vtkCellData *cd = input->GetCellData(); vtkPointData *outputPD = output->GetPointData(); vtkCellData *outputCD = output->GetCellData(); - vtkIdType outPts[6]; vtkFastGeomQuad *q; unsigned char* cellTypes = input->GetCellTypesArray()->GetPointer(0); @@ -936,9 +984,19 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, vtkPoints *coords; vtkCell *face; int flag2D = 0; + + // These are for subdividing quadratic cells + vtkDoubleArray *parametricCoords; + vtkDoubleArray *parametricCoords2; + vtkIdList *outPts; + vtkIdList *outPts2; pts = vtkIdList::New(); coords = vtkPoints::New(); + parametricCoords = vtkDoubleArray::New(); + parametricCoords2 = vtkDoubleArray::New(); + outPts = vtkIdList::New(); + outPts2 = vtkIdList::New(); // might not be necessary to set the data type for coords // but certainly safer to do so coords->SetDataType(input->GetPoints()->GetData()->GetDataType()); @@ -957,21 +1015,28 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, newVerts = vtkCellArray::New(); newLines = vtkCellArray::New(); - outputPD->CopyGlobalIdsOn(); - outputPD->CopyAllocate(inputPD, numPts, numPts/2); + if (this->NonlinearSubdivisionLevel <= 1) + { + outputPD->CopyGlobalIdsOn(); + outputPD->CopyAllocate(inputPD, numPts, numPts/2); + } + else + { + outputPD->InterpolateAllocate(inputPD, numPts, numPts/2); + } outputCD->CopyGlobalIdsOn(); outputCD->CopyAllocate(inputCD, numCells, numCells/2); if (this->PassThroughCellIds) { this->OriginalCellIds = vtkIdTypeArray::New(); - this->OriginalCellIds->SetName("vtkOriginalCellIds"); + this->OriginalCellIds->SetName(this->GetOriginalCellIdsName()); this->OriginalCellIds->SetNumberOfComponents(1); } if (this->PassThroughPointIds) { this->OriginalPointIds = vtkIdTypeArray::New(); - this->OriginalPointIds->SetName("vtkOriginalPointIds"); + this->OriginalPointIds->SetName(this->GetOriginalPointIdsName()); this->OriginalPointIds->SetNumberOfComponents(1); } @@ -1180,14 +1245,40 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, if ( cellIds->GetNumberOfIds() <= 0) { // FIXME: Face could not be consistent. vtkOrderedTriangulator is a better option - face->Triangulate(0,pts,coords); - for (i=0; i < pts->GetNumberOfIds(); i+=3) + if (this->NonlinearSubdivisionLevel >= 1) { - this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1), - pts->GetId(i+2), cellId); + // TODO: Handle NonlinearSubdivisionLevel > 1 correctly. + face->Triangulate(0,pts,coords); + for (i=0; i < pts->GetNumberOfIds(); i+=3) + { + this->InsertTriInHash(pts->GetId(i), pts->GetId(i+1), + pts->GetId(i+2), cellId); + } } - } - } + else + { + switch (face->GetCellType()) + { + case VTK_QUADRATIC_TRIANGLE: + this->InsertTriInHash(face->PointIds->GetId(0), + face->PointIds->GetId(1), + face->PointIds->GetId(2), cellId); + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + case VTK_QUADRATIC_LINEAR_QUAD: + this->InsertQuadInHash(face->PointIds->GetId(0), + face->PointIds->GetId(1), + face->PointIds->GetId(2), + face->PointIds->GetId(3), cellId); + break; + default: + vtkWarningMacro(<< "Encountered unknown nonlinear face."); + break; + } // switch cell type + } // subdivision level + } // cell has ids + } // for faces cellIds->Delete(); } //3d cell } //nonlinear cell @@ -1211,6 +1302,25 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, // Move to the next cell. cellPointer += (1 + *cellPointer); + // If we have a quadratic face and our subdivision level is zero, just treat + // it as a linear cell. This should work so long as the first points of the + // quadratic cell correspond to all those of the equivalent linear cell + // (which all the current definitions do). + if (this->NonlinearSubdivisionLevel < 1) + { + switch (cellType) + { + case VTK_QUADRATIC_TRIANGLE: + cellType = VTK_TRIANGLE; numCellPts = 3; + break; + case VTK_QUADRATIC_QUAD: + case VTK_BIQUADRATIC_QUAD: + case VTK_QUADRATIC_LINEAR_QUAD: + cellType = VTK_POLYGON; numCellPts = 4; + break; + } + } + // A couple of common cases to see if things go faster. if (cellType == VTK_PIXEL) { // Do we really want to insert the 2D cells into a hash? @@ -1263,14 +1373,99 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, || cellType == VTK_BIQUADRATIC_QUAD || cellType == VTK_QUADRATIC_LINEAR_QUAD) { + // Note: we should not be here if this->NonlinearSubdivisionLevel is less + // than 1. See the check above. input->GetCell( cellId, cell ); cell->Triangulate( 0, pts, coords ); - for ( i=0; i < pts->GetNumberOfIds(); i+=3 ) + // Copy the level 1 subdivision points (which also exist in the input and + // can therefore just be copied over. Note that the output of Triangulate + // records triangles in pts where each 3 points defines a triangle. We + // will keep this invariant and also keep the same invariant in + // parametericCoords and outPts later. + outPts->Reset(); + for ( i=0; i < pts->GetNumberOfIds(); i++ ) + { + vtkIdType op; + op = this->GetOutputPointId(pts->GetId(i), input, newPts, outputPD); + outPts->InsertNextId(op); + } + // Do any further subdivision if necessary. + if (this->NonlinearSubdivisionLevel > 1) + { + // We are going to need parametric coordinates to further subdivide. + double *pc = cell->GetParametricCoords(); + parametricCoords->Reset(); + parametricCoords->SetNumberOfComponents(3); + for (i = 0; i < pts->GetNumberOfIds(); i++) + { + vtkIdType ptId = pts->GetId(i); + vtkIdType cellPtId; + for (cellPtId = 0; cell->GetPointId(cellPtId) != ptId; cellPtId++); + parametricCoords->InsertNextTupleValue(pc + 3*cellPtId); + } + // Subdivide these triangles as many more times as necessary. Remember + // that we have already done the first subdivision. + for (j = 1; j < this->NonlinearSubdivisionLevel; j++) + { + parametricCoords2->Reset(); + parametricCoords2->SetNumberOfComponents(3); + outPts2->Reset(); + // Each triangle will be split into 4 triangles. + for (i = 0; i < outPts->GetNumberOfIds(); i += 3) + { + // Hold the input point ids and parametric coordinates. First 3 + // indices are the original points. Second three are the midpoints + // in the edges (0,1), (1,2) and (2,0), respectively (see comment + // below). + vtkIdType inPts[6]; + double inParamCoords[6][3]; + int k; + for (k = 0; k < 3; k++) + { + inPts[k] = outPts->GetId(i+k); + parametricCoords->GetTupleValue(i+k, inParamCoords[k]); + } + for (k = 3; k < 6; k++) + { + int pt1 = k-3; + int pt2 = (pt1 < 2) ? (pt1 + 1) : 0; + inParamCoords[k][0] = 0.5*(inParamCoords[pt1][0] + inParamCoords[pt2][0]); + inParamCoords[k][1] = 0.5*(inParamCoords[pt1][1] + inParamCoords[pt2][1]); + inParamCoords[k][2] = 0.5*(inParamCoords[pt1][2] + inParamCoords[pt2][2]); + inPts[k] = GetInterpolatedPointId(inPts[pt1], inPts[pt2], + input, cell, + inParamCoords[k], newPts, + outputPD); + } + // * 0 + // / \ Use the 6 points recorded + // / \ in inPts and inParamCoords + // 3 *-----* 5 to create the 4 triangles + // / \ / \ shown here. + // / \ / \ . + // *-----*-----* + // 1 4 2 + const int subtriangles[12] = {0,3,5, 3,1,4, 3,4,5, 5,4,2}; + for (k = 0; k < 12; k++) + { + int localId = subtriangles[k]; + outPts2->InsertNextId(inPts[localId]); + parametricCoords2->InsertNextTupleValue(inParamCoords[localId]); + } + } // Iterate over triangles + // Now that we have recorded the subdivided triangles in outPts2 and + // parametricCoords2, swap them with outPts and parametricCoords to + // make them the current ones. + vtkstd::swap(outPts, outPts2); + vtkstd::swap(parametricCoords, parametricCoords2); + } // Iterate over subdivision levels + } // If further subdivision + + // Now that we have done all the subdivisions and created all of the + // points, record the triangles. + for (i = 0; i < outPts->GetNumberOfIds(); i += 3) { - outPts[0] = this->GetOutputPointId( pts->GetId(i), input, newPts, outputPD ); - outPts[1] = this->GetOutputPointId( pts->GetId(i+1), input, newPts, outputPD ); - outPts[2] = this->GetOutputPointId( pts->GetId(i+2), input, newPts, outputPD ); - newPolys->InsertNextCell( 3, outPts ); + newPolys->InsertNextCell(3, outPts->GetPointer(i)); this->RecordOrigCellId(this->NumberOfNewCells, cellId); outputCD->CopyData(cd, cellId, this->NumberOfNewCells++); } @@ -1306,6 +1501,10 @@ int vtkDataSetSurfaceFilter::UnstructuredGridExecute(vtkDataSet *dataSetInput, cell->Delete(); coords->Delete(); pts->Delete(); + parametricCoords->Delete(); + parametricCoords2->Delete(); + outPts->Delete(); + outPts2->Delete(); output->SetPoints(newPts); newPts->Delete(); @@ -1367,6 +1566,7 @@ void vtkDataSetSurfaceFilter::InitializeQuadHash(vtkIdType numPoints) this->QuadHash[i] = NULL; this->PointMap[i] = -1; } + this->EdgeMap = new vtkEdgeInterpolationMap; } //---------------------------------------------------------------------------- @@ -1386,6 +1586,8 @@ void vtkDataSetSurfaceFilter::DeleteQuadHash() this->QuadHashLength = 0; delete [] this->PointMap; this->PointMap = NULL; + delete this->EdgeMap; + this->EdgeMap = NULL; } //---------------------------------------------------------------------------- @@ -1781,6 +1983,34 @@ vtkIdType vtkDataSetSurfaceFilter::GetOutputPointId(vtkIdType inPtId, return outPtId; } +//----------------------------------------------------------------------------- +vtkIdType vtkDataSetSurfaceFilter::GetInterpolatedPointId(vtkIdType edgePtA, + vtkIdType edgePtB, + vtkDataSet *input, + vtkCell *cell, + double pcoords[3], + vtkPoints *outPts, + vtkPointData *outPD) +{ + vtkIdType outPtId; + + outPtId = this->EdgeMap->FindEdge(edgePtA, edgePtB); + if (outPtId == -1) + { + int subId = -1; + double wcoords[3]; + double weights[100]; // Any reason to need more? + cell->EvaluateLocation(subId, pcoords, wcoords, weights); + outPtId = outPts->InsertNextPoint(wcoords); + outPD->InterpolatePoint(input->GetPointData(), outPtId, + cell->GetPointIds(), weights); + this->RecordOrigPointId(outPtId, -1); + this->EdgeMap->AddEdge(edgePtA, edgePtB, outPtId); + } + + return outPtId; +} + //---------------------------------------------------------------------------- void vtkDataSetSurfaceFilter::RecordOrigCellId(vtkIdType destIndex, vtkIdType originalId) diff --git a/Graphics/vtkDataSetSurfaceFilter.h b/Graphics/vtkDataSetSurfaceFilter.h index f089c97..80a41c4 100644 --- a/Graphics/vtkDataSetSurfaceFilter.h +++ b/Graphics/vtkDataSetSurfaceFilter.h @@ -80,6 +80,34 @@ public: vtkGetMacro(PassThroughPointIds,int); vtkBooleanMacro(PassThroughPointIds,int); + // Description: + // If PassThroughCellIds or PassThroughPointIds is on, then these ivars + // control the name given to the field in which the ids are written into. If + // set to NULL, then vtkOriginalCellIds or vtkOriginalPointIds (the default) + // is used, respectively. + vtkSetStringMacro(OriginalCellIdsName); + virtual const char *GetOriginalCellIdsName() { + return ( this->OriginalCellIdsName + ? this->OriginalCellIdsName : "vtkOriginalCellIds"); + } + vtkSetStringMacro(OriginalPointIdsName); + virtual const char *GetOriginalPointIdsName() { + return ( this->OriginalPointIdsName + ? this->OriginalPointIdsName : "vtkOriginalPointIds"); + } + + // Description: + // If the input is an unstructured grid with nonlinear faces, this parameter + // determines how many times the face is subdivided into linear faces. If 0, + // the output is the equivalent of its linear couterpart (and the midpoints + // determining the nonlinear interpolation are discarded). If 1 (the + // default), the nonlinear face is triangulated based on the midpoints. If + // greater than 1, the triangulated pieces are recursively subdivided to reach + // the desired subdivision. Setting the value to greater than 1 may cause + // some point data to not be passed even if no nonlinear faces exist. This + // option has no effect if the input is not an unstructured grid. + vtkSetMacro(NonlinearSubdivisionLevel, int); + vtkGetMacro(NonlinearSubdivisionLevel, int); // Description: // Direct access methods that can be used to use the this class as an @@ -143,6 +171,14 @@ protected: vtkIdType *PointMap; vtkIdType GetOutputPointId(vtkIdType inPtId, vtkDataSet *input, vtkPoints *outPts, vtkPointData *outPD); +//BTX + class vtkEdgeInterpolationMap; +//ETX + vtkEdgeInterpolationMap *EdgeMap; + vtkIdType GetInterpolatedPointId(vtkIdType edgePtA, vtkIdType edgePtB, + vtkDataSet *input, vtkCell *cell, + double pcoords[3], vtkPoints *outPts, + vtkPointData *outPD); vtkIdType NumberOfNewCells; @@ -164,10 +200,14 @@ protected: void RecordOrigCellId(vtkIdType newIndex, vtkIdType origId); virtual void RecordOrigCellId(vtkIdType newIndex, vtkFastGeomQuad *quad); vtkIdTypeArray *OriginalCellIds; + char *OriginalCellIdsName; int PassThroughPointIds; void RecordOrigPointId(vtkIdType newIndex, vtkIdType origId); vtkIdTypeArray *OriginalPointIds; + char *OriginalPointIdsName; + + int NonlinearSubdivisionLevel; private: vtkDataSetSurfaceFilter(const vtkDataSetSurfaceFilter&); // Not implemented. diff --git a/Graphics/vtkUnstructuredGridGeometryFilter.cxx b/Graphics/vtkUnstructuredGridGeometryFilter.cxx index d6ffb0a..7065491 100644 --- a/Graphics/vtkUnstructuredGridGeometryFilter.cxx +++ b/Graphics/vtkUnstructuredGridGeometryFilter.cxx @@ -27,6 +27,7 @@ #include "vtkPolyData.h" #include "vtkPyramid.h" #include "vtkPentagonalPrism.h" +#include "vtkSmartPointer.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkStructuredGrid.h" #include "vtkTetra.h" @@ -718,6 +719,11 @@ vtkUnstructuredGridGeometryFilter::vtkUnstructuredGridGeometryFilter() this->CellClipping = 0; this->ExtentClipping = 0; + this->PassThroughCellIds = 0; + this->PassThroughPointIds = 0; + this->OriginalCellIdsName = NULL; + this->OriginalPointIdsName = NULL; + this->Merging = 1; this->Locator = NULL; @@ -732,6 +738,9 @@ vtkUnstructuredGridGeometryFilter::~vtkUnstructuredGridGeometryFilter() this->Locator->UnRegister(this); this->Locator = NULL; } + + this->SetOriginalCellIdsName(NULL); + this->SetOriginalPointIdsName(NULL); } //----------------------------------------------------------------------------- @@ -905,8 +914,24 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPts->Allocate(numPts); output->Allocate(numCells); outputPD->CopyAllocate(pd,numPts,numPts/2); + vtkSmartPointer<vtkIdTypeArray> originalPointIds; + if (this->PassThroughPointIds) + { + originalPointIds = vtkSmartPointer<vtkIdTypeArray>::New(); + originalPointIds->SetName(this->GetOriginalPointIdsName()); + originalPointIds->SetNumberOfComponents(1); + originalPointIds->Allocate(numPts, numPts/2); + } outputCD->CopyAllocate(cd,numCells,numCells/2); + vtkSmartPointer<vtkIdTypeArray> originalCellIds; + if (this->PassThroughCellIds) + { + originalCellIds = vtkSmartPointer<vtkIdTypeArray>::New(); + originalCellIds->SetName(this->GetOriginalCellIdsName()); + originalCellIds->SetNumberOfComponents(1); + originalCellIds->Allocate(numCells, numCells/2); + } vtkIdType *pointMap=0; @@ -979,6 +1004,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( if ( this->Locator->InsertUniquePoint(x, newPtId) ) { outputPD->CopyData(pd,ptId,newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(newPtId); } @@ -993,6 +1022,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPtId=newPts->InsertNextPoint(inPts->GetPoint(ptId)); pointMap[ptId]=newPtId; outputPD->CopyData(pd, ptId, newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(pointMap[ptId]); } @@ -1000,6 +1033,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newCellId = output->InsertNextCell(cellType,cellIds); outputCD->CopyData(cd, cellId, newCellId); + if (this->PassThroughCellIds) + { + originalCellIds->InsertValue(newCellId, cellId); + } } else // added the faces to the hashtable { @@ -1378,6 +1415,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( if ( this->Locator->InsertUniquePoint(x, newPtId) ) { outputPD->CopyData(pd,ptId,newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(newPtId); } @@ -1392,6 +1433,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPtId=newPts->InsertNextPoint(inPts->GetPoint(ptId)); pointMap[ptId]=newPtId; outputPD->CopyData(pd, ptId, newPtId); + if (this->PassThroughPointIds) + { + originalPointIds->InsertValue(newPtId, ptId); + } } cellIds->InsertNextId(pointMap[ptId]); } @@ -1399,6 +1444,10 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newCellId = output->InsertNextCell(cellType,cellIds); outputCD->CopyData(cd, cellId, newCellId); + if (this->PassThroughCellIds) + { + originalCellIds->InsertValue(newCellId, cellId); + } } cursor.Next(); } @@ -1416,6 +1465,15 @@ int vtkUnstructuredGridGeometryFilter::RequestData( newPts->Delete(); // output->SetCells(types,locs,conn); + + if (this->PassThroughPointIds) + { + outputPD->AddArray(originalPointIds); + } + if (this->PassThroughCellIds) + { + outputCD->AddArray(originalCellIds); + } if(!this->Merging && this->Locator) { @@ -1491,6 +1549,12 @@ void vtkUnstructuredGridGeometryFilter::PrintSelf(ostream& os, os << indent << "CellClipping: " << (this->CellClipping ? "On\n" : "Off\n"); os << indent << "ExtentClipping: " << (this->ExtentClipping ? "On\n" : "Off\n"); + os << indent << "PassThroughCellIds: " << this->PassThroughCellIds << endl; + os << indent << "PassThroughPointIds: " << this->PassThroughPointIds << endl; + + os << indent << "OriginalCellIdsName: " << this->GetOriginalCellIdsName() << endl; + os << indent << "OriginalPointIdsName: " << this->GetOriginalPointIdsName() << endl; + os << indent << "Merging: " << (this->Merging ? "On\n" : "Off\n"); if ( this->Locator ) { diff --git a/Graphics/vtkUnstructuredGridGeometryFilter.h b/Graphics/vtkUnstructuredGridGeometryFilter.h index 66b28d8..4d73db9 100644 --- a/Graphics/vtkUnstructuredGridGeometryFilter.h +++ b/Graphics/vtkUnstructuredGridGeometryFilter.h @@ -107,6 +107,36 @@ public: vtkBooleanMacro(Merging,int); // Description: + // If on, the output polygonal dataset will have a celldata array that + // holds the cell index of the original 3D cell that produced each output + // cell. This is useful for cell picking. The default is off to conserve + // memory. Note that PassThroughCellIds will be ignored if UseStrips is on, + // since in that case each tringle strip can represent more than on of the + // input cells. + vtkSetMacro(PassThroughCellIds,int); + vtkGetMacro(PassThroughCellIds,int); + vtkBooleanMacro(PassThroughCellIds,int); + vtkSetMacro(PassThroughPointIds,int); + vtkGetMacro(PassThroughPointIds,int); + vtkBooleanMacro(PassThroughPointIds,int); + + // Description: + // If PassThroughCellIds or PassThroughPointIds is on, then these ivars + // control the name given to the field in which the ids are written into. If + // set to NULL, then vtkOriginalCellIds or vtkOriginalPointIds (the default) + // is used, respectively. + vtkSetStringMacro(OriginalCellIdsName); + virtual const char *GetOriginalCellIdsName() { + return ( this->OriginalCellIdsName + ? this->OriginalCellIdsName : "vtkOriginalCellIds"); + } + vtkSetStringMacro(OriginalPointIdsName); + virtual const char *GetOriginalPointIdsName() { + return ( this->OriginalPointIdsName + ? this->OriginalPointIdsName : "vtkOriginalPointIds"); + } + + // Description: // Set / get a spatial locator for merging points. By // default an instance of vtkMergePoints is used. void SetLocator(vtkIncrementalPointLocator *locator); @@ -138,6 +168,11 @@ protected: int CellClipping; int ExtentClipping; + int PassThroughCellIds; + int PassThroughPointIds; + char *OriginalCellIdsName; + char *OriginalPointIdsName; + int Merging; vtkIncrementalPointLocator *Locator; diff --git a/IO/vtkSLACReader.cxx b/IO/vtkSLACReader.cxx index 68ec746..4db8a03 100644 --- a/IO/vtkSLACReader.cxx +++ b/IO/vtkSLACReader.cxx @@ -1315,13 +1315,6 @@ int vtkSLACReader::ReadMidpointCoordinates( int vtkSLACReader::ReadMidpointData(int meshFD, vtkMultiBlockDataSet *output, MidpointIdMap &midpointIds) { - static bool GaveMidpointWarning = false; - if (!GaveMidpointWarning) - { - vtkWarningMacro(<< "Quadratic elements not displayed entirely correctly yet. Quadratic triangles are drawn as 4 linear triangles."); - GaveMidpointWarning = true; - } - // Get the point information from the data. vtkPoints *points = vtkPoints::SafeDownCast( output->GetInformation()->Get(vtkSLACReader::POINTS())); diff --git a/Rendering/vtkChooserPainter.cxx b/Rendering/vtkChooserPainter.cxx index a215b0f..11bcbe2 100644 --- a/Rendering/vtkChooserPainter.cxx +++ b/Rendering/vtkChooserPainter.cxx @@ -20,6 +20,7 @@ #include "vtkInformation.h" #include "vtkLinesPainter.h" #include "vtkObjectFactory.h" +#include "vtkPointData.h" #include "vtkPointsPainter.h" #include "vtkPolyData.h" #include "vtkPolygonsPainter.h" @@ -338,7 +339,9 @@ void vtkChooserPainter::RenderInternal(vtkRenderer* renderer, vtkActor* actor, if ( this->UseLinesPainterForWireframes && (actor->GetProperty()->GetRepresentation() == VTK_WIREFRAME) && !actor->GetProperty()->GetBackfaceCulling() - && !actor->GetProperty()->GetFrontfaceCulling() ) + && !actor->GetProperty()->GetFrontfaceCulling() + && !this->GetInputAsPolyData()->GetPointData()->GetAttribute( + vtkDataSetAttributes::EDGEFLAG) ) { this->LinePainter->Render(renderer, actor, vtkPainter::POLYS, forceCompileOnly); diff --git a/Rendering/vtkLinesPainter.cxx b/Rendering/vtkLinesPainter.cxx index ca9fc8a..877e075 100644 --- a/Rendering/vtkLinesPainter.cxx +++ b/Rendering/vtkLinesPainter.cxx @@ -131,6 +131,9 @@ int vtkLinesPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, // we just ignore the flag. idx &= (~VTK_PDM_FIELD_COLORS); + // Also ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + // draw all the elements, use fast path if available switch (idx) { diff --git a/Rendering/vtkOpenGLPainterDeviceAdapter.cxx b/Rendering/vtkOpenGLPainterDeviceAdapter.cxx index 0c0eb91..9328a3c 100644 --- a/Rendering/vtkOpenGLPainterDeviceAdapter.cxx +++ b/Rendering/vtkOpenGLPainterDeviceAdapter.cxx @@ -259,6 +259,7 @@ int vtkOpenGLPainterDeviceAdapter::IsAttributesSupported(int attribute) case vtkDataSetAttributes::NORMALS: case vtkDataSetAttributes::SCALARS: case vtkDataSetAttributes::TCOORDS: + case vtkDataSetAttributes::EDGEFLAG: return 1; } return 0; @@ -534,6 +535,18 @@ void vtkOpenGLPainterDeviceAdapter::SendAttribute(int index, int numcomp, return; } break; + case vtkDataSetAttributes::EDGEFLAG: // Edge Flag + if (numcomp != 1) + { + vtkErrorMacro("Bad number of components."); + return; + } + switch (type) + { + vtkTemplateMacro(glEdgeFlag(static_cast<GLboolean>( + reinterpret_cast<const VTK_TT*>(attribute)[offset]))); + } + break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -715,6 +728,33 @@ void vtkOpenGLPainterDeviceAdapter::SetAttributePointer(int index, } glTexCoordPointer(numcomponents, gltype, stride, pointer); break; + case vtkDataSetAttributes::EDGEFLAG: // Edge flag + if (numcomponents != 1) + { + vtkErrorMacro("Edge flag must have one component."); + return; + } + // Flag must be conformant to GLboolean + if ((type == VTK_FLOAT) || (type == GL_DOUBLE)) + { + vtkErrorMacro("Unsupported type for edge flag: " << type); + return; + } + // Thus is an unfriendly way to force the array to be conformant to + // a GLboolean array. At the very least there should be some indication + // in VTK outside of OpenGL to determine which VTK type to use. + switch (type) + { + vtkTemplateMacro(if (sizeof(VTK_TT) != sizeof(GLboolean)) + { + vtkErrorMacro(<< "Unsupported tyep for edge flag: " + << type); + return; + } + ); + } + glEdgeFlagPointer(stride, pointer); + break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -735,6 +775,8 @@ void vtkOpenGLPainterDeviceAdapter::EnableAttributeArray(int index) glEnableClientState(GL_COLOR_ARRAY); break; case vtkDataSetAttributes::TCOORDS: glEnableClientState(GL_TEXTURE_COORD_ARRAY); break; + case vtkDataSetAttributes::EDGEFLAG: + glEnableClientState(GL_EDGE_FLAG_ARRAY); break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; @@ -753,6 +795,8 @@ void vtkOpenGLPainterDeviceAdapter::DisableAttributeArray(int index) glDisableClientState(GL_COLOR_ARRAY); break; case vtkDataSetAttributes::TCOORDS: glDisableClientState(GL_TEXTURE_COORD_ARRAY); break; + case vtkDataSetAttributes::EDGEFLAG: + glDisableClientState(GL_EDGE_FLAG_ARRAY); break; default: vtkErrorMacro("Unsupported attribute index: " << index); return; diff --git a/Rendering/vtkPointsPainter.cxx b/Rendering/vtkPointsPainter.cxx index 97d1613..ce64eb6 100644 --- a/Rendering/vtkPointsPainter.cxx +++ b/Rendering/vtkPointsPainter.cxx @@ -107,6 +107,10 @@ int vtkPointsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, // since this painter does not deal with field colors specially, // we just ignore the flag. idx &= (~VTK_PDM_FIELD_COLORS); + + // Also ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + switch (idx) { case 0://no cell/point attribs are present. diff --git a/Rendering/vtkPolygonsPainter.cxx b/Rendering/vtkPolygonsPainter.cxx index 62ed003..3f02deb 100644 --- a/Rendering/vtkPolygonsPainter.cxx +++ b/Rendering/vtkPolygonsPainter.cxx @@ -181,6 +181,8 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, pd->GetLines()->GetNumberOfCells(); vtkIdType cellNumStart = cellNum; vtkIdType totalCells = ca->GetNumberOfCells(); + vtkUnsignedCharArray *ef = vtkUnsignedCharArray::SafeDownCast( + pd->GetPointData()->GetAttribute(vtkDataSetAttributes::EDGEFLAG)); vtkPainterDeviceAdapter* device = ren->GetRenderWindow()-> GetPainterDeviceAdapter(); @@ -188,6 +190,7 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, void *normals = 0; void *tcoords = 0; unsigned char *colors = 0; + unsigned char *edgeflags = 0; int primitive = VTK_POLYGON; if (ca->GetNumberOfCells() == 0) @@ -211,12 +214,17 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, { tcoords = t->GetVoidPointer(0); } + if (ef) + { + edgeflags = ef->GetPointer(0); + } vtkIdType *ptIds = ca->GetPointer(); vtkIdType *endPtIds = ptIds + ca->GetNumberOfConnectivityEntries(); int ptype = p->GetDataType(); int ntype = (n)? n->GetDataType() : 0; int ttype = (t)? t->GetDataType() : 0; int tcomps = (t)? t->GetNumberOfComponents() : 0; + int eftype = (ef)? ef->GetDataType() : 0; int celloffset = 0; // since this painter does not deal with field colors specially, @@ -412,9 +420,266 @@ int vtkPolygonsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, VTK_UNSIGNED_CHAR, colors); colors += 4;, celloffset = cellNum;); break; + + case VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, ;,;); + } + break; + + case VTK_PDM_NORMALS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + + case VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);,;,;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_TCOORDS | VTK_PDM_EDGEFLAGS: + if (this->BuildNormals) + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, tcomps, + ttype, tcoords, tcomps**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + PolyNormal,;); + } + else + { + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::TCOORDS, 1, + ttype, tcoords, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + ;,;); + } + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, + colors + 4**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++;, + celloffset = cellNum;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, colors); + colors += 4;,;); + break; + case VTK_PDM_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3**ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, colors); + colors += 4;,;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++; + device->SendAttribute(vtkPointData::SCALARS, 4, + VTK_UNSIGNED_CHAR, colors); + colors += 4;, + celloffset = cellNum;); + break; + case VTK_PDM_CELL_NORMALS | VTK_PDM_COLORS | VTK_PDM_OPAQUE_COLORS | VTK_PDM_CELL_COLORS | VTK_PDM_EDGEFLAGS: + vtkDrawPolysMacro(primitive, + device->SendAttribute(vtkPointData::EDGEFLAG, 1, + eftype, edgeflags, *ptIds); + device->SendAttribute(vtkPointData::NUM_ATTRIBUTES, 3, + ptype, points, 3**ptIds);, + device->SendAttribute(vtkPointData::NORMALS, 3, + ntype, normals, 3*celloffset); + celloffset++; + device->SendAttribute(vtkPointData::SCALARS, 3, + VTK_UNSIGNED_CHAR, colors); + colors += 4;, + celloffset = cellNum;); + break; + default: return 0; // let the delegate painter handle it. } + + if (idx & VTK_PDM_EDGEFLAGS) + { + // Reset the edge flag to 1 so that if the next thing rendered does not + // have an edge flag, it will have all edges on. + unsigned char edgeflag = 1; + device->SendAttribute(vtkPointData::EDGEFLAG, 1, VTK_UNSIGNED_CHAR, + &edgeflag, 0); + } + return 1; } diff --git a/Rendering/vtkPrimitivePainter.cxx b/Rendering/vtkPrimitivePainter.cxx index df859e9..d6253cd 100644 --- a/Rendering/vtkPrimitivePainter.cxx +++ b/Rendering/vtkPrimitivePainter.cxx @@ -159,6 +159,7 @@ void vtkPrimitivePainter::RenderInternal(vtkRenderer* renderer, vtkUnsignedCharArray *c=NULL; vtkDataArray *n; vtkDataArray *t; + vtkDataArray *ef; int tDim; vtkPolyData *input = this->GetInputAsPolyData(); int cellNormals; @@ -269,6 +270,28 @@ void vtkPrimitivePainter::RenderInternal(vtkRenderer* renderer, idx |= VTK_PDM_TCOORDS; } + // Edge flag + ef = input->GetPointData()->GetAttribute(vtkDataSetAttributes::EDGEFLAG); + if (ef) + { + if (ef->GetNumberOfComponents() != 1) + { + vtkDebugMacro(<< "Currently only 1d edge flags are supported."); + ef = NULL; + } + if (!ef->IsA("vtkUnsignedCharArray")) + { + vtkDebugMacro(<< "Currently only unsigned char edge flags are suported."); + ef = NULL; + } + } + + // Set the flags + if (ef) + { + idx |= VTK_PDM_EDGEFLAGS; + } + if (!act) { vtkErrorMacro("No actor"); diff --git a/Rendering/vtkPrimitivePainter.h b/Rendering/vtkPrimitivePainter.h index 100cc22..2ca46a7 100644 --- a/Rendering/vtkPrimitivePainter.h +++ b/Rendering/vtkPrimitivePainter.h @@ -49,14 +49,15 @@ protected: //BTX enum { - VTK_PDM_NORMALS = 0x01, - VTK_PDM_COLORS = 0x02, - VTK_PDM_TCOORDS = 0x04, - VTK_PDM_CELL_COLORS = 0x08, - VTK_PDM_CELL_NORMALS = 0x10, - VTK_PDM_OPAQUE_COLORS = 0x20, - VTK_PDM_FIELD_COLORS = 0x40, - VTK_PDM_GENERIC_VERTEX_ATTRIBUTES =0x80 + VTK_PDM_NORMALS = 0x001, + VTK_PDM_COLORS = 0x002, + VTK_PDM_TCOORDS = 0x004, + VTK_PDM_CELL_COLORS = 0x008, + VTK_PDM_CELL_NORMALS = 0x010, + VTK_PDM_OPAQUE_COLORS = 0x020, + VTK_PDM_FIELD_COLORS = 0x040, + VTK_PDM_EDGEFLAGS = 0x080, + VTK_PDM_GENERIC_VERTEX_ATTRIBUTES = 0x100 }; //ETX diff --git a/Rendering/vtkTStripsPainter.cxx b/Rendering/vtkTStripsPainter.cxx index 101070f..f326981 100644 --- a/Rendering/vtkTStripsPainter.cxx +++ b/Rendering/vtkTStripsPainter.cxx @@ -189,6 +189,9 @@ int vtkTStripsPainter::RenderPrimitive(unsigned long idx, vtkDataArray* n, int ttype = (t)? t->GetDataType() : 0; int tcomps = (t)? t->GetNumberOfComponents() : 0; + // Ignore edge flags. + idx &= (~VTK_PDM_EDGEFLAGS); + // draw all the elements, use fast path if available switch (idx) { ![]() diff --git a/Applications/ParaView/ParaViewFilters.xml b/Applications/ParaView/ParaViewFilters.xml index 33a878e..137ac3a 100644 --- a/Applications/ParaView/ParaViewFilters.xml +++ b/Applications/ParaView/ParaViewFilters.xml @@ -106,6 +106,7 @@ <Proxy group="filters" name="GroupDataSets" /> <Proxy group="filters" name="IntegrateAttributes" /> <Proxy group="filters" name="IntegrateFlowThroughSurface" /> + <Proxy group="filters" name="IsoVolume" /> <Proxy group="filters" name="LevelIdScalars" /> <Proxy group="filters" name="LinearExtrusionFilter" /> <Proxy group="filters" name="LoopSubdivisionFilter" /> diff --git a/Applications/StreamingParaView/streamingMainWindow.cxx b/Applications/StreamingParaView/streamingMainWindow.cxx index 050e93e..ebbbaa8 100644 --- a/Applications/StreamingParaView/streamingMainWindow.cxx +++ b/Applications/StreamingParaView/streamingMainWindow.cxx @@ -47,7 +47,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "pqApplicationCore.h" #include "pqCustomDisplayPolicy.h" -#include <QShortcut> +#include <QShortCut> #include <QStatusBar> #include <iostream> diff --git a/Plugins/CoProcessingScriptGenerator/pqCPExportStateWizard.cxx b/Plugins/CoProcessingScriptGenerator/pqCPExportStateWizard.cxx index bf8c141..4f2aab3 100644 --- a/Plugins/CoProcessingScriptGenerator/pqCPExportStateWizard.cxx +++ b/Plugins/CoProcessingScriptGenerator/pqCPExportStateWizard.cxx @@ -144,7 +144,8 @@ pqCPExportStateWizard::pqCPExportStateWizard( this->Internals = new pqInternals(); this->Internals->setupUi(this); ::ActiveWizard = NULL; - this->setOption(QWizard::NoCancelButton, false); + // the mac style does not have a cancel button so we want to not use it + this->setWizardStyle(ModernStyle); QObject::connect(this->Internals->allInputs, SIGNAL(itemSelectionChanged()), this, SLOT(updateAddRemoveButton())); diff --git a/Qt/ApplicationComponents/pqSaveStateReaction.cxx b/Qt/ApplicationComponents/pqSaveStateReaction.cxx index 40c6832..df8afd3 100644 --- a/Qt/ApplicationComponents/pqSaveStateReaction.cxx +++ b/Qt/ApplicationComponents/pqSaveStateReaction.cxx @@ -63,7 +63,7 @@ void pqSaveStateReaction::saveState() { pqFileDialog fileDialog(NULL, pqCoreUtilities::mainWidget(), - tr("Save State File"), QString(), + tr("Load State File"), QString(), tr("ParaView state file (*.pvsm);;All files (*)")); fileDialog.setObjectName("FileSaveServerStateDialog"); fileDialog.setFileMode(pqFileDialog::AnyFile); diff --git a/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui b/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui index 1d0bf2c..2f7c5c7 100644 --- a/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui +++ b/Qt/Components/Resources/UI/pqDisplayProxyEditor.ui @@ -581,13 +581,43 @@ </spacer> </item> <item row="7" column="0"> - <widget class="QLabel" name="label_19"> + <widget class="QLabel" name="label_17"> <property name="text"> + <string>Subdivision</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QSpinBox" name="NonlinearSubdivisionLevel"> + <property name="toolTip"> + <string>Nonlinear faces are approximated with flat polygons. This parameter controls how many times to subdivide nonlinear surface cells. Higher subdivisions generate closer approximations but take more memory and rendering time. Subdivision is recursive, so the number of output polygons can grow exponentially with this parameter.</string> + </property> + <property name="maximum"> + <number>4</number> + </property> + </widget> + </item> + <item row="7" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="8" column="0" > + <widget class="QLabel" name="label_19" > + <property name="text" > <string>Volume mapper</string> </property> </widget> </item> - <item row="7" column="1" colspan="2"> + <item row="8" column="1" colspan="2"> <widget class="QComboBox" name="SelectedMapperIndex"> <property name="toolTip"> <string><html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:Sans Serif; font-size:9pt; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Choose the mapper to use for volume rendering.</p></body></html></string> @@ -1123,6 +1153,7 @@ <tabstop>StylePointSize</tabstop> <tabstop>StyleLineWidth</tabstop> <tabstop>Opacity</tabstop> + <tabstop>NonlinearSubdivisionLevel</tabstop> <tabstop>SelectedMapperIndex</tabstop> <tabstop>EdgeColor</tabstop> <tabstop>SpecularIntensity</tabstop> diff --git a/Qt/Components/pqDisplayProxyEditor.cxx b/Qt/Components/pqDisplayProxyEditor.cxx index 64cfa25..bc3f83b 100644 --- a/Qt/Components/pqDisplayProxyEditor.cxx +++ b/Qt/Components/pqDisplayProxyEditor.cxx @@ -390,6 +390,15 @@ void pqDisplayProxyEditor::setRepresentation(pqPipelineRepresentation* repr) "value", SIGNAL(editingFinished()), reprProxy, reprProxy->GetProperty("Opacity")); + // setup of nonlinear subdivision + if (reprProxy->GetProperty("NonlinearSubdivisionLevel")) + { + this->Internal->Links->addPropertyLink( + this->Internal->NonlinearSubdivisionLevel, + "value", SIGNAL(valueChanged(int)), + reprProxy, reprProxy->GetProperty("NonlinearSubdivisionLevel")); + } + // setup for map scalars this->Internal->Links->addPropertyLink( this->Internal->ColorMapScalars, "checked", SIGNAL(stateChanged(int)), diff --git a/Qt/Core/pqContextView.cxx b/Qt/Core/pqContextView.cxx index 6077334..c03277b 100644 --- a/Qt/Core/pqContextView.cxx +++ b/Qt/Core/pqContextView.cxx @@ -283,12 +283,6 @@ void pqContextView::selectionChanged() opPort->getSource()->getProxy()); vtkSMSourceProxy* selectionSource = opPort->getSelectionInput(); - int selectionType = vtkSelectionNode::POINT; - if (QString(opPort->getDataClassName()) == "vtkTable") - { - selectionType = vtkSelectionNode::ROW; - } - if (!selectionSource) { vtkSMProxyManager* pxm = vtkSMProxyManager::GetProxyManager(); @@ -296,7 +290,7 @@ void pqContextView::selectionChanged() vtkSMSourceProxy::SafeDownCast(pxm->NewProxy("sources", "IDSelectionSource")); selectionSource->SetConnectionID(pqRepr->getServer()->GetConnectionID()); selectionSource->SetServers(vtkProcessModule::DATA_SERVER); - vtkSMPropertyHelper(selectionSource, "FieldType").Set(selectionType); + vtkSMPropertyHelper(selectionSource, "FieldType").Set(vtkSelectionNode::POINT); selectionSource->UpdateVTKObjects(); } else diff --git a/Qt/Core/pqSpreadSheetViewModel.cxx b/Qt/Core/pqSpreadSheetViewModel.cxx index 1e443b8..51a711a 100644 --- a/Qt/Core/pqSpreadSheetViewModel.cxx +++ b/Qt/Core/pqSpreadSheetViewModel.cxx @@ -309,8 +309,7 @@ void pqSpreadSheetViewModel::updateSelectionForBlock(vtkIdType blockNumber) vtkSMSpreadSheetRepresentationProxy* repr = this->Internal->Representation; if (repr && (this->Internal->getFieldType() == vtkDataObject::FIELD_ASSOCIATION_CELLS || - this->Internal->getFieldType() == vtkDataObject::FIELD_ASSOCIATION_POINTS || - this->Internal->getFieldType() == vtkDataObject::FIELD_ASSOCIATION_ROWS) ) + this->Internal->getFieldType() == vtkDataObject::FIELD_ASSOCIATION_POINTS)) { // If we are showing only the selected items, then there's not point in // highlighting the selected items, since all items are selected. So we diff --git a/Servers/Filters/CMakeLists.txt b/Servers/Filters/CMakeLists.txt index acf0a71..2adaebd 100644 --- a/Servers/Filters/CMakeLists.txt +++ b/Servers/Filters/CMakeLists.txt @@ -70,6 +70,7 @@ SET(Filters_SRCS vtkIntegrateAttributes.cxx vtkIntegrateFlowThroughSurface.cxx vtkInteractorStyleTransferFunctionEditor.cxx + vtkPVIsoVolume.cxx vtkKdTreeGenerator.cxx vtkKdTreeManager.cxx vtkMergeArrays.cxx @@ -96,7 +97,6 @@ SET(Filters_SRCS vtkPSciVizMultiCorrelativeStats.cxx vtkPSciVizPCAStats.cxx vtkPSciVizKMeans.cxx - vtkPVAMRDualClip.cxx vtkPVAnimationScene.cxx vtkPVArrayCalculator.cxx vtkPVArrowSource.cxx @@ -129,6 +129,7 @@ SET(Filters_SRCS vtkPVMain.cxx vtkPVMergeTables.cxx vtkPVNullSource.cxx + vtkPVRecoverGeometryWireframe.cxx vtkPVRenderViewProxy.cxx vtkPVScalarBarActor.cxx vtkPVSelectionSource.cxx diff --git a/Servers/Filters/Testing/Cxx/CMakeLists.txt b/Servers/Filters/Testing/Cxx/CMakeLists.txt index c5495f5..067caee 100644 --- a/Servers/Filters/Testing/Cxx/CMakeLists.txt +++ b/Servers/Filters/Testing/Cxx/CMakeLists.txt @@ -35,7 +35,7 @@ IF (VTK_USE_DISPLAY AND VTK_DATA_ROOT AND PARAVIEW_DATA_ROOT) # Enable these after the transfer function can take the vtkTable histograms. #TestTransferFunctionEditor #TestTransferFunctionEditor2 -TestPVAMRDualClip +TestPVIsoVolume ) FOREACH(name ${ServersFiltersImage_SRCS}) ADD_EXECUTABLE(${name} ${name}.cxx) diff --git a/Servers/Filters/Testing/Cxx/TestPVAMRDualClip.cxx b/Servers/Filters/Testing/Cxx/TestPVAMRDualClip.cxx deleted file mode 100644 index 314fe7e..0000000 --- a/Servers/Filters/Testing/Cxx/TestPVAMRDualClip.cxx +++ /dev/null @@ -1,89 +0,0 @@ -#include "vtkActor.h" -#include "vtkDataSetSurfaceFilter.h" -#include "vtkDummyController.h" -#include "vtkPolyDataMapper.h" -#include "vtkPVGeometryFilter.h" -#include "vtkPVAMRDualClip.h" -#include "vtkRegressionTestImage.h" -#include "vtkRenderer.h" -#include "vtkRenderWindow.h" -#include "vtkRenderWindowInteractor.h" -#include "vtkSmartPointer.h" -#include "vtkSpyPlotReader.h" -#include "vtkTestUtilities.h" - -int main(int argc, char* argv[]) -{ - int retVal = 0; - - typedef vtkSmartPointer<vtkDataSetSurfaceFilter> vtkDataSetSurfaceFilterRefPtr; - typedef vtkSmartPointer<vtkPVAMRDualClip> vtkPVAMRDualClipRefPtr; - typedef vtkSmartPointer<vtkSpyPlotReader> vtkSpyPlotReaderRefPtr; - typedef vtkSmartPointer<vtkPolyDataMapper> vtkPolyDataMapperRefPtr; - typedef vtkSmartPointer<vtkActor> vtkActorRefPtr; - typedef vtkSmartPointer<vtkRenderer> vtkRenderRefPtr; - typedef vtkSmartPointer<vtkRenderWindow> vtkRenderWindowRefPtr; - typedef vtkSmartPointer<vtkDummyController> vtkDummyControllerRefPtr; - typedef vtkSmartPointer<vtkPVGeometryFilter> vtkPVGeometryFilterRefPtr; - typedef vtkSmartPointer<vtkRenderWindowInteractor> vtkRenderWindowInteractorRefPtr; - - const char* fname = - vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/SPCTH/restarted/spcth.0"); - - if(!fname) - { - return retVal; - } - - vtkDummyControllerRefPtr controller (vtkDummyControllerRefPtr::New()); - vtkMultiProcessController::SetGlobalController(controller); - - vtkSpyPlotReaderRefPtr reader = vtkSpyPlotReaderRefPtr::New(); - reader->SetFileName(fname); - reader->SetGlobalController(controller); - reader->MergeXYZComponentsOn(); - reader->DownConvertVolumeFractionOn(); - reader->DistributeFilesOn(); - reader->SetCellArrayStatus("Material volume fraction - 3", 1); - reader->Update(); - - vtkPVAMRDualClipRefPtr filter = vtkPVAMRDualClipRefPtr::New(); - filter->SetInput(reader->GetOutputDataObject(0)); - filter->SetVolumeFractionSurfaceValue(0.1); - filter->SetEnableMergePoints(1); - filter->SetEnableDegenerateCells(1); - filter->SetEnableMultiProcessCommunication(1); - filter->AddInputCellArrayToProcess("Material volume fraction - 3"); - filter->Update(); - - vtkPVGeometryFilterRefPtr surface (vtkPVGeometryFilterRefPtr::New()); - surface->SetUseOutline(0); - surface->SetInput(filter->GetOutputDataObject(0)); - surface->Update(); - - vtkPolyDataMapperRefPtr mapper (vtkPolyDataMapperRefPtr::New()); - mapper->SetInput(surface->GetOutput()); - mapper->Update(); - - vtkActorRefPtr actor (vtkActorRefPtr::New()); - actor->SetMapper(mapper); - - vtkRenderRefPtr renderer (vtkRenderRefPtr::New()); - renderer->AddActor(actor); - renderer->ResetCamera(); - - vtkRenderWindowRefPtr renWin (vtkRenderWindowRefPtr::New()); - renWin->AddRenderer(renderer); - - vtkRenderWindowInteractorRefPtr iren (vtkRenderWindowInteractorRefPtr::New()); - iren->SetRenderWindow(renWin); - - retVal = vtkRegressionTestImage(renWin); - if(retVal == vtkRegressionTester::DO_INTERACTOR) - { - iren->Start(); - retVal = vtkRegressionTester::PASSED; - } - - return (retVal == vtkRegressionTester::PASSED) ? 0 : 1; -} diff --git a/Servers/Filters/Testing/Cxx/TestPVIsoVolume.cxx b/Servers/Filters/Testing/Cxx/TestPVIsoVolume.cxx new file mode 100644 index 0000000..a952949 --- /dev/null +++ b/Servers/Filters/Testing/Cxx/TestPVIsoVolume.cxx @@ -0,0 +1,91 @@ + +#include "vtkActor.h" +#include "vtkDataSetSurfaceFilter.h" +#include "vtkDummyController.h" +#include "vtkPolyDataMapper.h" +#include "vtkPVGeometryFilter.h" +#include "vtkPVIsoVolume.h" +#include "vtkRegressionTestImage.h" +#include "vtkRenderer.h" +#include "vtkRenderWindow.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkSmartPointer.h" +#include "vtkSpyPlotReader.h" +#include "vtkTestUtilities.h" + +int main(int argc, char* argv[]) +{ + int retVal = 0; + + typedef vtkSmartPointer<vtkDataSetSurfaceFilter> vtkDataSetSurfaceFilterRefPtr; + typedef vtkSmartPointer<vtkPVIsoVolume> vtkPVIsoVolumeRefPtr; + typedef vtkSmartPointer<vtkSpyPlotReader> vtkSpyPlotReaderRefPtr; + typedef vtkSmartPointer<vtkPolyDataMapper> vtkPolyDataMapperRefPtr; + typedef vtkSmartPointer<vtkActor> vtkActorRefPtr; + typedef vtkSmartPointer<vtkRenderer> vtkRenderRefPtr; + typedef vtkSmartPointer<vtkRenderWindow> vtkRenderWindowRefPtr; + typedef vtkSmartPointer<vtkDummyController> vtkDummyControllerRefPtr; + typedef vtkSmartPointer<vtkPVGeometryFilter> vtkPVGeometryFilterRefPtr; + typedef vtkSmartPointer<vtkRenderWindowInteractor> vtkRenderWindowInteractorRefPtr; + + const char* fname = + vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/SPCTH/restarted/spcth.0"); + + if(!fname) + { + return retVal; + } + + vtkDummyControllerRefPtr controller (vtkDummyControllerRefPtr::New()); + vtkMultiProcessController::SetGlobalController(controller); + + vtkSpyPlotReaderRefPtr reader = vtkSpyPlotReaderRefPtr::New(); + reader->SetFileName(fname); + reader->SetGlobalController(controller); + reader->MergeXYZComponentsOn(); + reader->DownConvertVolumeFractionOn(); + reader->DistributeFilesOn(); + reader->SetCellArrayStatus("Material volume fraction - 3", 1); + reader->Update(); + + vtkPVIsoVolumeRefPtr filter = vtkPVIsoVolumeRefPtr::New(); + filter->SetInput(reader->GetOutputDataObject(0)); + filter->SetVolumeFractionSurfaceValue(0.1); + filter->SetEnableMergePoints(1); + filter->SetEnableDegenerateCells(1); + filter->SetEnableMultiProcessCommunication(1); + filter->AddInputCellArrayToProcess("Material volume fraction - 3"); + filter->Update(); + + vtkPVGeometryFilterRefPtr surface (vtkPVGeometryFilterRefPtr::New()); + surface->SetUseOutline(0); + surface->SetInput(filter->GetOutputDataObject(0)); + surface->Update(); + + vtkPolyDataMapperRefPtr mapper (vtkPolyDataMapperRefPtr::New()); + mapper->SetInput(surface->GetOutput()); + mapper->Update(); + + vtkActorRefPtr actor (vtkActorRefPtr::New()); + actor->SetMapper(mapper); + + vtkRenderRefPtr renderer (vtkRenderRefPtr::New()); + renderer->AddActor(actor); + renderer->ResetCamera(); + + vtkRenderWindowRefPtr renWin (vtkRenderWindowRefPtr::New()); + renWin->AddRenderer(renderer); + + vtkRenderWindowInteractorRefPtr iren (vtkRenderWindowInteractorRefPtr::New()); + iren->SetRenderWindow(renWin); + + retVal = vtkRegressionTestImage(renWin); + if(retVal == vtkRegressionTester::DO_INTERACTOR) + { + iren->Start(); + retVal = vtkRegressionTester::PASSED; + } + + return (retVal == vtkRegressionTester::PASSED) ? 0 : 1; +} + diff --git a/Servers/Filters/vtkPVAMRDualClip.cxx b/Servers/Filters/vtkPVAMRDualClip.cxx deleted file mode 100644 index 59e7e69..0000000 --- a/Servers/Filters/vtkPVAMRDualClip.cxx +++ /dev/null @@ -1,97 +0,0 @@ -#include "vtkPVAMRDualClip.h" - -#include "vtkHierarchicalBoxDataSet.h" -#include "vtkInformation.h" -#include "vtkInformationVector.h" -#include "vtkMultiBlockDataSet.h" -#include "vtkObjectFactory.h" - -#include "vtkCompositeDataIterator.h" - -#include <vtkstd/string> // STL required. -#include <vtkstd/vector> // STL required. - -vtkCxxRevisionMacro(vtkPVAMRDualClip, "1.1"); -vtkStandardNewMacro(vtkPVAMRDualClip); - -const double PV_AMR_SURFACE_VALUE_UNSIGNED_CHAR=255; - -//----------------------------------------------------------------------------- -class vtkPVAMRDualClipInternal -{ -public: - - vtkstd::vector<vtkstd::string> CellArrays; -}; - -//----------------------------------------------------------------------------- -vtkPVAMRDualClip::vtkPVAMRDualClip() : - vtkAMRDualClip(), - VolumeFractionSurfaceValue(1.0) -{ - this->Implementation = new vtkPVAMRDualClipInternal(); -} - -//----------------------------------------------------------------------------- -vtkPVAMRDualClip::~vtkPVAMRDualClip() -{ - if(this->Implementation) - { - delete this->Implementation; - this->Implementation = 0; - } -} - -//----------------------------------------------------------------------------- -void vtkPVAMRDualClip::PrintSelf(ostream &os, vtkIndent indent) -{ - this->Superclass::PrintSelf(os, indent); -} - -//----------------------------------------------------------------------------- -int vtkPVAMRDualClip::RequestData(vtkInformation* vtkNotUsed(request), - vtkInformationVector** inputVector, - vtkInformationVector* outputVector) -{ - vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); - vtkHierarchicalBoxDataSet* hbdsInput=vtkHierarchicalBoxDataSet::SafeDownCast( - inInfo->Get(vtkDataObject::DATA_OBJECT())); - - vtkInformation *outInfo; - outInfo = outputVector->GetInformationObject(0); - vtkMultiBlockDataSet* mbdsOutput0 = vtkMultiBlockDataSet::SafeDownCast( - outInfo->Get(vtkDataObject::DATA_OBJECT())); - - - this->SetIsoValue(this->VolumeFractionSurfaceValue * - PV_AMR_SURFACE_VALUE_UNSIGNED_CHAR); - - size_t noOfArrays = this->Implementation->CellArrays.size(); - for(size_t i=0; i < noOfArrays; ++i) - { - vtkMultiBlockDataSet* out = this->DoRequestData( - hbdsInput, this->Implementation->CellArrays[i].c_str()); - - if(out) - { - /// Assign the name to the block by the array name. - mbdsOutput0->SetBlock(i, out); - out->Delete(); - } - } - return 1; -} - -//----------------------------------------------------------------------------- -void vtkPVAMRDualClip::AddInputCellArrayToProcess(const char* name) -{ - this->Implementation->CellArrays.push_back(vtkstd::string(name)); - this->Modified(); -} - -//----------------------------------------------------------------------------- -void vtkPVAMRDualClip::ClearInputCellArrayToProcess() -{ - this->Implementation->CellArrays.clear(); - this->Modified(); -} diff --git a/Servers/Filters/vtkPVAMRDualClip.h b/Servers/Filters/vtkPVAMRDualClip.h deleted file mode 100644 index c1f1213..0000000 --- a/Servers/Filters/vtkPVAMRDualClip.h +++ /dev/null @@ -1,68 +0,0 @@ -/*========================================================================= - - Program: ParaView - Module: vtkPVAMRDualClip.h - - Copyright (c) Kitware, Inc. - All rights reserved. - See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. - - This software is distributed WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - PURPOSE. See the above copyright notice for more information. - -=========================================================================*/ -// .NAME vtkPVAMRDualClip - Generates contour given one or more cell array -// and a volume fraction value. -// -// .SECTION Description -// -// .SEE vtkAMRDualClip -// - -#ifndef __vtkPVAMRDualClip_h -#define __vtkPVAMRDualClip_h - -#include "vtkAMRDualClip.h" - -// Forware declaration. -class vtkPVAMRDualClipInternal; - -class VTK_EXPORT vtkPVAMRDualClip : public vtkAMRDualClip -{ -public: - static vtkPVAMRDualClip* New(); - vtkTypeRevisionMacro(vtkPVAMRDualClip,vtkAMRDualClip); - void PrintSelf(ostream& os, vtkIndent indent); - - vtkPVAMRDualClip(); - ~vtkPVAMRDualClip(); - - // Description: - // Add to list of cell arrays which are used for generating contours. - void AddInputCellArrayToProcess(const char* name); - void ClearInputCellArrayToProcess(); - - // Description: - // Get / Set volume fraction value. - vtkGetMacro(VolumeFractionSurfaceValue, double); - vtkSetMacro(VolumeFractionSurfaceValue, double); - - //BTX - virtual int RequestData(vtkInformation*, vtkInformationVector**, - vtkInformationVector*); - -private: - vtkPVAMRDualClip(const vtkPVAMRDualClip&); // Not implemented. - void operator=(const vtkPVAMRDualClip&); // Not implemented. - - //ETX - -protected: - - double VolumeFractionSurfaceValue; - - vtkPVAMRDualClipInternal* Implementation; -}; - -#endif // __vtkPVAMRDualClip_h diff --git a/Servers/Filters/vtkPVExtractSelection.cxx b/Servers/Filters/vtkPVExtractSelection.cxx index e7d2da8..c542828 100644 --- a/Servers/Filters/vtkPVExtractSelection.cxx +++ b/Servers/Filters/vtkPVExtractSelection.cxx @@ -28,12 +28,10 @@ #include "vtkSelection.h" #include "vtkSelectionNode.h" #include "vtkSmartPointer.h" -#include "vtkTable.h" -#include "vtkGraph.h" #include <vtkstd/vector> -class vtkPVExtractSelection::vtkSelectionNodeVector : +class vtkPVExtractSelection::vtkSelectionNodeVector : public vtkstd::vector<vtkSmartPointer<vtkSelectionNode> > { }; @@ -84,7 +82,7 @@ int vtkPVExtractSelection::RequestDataObject( { vtkInformation* info = outputVector->GetInformationObject(i); vtkSelection *selOut = vtkSelection::GetData(info); - if (!selOut || !selOut->IsA("vtkSelection")) + if (!selOut || !selOut->IsA("vtkSelection")) { vtkDataObject* newOutput = vtkSelection::New(); if (!newOutput) @@ -119,20 +117,15 @@ int vtkPVExtractSelection::RequestData( vtkCompositeDataSet* cdInput = vtkCompositeDataSet::SafeDownCast(inputDO); vtkCompositeDataSet* cdOutput = vtkCompositeDataSet::GetData(outputVector, 0); - vtkDataObject *dataObjectOutput = vtkDataObject::GetData(outputVector, 0); + vtkDataSet *geomOutput = vtkDataSet::GetData(outputVector, 0); //make an ids selection for the second output - //we can do this because all of the extractSelectedX filters produce - //arrays called "vtkOriginalXIds" that record what input cells produced + //we can do this because all of the extractSelectedX filters produce + //arrays called "vtkOriginalXIds" that record what input cells produced //each output cell, at least as long as PRESERVE_TOPOLOGY is off - //when we start allowing PreserveTopology, this will have to instead run + //when we start allowing PreserveTopology, this will have to instead run //through the vtkInsidedNess arrays, and for every on entry, record the //entries index - // - // TODO: The ExtractSelectedGraph filter does not produce the vtkOriginalXIds, - // so to add support for vtkGraph selection in ParaView the filter will have - // to be extended. This requires test cases in ParaView to confirm it functions - // as expected. vtkSelection *output = vtkSelection::SafeDownCast( outputVector->GetInformationObject(1)->Get(vtkDataObject::DATA_OBJECT())); @@ -182,9 +175,9 @@ int vtkPVExtractSelection::RequestData( // vtkSelection instances correctly to help identify the block they came // from. vtkCompositeDataIterator* iter = cdInput->NewIterator(); - vtkHierarchicalBoxDataIterator* hbIter = + vtkHierarchicalBoxDataIterator* hbIter = vtkHierarchicalBoxDataIterator::SafeDownCast(iter); - for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); + for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem()) { vtkSelectionNode* curSel = this->LocateSelection(iter->GetCurrentFlatIndex(), @@ -195,18 +188,18 @@ int vtkPVExtractSelection::RequestData( hbIter->GetCurrentIndex(), sel); } - dataObjectOutput = vtkDataObject::SafeDownCast(cdOutput->GetDataSet(iter)); + geomOutput = vtkDataSet::SafeDownCast(cdOutput->GetDataSet(iter)); vtkSelectionNodeVector curOVector; - if (curSel && dataObjectOutput) + if (curSel && geomOutput) { - this->RequestDataInternal(curOVector, dataObjectOutput, curSel); + this->RequestDataInternal(curOVector, geomOutput, curSel); } for (vtkSelectionNodeVector::iterator giter = non_composite_nodes.begin(); giter != non_composite_nodes.end(); ++giter) { - this->RequestDataInternal(curOVector, dataObjectOutput, giter->GetPointer()); + this->RequestDataInternal(curOVector, geomOutput, giter->GetPointer()); } for (vtkSelectionNodeVector::iterator viter = curOVector.begin(); @@ -221,12 +214,12 @@ int vtkPVExtractSelection::RequestData( } iter->Delete(); } - else if (dataObjectOutput) // and not composite dataset. + else if (geomOutput) { unsigned int numNodes = sel->GetNumberOfNodes(); for (unsigned int i = 0; i < numNodes; i++) { - this->RequestDataInternal(oVector, dataObjectOutput, sel->GetNode(i)); + this->RequestDataInternal(oVector, geomOutput, sel->GetNode(i)); } } @@ -274,7 +267,7 @@ vtkSelectionNode* vtkPVExtractSelection::LocateSelection(unsigned int composite_ if (node) { if (node->GetProperties()->Has(vtkSelectionNode::COMPOSITE_INDEX()) && - node->GetProperties()->Get(vtkSelectionNode::COMPOSITE_INDEX()) == + node->GetProperties()->Get(vtkSelectionNode::COMPOSITE_INDEX()) == static_cast<int>(composite_index)) { return node; @@ -286,27 +279,23 @@ vtkSelectionNode* vtkPVExtractSelection::LocateSelection(unsigned int composite_ //---------------------------------------------------------------------------- void vtkPVExtractSelection::RequestDataInternal(vtkSelectionNodeVector& outputs, - vtkDataObject* dataObjectOutput, vtkSelectionNode* sel) + vtkDataSet* geomOutput, vtkSelectionNode* sel) { // DON'T CLEAR THE outputs. - vtkDataSet* ds = vtkDataSet::SafeDownCast(dataObjectOutput); - vtkTable* table = vtkTable::SafeDownCast(dataObjectOutput); - vtkGraph* graph = vtkGraph::SafeDownCast(dataObjectOutput); - int ft = vtkSelectionNode::CELL; if (sel && sel->GetProperties()->Has(vtkSelectionNode::FIELD_TYPE())) { ft = sel->GetProperties()->Get(vtkSelectionNode::FIELD_TYPE()); } - if (ds && ft == vtkSelectionNode::CELL) + if (geomOutput && ft == vtkSelectionNode::CELL) { vtkSelectionNode* output = vtkSelectionNode::New(); output->GetProperties()->Copy(sel->GetProperties(), /*deep=*/1); output->SetContentType(vtkSelectionNode::INDICES); vtkIdTypeArray *oids = vtkIdTypeArray::SafeDownCast( - ds->GetCellData()->GetArray("vtkOriginalCellIds")); + geomOutput->GetCellData()->GetArray("vtkOriginalCellIds")); if (oids) { output->SetSelectionList(oids); @@ -316,15 +305,14 @@ void vtkPVExtractSelection::RequestDataInternal(vtkSelectionNodeVector& outputs, } // no else, since original point indices are always passed. - if (ds && ( - ft == vtkSelectionNode::CELL || ft == vtkSelectionNode::POINT)) + if (geomOutput) { vtkSelectionNode* output = vtkSelectionNode::New(); output->GetProperties()->Copy(sel->GetProperties(), /*deep=*/1); output->SetFieldType(vtkSelectionNode::POINT); output->SetContentType(vtkSelectionNode::INDICES); vtkIdTypeArray* oids = vtkIdTypeArray::SafeDownCast( - ds->GetPointData()->GetArray("vtkOriginalPointIds")); + geomOutput->GetPointData()->GetArray("vtkOriginalPointIds")); if (oids) { output->SetSelectionList(oids); @@ -332,32 +320,6 @@ void vtkPVExtractSelection::RequestDataInternal(vtkSelectionNodeVector& outputs, } output->Delete(); } - - if (table && ft == vtkSelectionNode::ROW) - { - vtkSelectionNode* output = vtkSelectionNode::New(); - output->GetProperties()->Copy(sel->GetProperties(), /*deep=*/1); - output->SetFieldType(vtkSelectionNode::ROW); - output->SetContentType(vtkSelectionNode::INDICES); - vtkIdTypeArray* oids = vtkIdTypeArray::SafeDownCast( - table->GetRowData()->GetArray("vtkOriginalRowIds")); - if (oids) - { - output->SetSelectionList(oids); - outputs.push_back(output); - } - output->Delete(); - } - - // The ExtractSelectedGraph filter does not produce the vtkOriginal*Ids array, - // it will need extending to be able to follow the same pattern (with some - // test cases to verify functionality). - if (graph && ft == vtkSelectionNode::VERTEX) - { - } - if (graph && ft == vtkSelectionNode::EDGE) - { - } } //---------------------------------------------------------------------------- diff --git a/Servers/Filters/vtkPVExtractSelection.h b/Servers/Filters/vtkPVExtractSelection.h index 93517ad..b8eedaf 100644 --- a/Servers/Filters/vtkPVExtractSelection.h +++ b/Servers/Filters/vtkPVExtractSelection.h @@ -29,9 +29,6 @@ // cells in the subset with the original data set. This is used, for instance, // by ParaView's Spreadsheet view. // -// Output port 2 -- is simply the input vtkSelection (set on input port number -// 1). -// // .SECTION See Also // vtkExtractSelection vtkSelection @@ -84,8 +81,7 @@ private: class vtkSelectionNodeVector; void RequestDataInternal(vtkSelectionNodeVector& outputs, - vtkDataObject* dataObjectOutput, - vtkSelectionNode* sel); + vtkDataSet* geomOutput, vtkSelectionNode* sel); // Returns the combined content type for the selection. int GetContentType(vtkSelection* sel); diff --git a/Servers/Filters/vtkPVGeometryFilter.cxx b/Servers/Filters/vtkPVGeometryFilter.cxx index 13a956f..47d7333 100644 --- a/Servers/Filters/vtkPVGeometryFilter.cxx +++ b/Servers/Filters/vtkPVGeometryFilter.cxx @@ -14,10 +14,12 @@ =========================================================================*/ #include "vtkPVGeometryFilter.h" +#include "vtkAlgorithmOutput.h" #include "vtkAppendPolyData.h" #include "vtkCallbackCommand.h" #include "vtkCellArray.h" #include "vtkCellData.h" +#include "vtkCellTypes.h" #include "vtkCleanArrays.h" #include "vtkCommand.h" #include "vtkCompositeDataIterator.h" @@ -42,6 +44,7 @@ #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkPolygon.h" +#include "vtkPVRecoverGeometryWireframe.h" #include "vtkRectilinearGrid.h" #include "vtkRectilinearGridOutlineFilter.h" #include "vtkSmartPointer.h" @@ -52,14 +55,17 @@ #include "vtkTimerLog.h" #include "vtkUnsignedCharArray.h" #include "vtkUnsignedIntArray.h" -#include "vtkAlgorithmOutput.h" #include "vtkUnstructuredGrid.h" +#include "vtkUnstructuredGridGeometryFilter.h" #include <vtkstd/map> #include <vtkstd/vector> #include <vtkstd/string> #include <assert.h> +#define VTK_CREATE(type, name) \ + vtkSmartPointer<type> name = vtkSmartPointer<type>::New() + vtkCxxRevisionMacro(vtkPVGeometryFilter, "1.105"); vtkStandardNewMacro(vtkPVGeometryFilter); @@ -131,10 +137,13 @@ vtkPVGeometryFilter::vtkPVGeometryFilter () this->UseOutline = 1; this->UseStrips = 0; this->GenerateCellNormals = 1; + this->NonlinearSubdivisionLevel = 1; this->DataSetSurfaceFilter = vtkDataSetSurfaceFilter::New(); this->GenericGeometryFilter=vtkGenericGeometryFilter::New(); - + this->UnstructuredGridGeometryFilter=vtkUnstructuredGridGeometryFilter::New(); + this->RecoverWireframeFilter = vtkPVRecoverGeometryWireframe::New(); + // Setup a callback for the internal readers to report progress. this->InternalProgressObserver = vtkCallbackCommand::New(); this->InternalProgressObserver->SetCallback( @@ -162,13 +171,31 @@ vtkPVGeometryFilter::vtkPVGeometryFilter () //---------------------------------------------------------------------------- vtkPVGeometryFilter::~vtkPVGeometryFilter () { - if(this->DataSetSurfaceFilter) + // Be careful how you delete these so that you don't foul up the garbage + // collector. + if (this->DataSetSurfaceFilter) { - this->DataSetSurfaceFilter->Delete(); + vtkDataSetSurfaceFilter *tmp = this->DataSetSurfaceFilter; + this->DataSetSurfaceFilter = NULL; + tmp->Delete(); } - if(this->GenericGeometryFilter!=0) + if (this->GenericGeometryFilter) { - this->GenericGeometryFilter->Delete(); + vtkGenericGeometryFilter *tmp = this->GenericGeometryFilter; + this->GenericGeometryFilter = NULL; + tmp->Delete(); + } + if (this->UnstructuredGridGeometryFilter) + { + vtkUnstructuredGridGeometryFilter *tmp=this->UnstructuredGridGeometryFilter; + this->UnstructuredGridGeometryFilter = NULL; + tmp->Delete(); + } + if (this->RecoverWireframeFilter) + { + vtkPVRecoverGeometryWireframe *tmp = this->RecoverWireframeFilter; + this->RecoverWireframeFilter = NULL; + tmp->Delete(); } this->OutlineSource->Delete(); this->InternalProgressObserver->Delete(); @@ -1067,10 +1094,160 @@ void vtkPVGeometryFilter::UnstructuredGridExecute( if (!this->UseOutline) { this->OutlineFlag = 0; + + bool handleSubdivision = false; + if (this->NonlinearSubdivisionLevel > 0) + { + // Check to see if the data actually has nonlinear cells. Handling + // nonlinear cells adds unnecessary work if we only have linear cells. + vtkUnsignedCharArray *types = input->GetCellTypesArray(); + vtkIdType numCells = input->GetNumberOfCells(); + for (vtkIdType i = 0; i < numCells; i++) + { + if (!vtkCellTypes::IsLinear(types->GetValue(i))) + { + handleSubdivision = true; + break; + } + } + } + + vtkSmartPointer<vtkIdTypeArray> facePtIds2OriginalPtIds; + + if (handleSubdivision) + { + // Use the vtkUnstructuredGridGeometryFilter to extract 2D surface cells + // from the geometry. This is important to extract an appropriate + // wireframe in vtkPVRecoverGeometryWireframe. Also, at the time of this + // writing vtkDataSetSurfaceFilter only properly subdivides 2D cells past + // level 1. + VTK_CREATE(vtkUnstructuredGrid, inputClone); + inputClone->ShallowCopy(input); + this->UnstructuredGridGeometryFilter->SetInput(inputClone); + + // Let the vtkUnstructuredGridGeometryFilter record from which point and + // cell each face comes from in the standard vtkOriginalCellIds array. + this->UnstructuredGridGeometryFilter->SetPassThroughCellIds( + this->PassThroughCellIds); + this->UnstructuredGridGeometryFilter->SetPassThroughPointIds( + this->PassThroughPointIds); + + // Observe the progress of the internal filter. + // TODO: Make the consecutive internal filter execution have monotonically + // increasing progress rather than restarting for every internal filter. + this->UnstructuredGridGeometryFilter->AddObserver( + vtkCommand::ProgressEvent, + this->InternalProgressObserver); + this->UnstructuredGridGeometryFilter->Update(); + // The internal filter finished. Remove the observer. + this->UnstructuredGridGeometryFilter->RemoveObserver( + this->InternalProgressObserver); + + this->UnstructuredGridGeometryFilter->SetInput(NULL); + + // Feed the extracted surface as the input to the rest of the processing. + input->ShallowCopy(this->UnstructuredGridGeometryFilter->GetOutput()); + + // Keep a handle to the vtkOriginalPointIds array. We might need it. + facePtIds2OriginalPtIds = vtkIdTypeArray::SafeDownCast( + input->GetPointData()->GetArray("vtkOriginalPointIds")); + + // Flag the data set surface filter to record original cell ids, but do it + // in a specially named array that vtkPVRecoverGeometryWireframe will + // recognize. Note that because the data set comes from + // UnstructuredGridGeometryFilter, the ids will represent the faces rather + // than the original cells, which is important. + this->DataSetSurfaceFilter->PassThroughCellIdsOn(); + this->DataSetSurfaceFilter->SetOriginalCellIdsName( + vtkPVRecoverGeometryWireframe::ORIGINAL_FACE_IDS()); + + if (this->PassThroughPointIds) + { + if (this->NonlinearSubdivisionLevel <= 1) + { + // Do not allow the vtkDataSetSurfaceFilter create an array of + // original cell ids; it will overwrite the correct array from the + // vtkUnstructuredGridGeometryFilter. + this->DataSetSurfaceFilter->PassThroughPointIdsOff(); + } + else + { + // vtkDataSetSurfaceFilter is going to strip the vtkOriginalPointIds + // created by the vtkPVUnstructuredGridGeometryFilter because it + // cannot interpolate the ids. Make the vtkDataSetSurfaceFilter make + // its own original ids array. We will resolve them later. + this->DataSetSurfaceFilter->PassThroughPointIdsOn(); + } + } + } + if (input->GetNumberOfCells() > 0) { this->DataSetSurfaceFilter->UnstructuredGridExecute(input, output); } + + if (handleSubdivision) + { + // Restore state of DataSetSurfaceFilter. + this->DataSetSurfaceFilter->SetPassThroughCellIds( + this->PassThroughCellIds); + this->DataSetSurfaceFilter->SetOriginalCellIdsName(NULL); + this->DataSetSurfaceFilter->SetPassThroughPointIds( + this->PassThroughPointIds); + + // Now use vtkPVRecoverGeometryWireframe to create an edge flag attribute + // that will cause the wireframe to be rendered correctly. + VTK_CREATE(vtkPolyData, nextStageInput); + nextStageInput->ShallowCopy(output); // Yes output is correct. + this->RecoverWireframeFilter->SetInput(nextStageInput); + + // Observe the progress of the internal filter. + // TODO: Make the consecutive internal filter execution have monotonically + // increasing progress rather than restarting for every internal filter. + this->RecoverWireframeFilter->AddObserver( + vtkCommand::ProgressEvent, + this->InternalProgressObserver); + this->RecoverWireframeFilter->Update(); + // The internal filter finished. Remove the observer. + this->RecoverWireframeFilter->RemoveObserver( + this->InternalProgressObserver); + + this->RecoverWireframeFilter->SetInput(NULL); + + // Get what should be the final output. + output->ShallowCopy(this->RecoverWireframeFilter->GetOutput()); + + if (this->PassThroughPointIds && (this->NonlinearSubdivisionLevel > 1)) + { + // The output currently has a vtkOriginalPointIds array that maps points + // to the data containing only the faces. Correct this to point to the + // original data set. + vtkIdTypeArray *polyPtIds2FacePtIds = vtkIdTypeArray::SafeDownCast( + output->GetPointData()->GetArray("vtkOriginalPointIds")); + if (!facePtIds2OriginalPtIds || !polyPtIds2FacePtIds) + { + vtkErrorMacro(<< "Missing original point id arrays."); + return; + } + vtkIdType numPts = polyPtIds2FacePtIds->GetNumberOfTuples(); + VTK_CREATE(vtkIdTypeArray, polyPtIds2OriginalPtIds); + polyPtIds2OriginalPtIds->SetName("vtkOriginalPointIds"); + polyPtIds2OriginalPtIds->SetNumberOfComponents(1); + polyPtIds2OriginalPtIds->SetNumberOfTuples(numPts); + for (vtkIdType polyPtId = 0; polyPtId < numPts; polyPtId++) + { + vtkIdType facePtId = polyPtIds2FacePtIds->GetValue(polyPtId); + vtkIdType originalPtId = -1; + if (facePtId >= 0) + { + originalPtId = facePtIds2OriginalPtIds->GetValue(facePtId); + } + polyPtIds2OriginalPtIds->SetValue(polyPtId, originalPtId); + } + output->GetPointData()->AddArray(polyPtIds2OriginalPtIds); + } + } + return; } @@ -1193,6 +1370,10 @@ void vtkPVGeometryFilter::ReportReferences(vtkGarbageCollector* collector) "DataSetSurfaceFilter"); vtkGarbageCollectorReport(collector, this->GenericGeometryFilter, "GenericGeometryFilter"); + vtkGarbageCollectorReport(collector, this->UnstructuredGridGeometryFilter, + "UnstructuredGridGeometryFilter"); + vtkGarbageCollectorReport(collector, this->RecoverWireframeFilter, + "RecoverWireframeFilter"); } //---------------------------------------------------------------------------- @@ -1213,6 +1394,8 @@ void vtkPVGeometryFilter::PrintSelf(ostream& os, vtkIndent indent) os << indent << "UseStrips: " << (this->UseStrips?"on":"off") << endl; os << indent << "GenerateCellNormals: " << (this->GenerateCellNormals?"on":"off") << endl; + os << indent << "NonlinearSubdivisionLevel: " + << this->NonlinearSubdivisionLevel << endl; os << indent << "Controller: " << this->Controller << endl; os << indent << "PassThroughCellIds: " @@ -1306,3 +1489,20 @@ void vtkPVGeometryFilter::RemoveGhostCells(vtkPolyData* output) output->RemoveGhostCells(1); } } + +//----------------------------------------------------------------------------- +void vtkPVGeometryFilter::SetNonlinearSubdivisionLevel(int newvalue) +{ + if (this->NonlinearSubdivisionLevel != newvalue) + { + this->NonlinearSubdivisionLevel = newvalue; + + if (this->DataSetSurfaceFilter) + { + this->DataSetSurfaceFilter->SetNonlinearSubdivisionLevel( + this->NonlinearSubdivisionLevel); + } + + this->Modified(); + } +} diff --git a/Servers/Filters/vtkPVGeometryFilter.h b/Servers/Filters/vtkPVGeometryFilter.h index f9e4485..9fb7be2 100644 --- a/Servers/Filters/vtkPVGeometryFilter.h +++ b/Servers/Filters/vtkPVGeometryFilter.h @@ -34,9 +34,11 @@ class vtkInformationVector; class vtkCompositeDataSet; class vtkMultiProcessController; class vtkOutlineSource; +class vtkPVRecoverGeometryWireframe; class vtkRectilinearGrid; class vtkStructuredGrid; class vtkUnstructuredGrid; +class vtkUnstructuredGridGeometryFilter; class VTK_EXPORT vtkPVGeometryFilter : public vtkPolyDataAlgorithm { @@ -79,6 +81,15 @@ public: vtkBooleanMacro(GenerateCellNormals, int); // Description: + // Nonlinear faces are approximated with flat polygons. This parameter + // controls how many times to subdivide nonlinear surface cells. Higher + // subdivisions generate closer approximations but take more memory and + // rendering time. Subdivision is recursive, so the number of output polygons + // can grow exponentially with this parameter. + virtual void SetNonlinearSubdivisionLevel(int); + vtkGetMacro(NonlinearSubdivisionLevel, int); + + // Description: // Set and get the controller. virtual void SetController(vtkMultiProcessController*); vtkGetObjectMacro(Controller, vtkMultiProcessController); @@ -159,11 +170,14 @@ protected: int UseOutline; int UseStrips; int GenerateCellNormals; + int NonlinearSubdivisionLevel; vtkMultiProcessController* Controller; vtkOutlineSource *OutlineSource; vtkDataSetSurfaceFilter* DataSetSurfaceFilter; vtkGenericGeometryFilter *GenericGeometryFilter; + vtkUnstructuredGridGeometryFilter *UnstructuredGridGeometryFilter; + vtkPVRecoverGeometryWireframe *RecoverWireframeFilter; int CheckAttributes(vtkDataObject* input); diff --git a/Servers/Filters/vtkPVIsoVolume.cxx b/Servers/Filters/vtkPVIsoVolume.cxx new file mode 100644 index 0000000..e7b235c --- /dev/null +++ b/Servers/Filters/vtkPVIsoVolume.cxx @@ -0,0 +1,97 @@ +#include "vtkPVIsoVolume.h" + +#include "vtkHierarchicalBoxDataSet.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkMultiBlockDataSet.h" +#include "vtkObjectFactory.h" + +#include "vtkCompositeDataIterator.h" + +#include <vtkstd/string> // STL required. +#include <vtkstd/vector> // STL required. + +vtkCxxRevisionMacro(vtkPVIsoVolume, "1.1"); +vtkStandardNewMacro(vtkPVIsoVolume); + +const double PV_AMR_SURFACE_VALUE_UNSIGNED_CHAR=255; + +//----------------------------------------------------------------------------- +class vtkPVIsoVolumeInternal +{ +public: + + vtkstd::vector<vtkstd::string> CellArrays; +}; + +//----------------------------------------------------------------------------- +vtkPVIsoVolume::vtkPVIsoVolume() : + vtkAMRDualClip(), + VolumeFractionSurfaceValue(1.0) +{ + this->Implementation = new vtkPVIsoVolumeInternal(); +} + +//----------------------------------------------------------------------------- +vtkPVIsoVolume::~vtkPVIsoVolume() +{ + if(this->Implementation) + { + delete this->Implementation; + this->Implementation = 0; + } +} + +//----------------------------------------------------------------------------- +void vtkPVIsoVolume::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +//----------------------------------------------------------------------------- +int vtkPVIsoVolume::RequestData(vtkInformation* vtkNotUsed(request), + vtkInformationVector** inputVector, + vtkInformationVector* outputVector) +{ + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + vtkHierarchicalBoxDataSet* hbdsInput=vtkHierarchicalBoxDataSet::SafeDownCast( + inInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkInformation *outInfo; + outInfo = outputVector->GetInformationObject(0); + vtkMultiBlockDataSet* mbdsOutput0 = vtkMultiBlockDataSet::SafeDownCast( + outInfo->Get(vtkDataObject::DATA_OBJECT())); + + + this->SetIsoValue(this->VolumeFractionSurfaceValue * + PV_AMR_SURFACE_VALUE_UNSIGNED_CHAR); + + size_t noOfArrays = this->Implementation->CellArrays.size(); + for(size_t i=0; i < noOfArrays; ++i) + { + vtkMultiBlockDataSet* out = this->DoRequestData( + hbdsInput, this->Implementation->CellArrays[i].c_str()); + + if(out) + { + /// Assign the name to the block by the array name. + mbdsOutput0->SetBlock(i, out); + out->Delete(); + } + } + return 1; +} + +//----------------------------------------------------------------------------- +void vtkPVIsoVolume::AddInputCellArrayToProcess(const char* name) +{ + this->Implementation->CellArrays.push_back(vtkstd::string(name)); + this->Modified(); +} + +//----------------------------------------------------------------------------- +void vtkPVIsoVolume::ClearInputCellArrayToProcess() +{ + this->Implementation->CellArrays.clear(); + this->Modified(); +} diff --git a/Servers/Filters/vtkPVIsoVolume.h b/Servers/Filters/vtkPVIsoVolume.h new file mode 100644 index 0000000..029c58c --- /dev/null +++ b/Servers/Filters/vtkPVIsoVolume.h @@ -0,0 +1,68 @@ +/*========================================================================= + + Program: ParaView + Module: vtkPVIsoVolume.h + + Copyright (c) Kitware, Inc. + All rights reserved. + See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +// .NAME vtkPVIsoVolume - Generates contour given one or more cell array +// and a volume fraction value. +// +// .SECTION Description +// +// .SEE vtkAMRDualClip +// + +#ifndef __vtkPVIsoVolume_h +#define __vtkPVIsoVolume_h + +#include "vtkAMRDualClip.h" + +// Forware declaration. +class vtkPVIsoVolumeInternal; + +class VTK_EXPORT vtkPVIsoVolume : public vtkAMRDualClip +{ +public: + static vtkPVIsoVolume* New(); + vtkTypeRevisionMacro(vtkPVIsoVolume,vtkAMRDualClip); + void PrintSelf(ostream& os, vtkIndent indent); + + vtkPVIsoVolume(); + ~vtkPVIsoVolume(); + + // Description: + // Add to list of cell arrays which are used for generating contours. + void AddInputCellArrayToProcess(const char* name); + void ClearInputCellArrayToProcess(); + + // Description: + // Get / Set volume fraction value. + vtkGetMacro(VolumeFractionSurfaceValue, double); + vtkSetMacro(VolumeFractionSurfaceValue, double); + + //BTX + virtual int RequestData(vtkInformation*, vtkInformationVector**, + vtkInformationVector*); + +private: + vtkPVIsoVolume(const vtkPVIsoVolume&); // Not implemented. + void operator=(const vtkPVIsoVolume&); // Not implemented. + + //ETX + +protected: + + double VolumeFractionSurfaceValue; + + vtkPVIsoVolumeInternal* Implementation; +}; + +#endif // __vtkPVIsoVolume_h diff --git a/Servers/Filters/vtkPVRecoverGeometryWireframe.cxx b/Servers/Filters/vtkPVRecoverGeometryWireframe.cxx new file mode 100644 index 0000000..acc35f3 --- /dev/null +++ b/Servers/Filters/vtkPVRecoverGeometryWireframe.cxx @@ -0,0 +1,308 @@ +// -*- c++ -*- +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: pqBlotDialog.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*------------------------------------------------------------------------- + Copyright 2009 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, + the U.S. Government retains certain rights in this software. +-------------------------------------------------------------------------*/ + +#include "vtkPVRecoverGeometryWireframe.h" + +#include "vtkCellArray.h" +#include "vtkCellData.h" +#include "vtkIdTypeArray.h" +#include "vtkObjectFactory.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" +#include "vtkUnsignedCharArray.h" + +#include "vtkSmartPointer.h" +#define VTK_CREATE(type, name) \ + vtkSmartPointer<type> name = vtkSmartPointer<type>::New() + +#include <vtkstd/algorithm> +#include <vtkstd/vector> +#include <vtksys/hash_map.hxx> + +static const unsigned char NO_EDGE_FLAG = static_cast<unsigned char >(-1); + +//============================================================================= +namespace vtkPVRecoverGeometryWireframeNamespace +{ + // Description: + // Simple class used internally to define an edge based on the endpoints. The + // endpoints are canonically identified by the lower and higher values. + class EdgeEndpoints + { + public: + EdgeEndpoints() : MinEndPoint(-1), MaxEndPoint(-1) {} + EdgeEndpoints(vtkIdType endpointA, vtkIdType endpointB) + : MinEndPoint((endpointA < endpointB) ? endpointA : endpointB), + MaxEndPoint((endpointA < endpointB) ? endpointB : endpointA) + {} + const vtkIdType MinEndPoint; + const vtkIdType MaxEndPoint; + inline bool operator==(const EdgeEndpoints &other) const { + return ( (this->MinEndPoint == other.MinEndPoint) + && (this->MaxEndPoint == other.MaxEndPoint) ); + } + }; + struct EdgeEndpointsHash { + public: + size_t operator()(const EdgeEndpoints &edge) const { + return static_cast<size_t>(edge.MinEndPoint + edge.MaxEndPoint); + } + }; + + // Description: + // Holds the information necessary for the facet this edge came from. + class EdgeInformation + { + public: + vtkIdType OriginalFaceId; + vtkIdType *StartPointIdP; + }; + + // Description: + // A map from edge endpoints to the information about that edge. + typedef vtksys::hash_map<EdgeEndpoints, EdgeInformation, EdgeEndpointsHash> + EdgeMapType; + + void RecordEdgeFlag(vtkPolyData *output, const EdgeInformation &edgeInfo, + vtkUnsignedCharArray *edgeFlagArray, unsigned char flag, + vtkIdType *duplicatePointMap) + { + vtkIdType pt = edgeInfo.StartPointIdP[0]; + if (edgeFlagArray->GetValue(pt) == flag) + { + // Edge flag already set correctly. Nothing to do. + return; + } + if (edgeFlagArray->GetValue(pt) == NO_EDGE_FLAG) + { + // Nothing has set the edge flag yet. Just set it and return. + edgeFlagArray->SetValue(pt, flag); + return; + } + + // If we are here then some other cell has already put a flag on this + // point different than ours. We have to adjust our cell topology to + // use a duplicate point. + if (duplicatePointMap[pt] == -1) + { + // No duplicate made. We need to make one. + vtkPoints *points = output->GetPoints(); + double coords[3]; + points->GetPoint(pt, coords); + vtkIdType newPt = points->InsertNextPoint(coords); + duplicatePointMap[pt] = newPt; + // Copying attributes from yourself seems weird, but is valid. + vtkPointData *pd = output->GetPointData(); + pd->CopyData(pd, pt, newPt); + edgeFlagArray->InsertValue(newPt, flag); + } + edgeInfo.StartPointIdP[0] = duplicatePointMap[pt]; + } +} +using namespace vtkPVRecoverGeometryWireframeNamespace; + +//============================================================================= +vtkCxxRevisionMacro(vtkPVRecoverGeometryWireframe, "$Revision$"); +vtkStandardNewMacro(vtkPVRecoverGeometryWireframe); + +//----------------------------------------------------------------------------- +vtkPVRecoverGeometryWireframe::vtkPVRecoverGeometryWireframe() +{ +} + +vtkPVRecoverGeometryWireframe::~vtkPVRecoverGeometryWireframe() +{ +} + +void vtkPVRecoverGeometryWireframe::PrintSelf(ostream &os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +//----------------------------------------------------------------------------- +int vtkPVRecoverGeometryWireframe::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + vtkPolyData *input = vtkPolyData::GetData(inputVector[0]); + vtkPolyData *output = vtkPolyData::GetData(outputVector); + + vtkIdType npts, *pts; + vtkstd::vector<vtkIdType> originalPts; + + if (!input->GetCellData()->HasArray(ORIGINAL_FACE_IDS())) + { + // Did not find the field used to identify the face each linear patch comes + // from. The original data was probably linear so using all the edges + // should be OK (and is at least the best we can do), so just pass the data. + output->ShallowCopy(input); + return 1; + } + + vtkIdTypeArray *faceIds = vtkIdTypeArray::SafeDownCast( + input->GetCellData()->GetAbstractArray(ORIGINAL_FACE_IDS())); + if (!faceIds) + { + vtkErrorMacro(<< ORIGINAL_FACE_IDS() << " array is not of expected type."); + return 0; + } + + // Shallow copy the cell data. All the cells get copied to output. + output->GetCellData()->PassData(input->GetCellData()); + + // Deep copy the point information and be ready to add points. + VTK_CREATE(vtkPoints, points); + points->DeepCopy(input->GetPoints()); + output->SetPoints(points); + vtkPointData *inputPD = input->GetPointData(); + vtkPointData *outputPD = output->GetPointData(); + outputPD->CopyAllocate(inputPD); + vtkIdType numOriginalPoints = points->GetNumberOfPoints(); + for (vtkIdType i = 0; i < numOriginalPoints; i++) + { + outputPD->CopyData(inputPD, i, i); + } + + // Create an edge flag array. + VTK_CREATE(vtkUnsignedCharArray, edgeflags); + edgeflags->SetName("vtkEdgeFlags"); + outputPD->AddArray(edgeflags); + outputPD->SetActiveAttribute("vtkEdgeFlags", vtkDataSetAttributes::EDGEFLAG); + edgeflags->SetNumberOfComponents(1); + edgeflags->SetNumberOfTuples(numOriginalPoints); + vtkstd::fill(edgeflags->GetPointer(0), + edgeflags->GetPointer(numOriginalPoints), NO_EDGE_FLAG); + + // Some (probably many) points will have to be duplicated because different + // cells will need different edge flags. This array maps the original + // point id to the duplicate id. + vtkstd::vector<vtkIdType> duplicatePointMap(numOriginalPoints); + vtkstd::fill(duplicatePointMap.begin(), duplicatePointMap.end(), -1); + + // Shallow copy the verts. Set the edge flags to true. + vtkCellArray *inputVerts = input->GetVerts(); + output->SetVerts(inputVerts); + for (inputVerts->InitTraversal(); inputVerts->GetNextCell(npts, pts); ) + { + for (vtkIdType i = 0; i < npts; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Shallow copy the lines. Set the edge flags to true. + vtkCellArray *inputLines = input->GetLines(); + output->SetLines(inputLines); + for (inputLines->InitTraversal(); inputLines->GetNextCell(npts, pts); ) + { + // No need to set edge flag for last index. + for (vtkIdType i = 0; i < npts-1; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Shallow copy the triangle strips. Set the edge flags to true. + vtkCellArray *inputStrips = input->GetStrips(); + output->SetStrips(inputStrips); + for (inputStrips->InitTraversal(); inputStrips->GetNextCell(npts, pts); ) + { + for (vtkIdType i = 0; i < npts; i++) + { + edgeflags->SetValue(pts[i], 1); + } + } + + // Deep copy the polygons because we will be changing some indices when we + // duplicate points. + VTK_CREATE(vtkCellArray, outputPolys); + outputPolys->DeepCopy(input->GetPolys()); + output->SetPolys(outputPolys); + + // Iterate over all the input facets and see which edge interfaces belonged to + // different faces. We do that by recording the original face id in a map. + // When we find a pair of edges, we turn on the appropriate edge flag if they + // came from different faces, or turn it off if they came from the same face. + EdgeMapType edgeMap; + vtkIdType inputCellId + = inputVerts->GetNumberOfCells() + inputLines->GetNumberOfCells(); + for (outputPolys->InitTraversal(); outputPolys->GetNextCell(npts, pts); + inputCellId++) + { + if ((inputCellId%1000) == 0) + { + this->UpdateProgress(static_cast<double>(inputCellId) + /input->GetNumberOfCells()); + if (this->GetAbortExecute()) return 0; + } + // Record the original points of the polygon. As we iterate over edges, + // we may change the indices, but we allways compare edges by the original + // indices. + originalPts.resize(npts); + vtkstd::copy(pts, pts+npts, originalPts.begin()); + vtkIdType originalFace = faceIds->GetValue(inputCellId); + for (vtkIdType i = 0; i < npts; i++) + { + EdgeEndpoints edge(originalPts[i], originalPts[(i+1)%npts]); + EdgeInformation edgeInfo; + edgeInfo.OriginalFaceId = originalFace; + edgeInfo.StartPointIdP = &pts[i]; + + EdgeMapType::iterator edgeMatch = edgeMap.find(edge); + if (edgeMatch == edgeMap.end()) + { + // Not encountered yet. Add to the map. + edgeMap.insert(vtkstd::make_pair(edge, edgeInfo)); + } + else + { + // The edge flag is true if the edge connects two different faces. + unsigned char eflag = static_cast<unsigned char>( + edgeMatch->second.OriginalFaceId != originalFace); + RecordEdgeFlag(output, edgeMatch->second, edgeflags, eflag, + &duplicatePointMap.at(0)); + RecordEdgeFlag(output, edgeInfo, edgeflags, eflag, + &duplicatePointMap.at(0)); + // Remove the edge from the map since we already found the pair. + edgeMap.erase(edgeMatch); + } + } // For each edge + } // For each cell. + + // Everything left in the edge map has no match. It must necessarily be + // on the outside of a face. + for (EdgeMapType::iterator iter = edgeMap.begin(); + iter != edgeMap.end(); iter++) + { + RecordEdgeFlag(output, iter->second, edgeflags, 1, + &duplicatePointMap.at(0)); + } + + // If any points are unmarked, set some edge flag on them (although they + // are probably not referenced by any cell). + for (vtkIdType i = 0; i < numOriginalPoints; i++) + { + if (edgeflags->GetValue(i) == NO_EDGE_FLAG) edgeflags->SetValue(i, 1); + } + + return 1; +} diff --git a/Servers/Filters/vtkPVRecoverGeometryWireframe.h b/Servers/Filters/vtkPVRecoverGeometryWireframe.h new file mode 100644 index 0000000..6d1d569 --- /dev/null +++ b/Servers/Filters/vtkPVRecoverGeometryWireframe.h @@ -0,0 +1,73 @@ +// -*- c++ -*- +/*========================================================================= + + Program: Visualization Toolkit + Module: $RCSfile: pqBlotDialog.h,v $ + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/*------------------------------------------------------------------------- + Copyright 2009 Sandia Corporation. + Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, + the U.S. Government retains certain rights in this software. +-------------------------------------------------------------------------*/ + +// .NAME vtkPVRecoverGeometryWireframe - Get corrected wireframe from tesselated facets +// +// .SECTION Description +// +// When vtkPVGeometryFilter tessellates nonlinear faces into linear +// approximations, it introduces edges in the middle of the facets of the +// original mesh (as any valid tessellation would). To correct for this, +// vtkPVGeometryFilter also writes out some fields that allows use to identify +// the edges that are actually part of the original mesh. This filter works in +// conjunction with vtkPVGeometryFilter by taking its output, adding an edge +// flag and making the appropriate adjustments so that rendering with line +// fill mode will make the correct wireframe. +// +// .SECTION See Also +// vtkPVGeometryFilter +// + +#ifndef __vtkPVRecoverGeometryWireframe_h +#define __vtkPVRecoverGeometryWireframe_h + +#include "vtkPolyDataAlgorithm.h" + +class VTK_EXPORT vtkPVRecoverGeometryWireframe : public vtkPolyDataAlgorithm +{ +public: + vtkTypeRevisionMacro(vtkPVRecoverGeometryWireframe, vtkPolyDataAlgorithm); + static vtkPVRecoverGeometryWireframe *New(); + virtual void PrintSelf(ostream &os, vtkIndent indent); + + // Description: + // In order to determine which edges existed in the original data, we need an + // identifier on each cell determining which face (not cell) it originally + // came from. The ids should be put in a cell data array with this name. The + // existance of this field is also a signal that this wireframe extraction is + // necessary. + static const char *ORIGINAL_FACE_IDS() + { return "vtkPVRecoverWireframeOriginalFaceIds"; } + +protected: + vtkPVRecoverGeometryWireframe(); + ~vtkPVRecoverGeometryWireframe(); + + virtual int RequestData(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector); + +private: + vtkPVRecoverGeometryWireframe(const vtkPVRecoverGeometryWireframe &); // Not implemented + void operator=(const vtkPVRecoverGeometryWireframe &); // Not implemented +}; + +#endif //__vtkPVRecoverGeometryWireframe_h diff --git a/Servers/ServerManager/Resources/filters.xml b/Servers/ServerManager/Resources/filters.xml index 9b92034..efd7835 100644 --- a/Servers/ServerManager/Resources/filters.xml +++ b/Servers/ServerManager/Resources/filters.xml @@ -1545,6 +1545,26 @@ The Extract Surface filter extracts the polygons forming the outer surface of th If the value of this property is set to 1, internal surfaces along process boundaries will be removed. NOTE: Enabling this option might cause multiple executions of the data source because more information is needed to remove internal surfaces. </Documentation> </IntVectorProperty> + + <IntVectorProperty name="NonlinearSubdivisionLevel" + command="SetNonlinearSubdivisionLevel" + number_of_elements="1" + default_values="1"> + <IntRangeDomain name="range" min="0" max="4" /> + <Documentation> + If the input is an unstructured grid with nonlinear faces, this + parameter determines how many times the face is subdivided into + linear faces. If 0, the output is the equivalent of its linear + couterpart (and the midpoints determining the nonlinear + interpolation are discarded). If 1, the nonlinear face is + triangulated based on the midpoints. If greater than 1, the + triangulated pieces are recursively subdivided to reach the + desired subdivision. Setting the value to greater than 1 may + cause some point data to not be passed even if no quadratic faces + exist. This option has no effect if the input is not an + unstructured grid. + </Documentation> + </IntVectorProperty> <!-- End DataSetSurfaceFilter --> </SourceProxy> @@ -2086,7 +2106,7 @@ attributes of the fragments. </SourceProxy> <!-- ==================================================================== --> - <!--<SourceProxy name="AMRDualClip" class="vtkAMRDualClip" + <SourceProxy name="AMRDualClip" class="vtkAMRDualClip" label="AMR Clip"> <Documentation short_help="Clip with decimation." @@ -2176,10 +2196,11 @@ attributes of the fragments. Use more memory to merge points on the boundaries of blocks. </Documentation> </IntVectorProperty> - </SourceProxy>--> + <!-- End AMR Dual Clip --> + </SourceProxy> <!-- ==================================================================== --> - <SourceProxy name="AMRDualClip" class="vtkPVAMRDualClip" label="AMR Dual Clip"> + <SourceProxy name="IsoVolume" class="vtkPVIsoVolume" label="Iso Volume"> <Documentation short_help="Clip with decimation." long_help="Clip with scalars. Tetrahedra."> @@ -7364,6 +7385,20 @@ Tessellate a higher-order dataset. Toggle whether to generate an outline or a surface. </Documentation> </IntVectorProperty> + <IntVectorProperty name="NonlinearSubdivisionLevel" + command="SetNonlinearSubdivisionLevel" + number_of_elements="1" + default_values="1"> + <IntRangeDomain name="range" min="0" max="4" /> + <Documentation> + Nonlinear faces are approximated with flat polygons. This + parameter controls how many times to subdivide nonlinear surface + cells. Higher subdivisions generate closer approximations but + take more memory and rendering time. Subdivision is recursive, + so the number of output polygons can grow exponentially with this + parameter. + </Documentation> + </IntVectorProperty> <IntVectorProperty name="PassThroughIds" command="SetPassThroughCellIds" diff --git a/Servers/ServerManager/Resources/rendering.xml b/Servers/ServerManager/Resources/rendering.xml index c5cf4eb..8d019f7 100644 --- a/Servers/ServerManager/Resources/rendering.xml +++ b/Servers/ServerManager/Resources/rendering.xml @@ -7118,7 +7118,7 @@ <SubProxy> <!-- - Geometry filter is used to conver non-polydata input to polydata. + Geometry filter is used to convert non-polydata input to polydata. It is also used to convert poly data to triangle strips when requested. --> @@ -7127,6 +7127,7 @@ <ExposedProperties> <Property name="UseStrips" /> <Property name="ForceStrips" /> + <Property name="NonlinearSubdivisionLevel" /> </ExposedProperties> </SubProxy> @@ -7992,6 +7993,7 @@ <!-- Geometry Filter properties --> <Property name="UseStrips" /> <Property name="ForceStrips" /> + <Property name="NonlinearSubdivisionLevel" /> <!-- Mapper properties --> <Property name="LookupTable" /> diff --git a/Servers/ServerManager/Resources/utilities.xml b/Servers/ServerManager/Resources/utilities.xml index b25bbb3..0b02b60 100644 --- a/Servers/ServerManager/Resources/utilities.xml +++ b/Servers/ServerManager/Resources/utilities.xml @@ -460,7 +460,7 @@ name="Bounds" command="SetBounds" number_of_elements="6" - default_values="0 1 0 1 0 1" > + default_values="none" > </DoubleVectorProperty> <DoubleVectorProperty name="Position" diff --git a/Servers/ServerManager/Testing/Python/PythonSMTraceTest2.py b/Servers/ServerManager/Testing/Python/PythonSMTraceTest2.py index 6494d9b..dc43f98 100644 --- a/Servers/ServerManager/Testing/Python/PythonSMTraceTest2.py +++ b/Servers/ServerManager/Testing/Python/PythonSMTraceTest2.py @@ -73,24 +73,18 @@ glyph = FindSource("my glyph") clip = FindSource("my clip") group = FindSource("my group") -print "background:", view.Background -print "background2:", view2.Background -print "representations:", view.Representations -print "representations2:", view2.Representations - # Test the results -epsilon = 0.000001 if not sphere: fail("Could not find sphere") if glyph.GlyphType.Resolution != 15: fail("Glyph cone resolution is incorrect.") -if abs(clip.ClipType.Radius - 0.25) > epsilon: +if abs(clip.ClipType.Radius - 0.25) > 0.000001: fail("Clip sphere radius is incorrect.") if sphere not in group.Input or clip not in group.Input: fail("Group has wrong inputs.") if GetDisplayProperties(group).Representation != "Surface With Edges": fail("Group representation is incorrect") -if abs(view.Background[1] - 0) > epsilon or abs(view.Background[2] - 1) > epsilon: +if view.Background[1] != 0 or view.Background[2] != 1: fail("View has incorrect background color") if len(view.Representations) != 1: fail("First view has incorrect number of representations.") diff --git a/VTK b/VTK index 46a8f04..2d1be1b 160000 --- a/VTK +++ b/VTK @@ -1 +1 @@ -Subproject commit 46a8f04a3d6084d18136ac6e51c3eb2685907497 +Subproject commit 2d1be1be9bf769839685a2205ecf34a4f19cb660 | ||||||||
Relationships | ||||||||||||||||
|
Relationships |
Notes | |
(0016700) Ken Moreland (manager) 2009-06-10 18:29 |
I've attached a patch that I think gets through about 75% of the work. It subdivides nonlinear faces to a chosen level (really bug 0009132) and then extracts an appropriate wireframe for the tessellated faces. There is some wiring to fix up (it does the wireframe all the time right now), but that should not be too hard. The part that I am struggling with is how to show only the "front" facing lines. |
(0016719) Ken Moreland (manager) 2009-06-12 16:11 |
The latest patch (NonlinearSubdivisions6.patch) mostly resolves the problem. Rendering wireframe with edges mode works pretty well. Simple wireframe mode is still showing all edges (not sure why). The approach is slightly different than that in the previous patch. To get rid of the extra edges, an edge flag is added to the point data. I had to change some painter code to support edge flags (which are supported by OpenGL 1.1). Selecting nonlinear cells is also broken in this patch. |
(0019272) Ken Moreland (manager) 2010-01-22 12:06 |
The work is done! Because the changes touch some core classes, I am waiting for someone at Kitware to review the changes. I am assigning this bug to Utkarsh so that he can review the changes. When/if he approves them, he can assign the bug back to me and I will check in the code. The latest patch, NonlinearSubdivisions9.patch, contains all the necessary changes. I also have the code waiting in a github repository if that is easier. The URL for the repository is <git://github.com/kmorel/ParaView.git> [^] and the change is in the branch <NonlinearSurface>. You can see a summary on this github.com page. http://github.com/kmorel/ParaView/tree/NonlinearSurface [^] |
(0020339) Ken Moreland (manager) 2010-04-21 17:09 |
Due to the transition from CVS to git and other changes to files, I have uploaded new patches. Because ParaView and VTK are now separate modules and the changes span both, I have attached a separate patch for each of them. I have also created new repositories on github for direct git access. http://github.com/kmorel/VTK-NonlinearSurface [^] http://github.com/kmorel/ParaView-NonlinearSurface [^] |
(0020368) Ken Moreland (manager) 2010-04-22 20:09 |
Odd. I must have done a diff against the wrong git commit the last time I made the patches. Attached are new versions. Also including VTK_POLYHEDRON as a linear cell type. |
(0020430) Ken Moreland (manager) 2010-04-27 12:54 |
Pushed changes to the central repository. VTK commits: http://vtk.org/gitweb?p=VTK.git;a=commit;h=175efdc2937b89cef01f10cc6fbd0f2b3c1e313f [^] http://vtk.org/gitweb?p=VTK.git;a=commit;h=b1778f69d6c38b828f7e28d7d43662084a15d320 [^] ParaView commits: http://paraview.org/gitweb?p=ParaView.git;a=commit;h=61f83397853c4a4c351ca8168e6d978b953b50e0 [^] |
(0020573) Alan Scott (manager) 2010-05-04 20:02 |
Tested local server, trunk, Windows. |
Notes |
Issue History | |||
Date Modified | Username | Field | Change |
2009-06-10 13:56 | Ken Moreland | New Issue | |
2009-06-10 13:56 | Ken Moreland | Status | backlog => tabled |
2009-06-10 13:56 | Ken Moreland | Assigned To | => Ken Moreland |
2009-06-10 13:56 | Ken Moreland | Relationship added | related to 0009132 |
2009-06-10 18:26 | Ken Moreland | File Added: NonlinearSubdivisions4.patch | |
2009-06-10 18:29 | Ken Moreland | Note Added: 0016700 | |
2009-06-12 15:08 | Ken Moreland | File Added: NonlinearSubdivisions6.patch | |
2009-06-12 16:11 | Ken Moreland | Note Added: 0016719 | |
2010-01-22 12:02 | Ken Moreland | File Added: NonlinearSubdivisions9.patch | |
2010-01-22 12:02 | Ken Moreland | Assigned To | Ken Moreland => Utkarsh Ayachit |
2010-01-22 12:06 | Ken Moreland | Note Added: 0019272 | |
2010-02-04 13:03 | Utkarsh Ayachit | Priority | normal => immediate |
2010-02-10 09:34 | Utkarsh Ayachit | Assigned To | Utkarsh Ayachit => Berk Geveci |
2010-03-01 10:27 | Utkarsh Ayachit | Assigned To | Berk Geveci => Will Schroeder |
2010-04-21 17:03 | Ken Moreland | File Added: NonlinearSurface10.VTK.patch | |
2010-04-21 17:03 | Ken Moreland | File Added: NonlinearSurface10.ParaView.patch | |
2010-04-21 17:09 | Ken Moreland | Note Added: 0020339 | |
2010-04-22 20:07 | Ken Moreland | File Added: NonlinearSurface11.VTK.patch | |
2010-04-22 20:08 | Ken Moreland | File Added: NonlinearSurface11.ParaView.patch | |
2010-04-22 20:09 | Ken Moreland | Note Added: 0020368 | |
2010-04-27 12:52 | Ken Moreland | Assigned To | Will Schroeder => Ken Moreland |
2010-04-27 12:54 | Ken Moreland | Note Added: 0020430 | |
2010-04-27 12:54 | Ken Moreland | Status | tabled => @80@ |
2010-04-27 12:54 | Ken Moreland | Fixed in Version | => 3.10 |
2010-04-27 12:54 | Ken Moreland | Resolution | open => fixed |
2010-05-04 20:02 | Alan Scott | Note Added: 0020573 | |
2010-05-04 20:02 | Alan Scott | Status | @80@ => closed |
2010-05-05 10:24 | Ken Moreland | Relationship added | related to 0010676 |
2010-05-05 10:29 | Ken Moreland | Relationship added | related to 0010677 |
Issue History |
Copyright © 2000 - 2018 MantisBT Team |