Commit b4d44ee9 authored by Scott Wittenburg's avatar Scott Wittenburg

Move the point gaussian representation into ParaView core.

Also add a new Python test of the representation that attempts to
exercise many of the features.  In addition, update pwf editor to
work better for the point gaussian representation, by adding X
range edit fields to the widget so that the user is not stuck
with X in [0, 1].  The change also ensures that user changes to
the piecewise function are propagated to the SMProperty on the
proxy, which was not the case before.
parent 63e1bd8d
Pipeline #1783 passed with stage
......@@ -48,6 +48,14 @@ paraview_add_test_python(
TestClipCylinder.py
)
# This test makes use of "Point Gaussian" representation, only available with OpenGL2
if("${VTK_RENDERING_BACKEND}" STREQUAL "OpenGL2")
paraview_add_test_python(
NO_DATA NO_RT
PointGaussianProperties.py
)
endif()
paraview_add_test_pvbatch(
NO_DATA NO_RT
CinemaTest.py
......
import os, sys
from paraview import simple
from vtkPVServerManagerRenderingPython import *
from vtk import *
NUM_POINTS = 5
### Create the geometry
points = vtkPoints()
points.SetNumberOfPoints(NUM_POINTS)
for i in xrange(NUM_POINTS):
points.SetPoint(i, i, 0.0, 0.0)
verts = vtkCellArray()
verts.InsertNextCell(NUM_POINTS)
for i in xrange(NUM_POINTS):
verts.InsertCellPoint(i)
polyData = vtkPolyData()
polyData.SetPoints(points)
polyData.SetVerts(verts)
### Create some point data
pointData = polyData.GetPointData();
# Set up a data array containing the point ordinal values
ordinalArrayName = "Ordinal";
ordinalRange = [ 0, NUM_POINTS - 1 ]
ordinalArray = vtkDoubleArray()
ordinalArray.SetName(ordinalArrayName);
ordinalArray.SetNumberOfComponents(1);
ordinalArray.SetNumberOfTuples(NUM_POINTS);
for i in xrange(NUM_POINTS):
ordinalArray.SetTuple1(i, i)
pointData.AddArray(ordinalArray)
source = simple.TrivialProducer()
source.GetClientSideObject().SetOutput(polyData)
# create a calculator to compute distance
calculator1 = simple.Calculator(Input=source)
calculator1.ResultArrayName = 'Distance'
calculator1.Function = 'mag(coords)'
# create another calculator to compute inverse distance
calculator2 = simple.Calculator(Input=calculator1)
calculator2.ResultArrayName = 'Inverse Distance'
calculator2.Function = '%s-Distance' % str(NUM_POINTS - 1)
# Get the representation
rep = simple.Show(calculator2)
# Set up coloring by one array
rep.Representation = 'Point Gaussian'
simple.ColorBy(rep, ('POINTS', 'Ordinal'))
vtkSMPVRepresentationProxy.RescaleTransferFunctionToDataRange(rep.SMProxy, 'Ordinal', 0, False)
# Set up sizing by another array
scaleTransferFunction = simple.CreatePiecewiseFunction(Points=[0.0, 0.05, 0.5, 0.0, NUM_POINTS - 1, 0.15, 0.5, 0.0])
rep.ScaleTransferFunction = scaleTransferFunction
rep.SetScaleArray = 'Distance'
rep.ScaleByArray = 1
rep.GaussianRadius = 1
# And finally, set up opacity by a third array
opacityTransferFunction = simple.CreatePiecewiseFunction(Points=[0.0, 0.2, 0.5, 0.0, NUM_POINTS - 1, 1.0, 0.5, 0.0])
rep.OpacityTransferFunction = opacityTransferFunction
rep.OpacityArray = 'Inverse Distance'
rep.OpacityByArray = 1
# Now set a custom shader snippet
rep.CustomShader = '''
//VTK::Color::Impl
float dist = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);
if (dist > 9.0) {
discard;
}
'''
# Now render, configure the view, and re-render
renderView = simple.Render()
renderView.CenterOfRotation = [ (NUM_POINTS - 1) / 2.0 , 0, 0 ]
renderView.CameraPosition = [ (NUM_POINTS - 1) / 2.0 , 0, NUM_POINTS * 2 ]
renderView.CameraFocalPoint = [ (NUM_POINTS - 1) / 2.0 , 0, 0 ]
renderView.CameraViewAngle = 30.0
renderView.CameraParallelProjection = 0
simple.Render(renderView)
# Now compare to baseline image
try:
baselineIndex = sys.argv.index('-B')+1
baselinePath = sys.argv[baselineIndex]
except:
print "Could not get baseline directory. Test failed."
import os
baseline_file = os.path.join(baselinePath, "PointGaussianProperties.png")
import vtk.test.Testing
vtk.test.Testing.VTK_TEMP_DIR = vtk.util.misc.vtkGetTempDir()
vtk.test.Testing.compareImage(renderView.GetRenderWindow(), baseline_file, threshold=25)
vtk.test.Testing.interact()
\ No newline at end of file
<?xml version="1.0" ?>
<pqevents>
<pqevent object="pqClientMainWindow/menubar" command="activate" arguments="menuTools" />
<pqevent object="pqClientMainWindow/menubar/menuTools" command="activate" arguments="actionManage_Plugins" />
<pqevent object="pqClientMainWindow/PluginManagerDialog/localGroup/localPlugins" command="setCurrent" arguments="PointGaussian" />
<pqevent object="pqClientMainWindow/PluginManagerDialog/localGroup/loadSelected_Local" command="activate" arguments="" />
<pqevent object="pqClientMainWindow/PluginManagerDialog/buttonBox/1QPushButton0" command="activate" arguments="" />
<pqevent object="pqClientMainWindow/propertiesDock/propertiesPanel/scrollArea/qt_scrollarea_viewport/scrollAreaWidgetContents/ViewFrame/ProxyPanel/BackgroundEditor/BackgroundType" command="set_string" arguments="Gradient" />
<pqevent object="pqClientMainWindow/menubar" command="activate" arguments="menuTools" />
<pqevent object="pqClientMainWindow/menubar/menuSources" command="activate" arguments="Sphere" />
<pqevent object="pqClientMainWindow/propertiesDock/propertiesPanel/Accept" command="activate" arguments="" />
<pqevent object="pqClientMainWindow/representationToolbar/displayRepresentation/comboBox" command="set_string" arguments="Point Gaussian" />
<pqevent object="pqClientMainWindow/representationToolbar/displayRepresentation/comboBox" command="set_string" arguments="Surface" />
</pqevents>
</pqevents>
\ No newline at end of file
......@@ -321,6 +321,13 @@ if(NOT APPLE)
)
endif()
# This test makes use of "Point Gaussian" representation, only available with OpenGL2
if("${VTK_RENDERING_BACKEND}" STREQUAL "OpenGL2")
list(APPEND TESTS_WITH_BASELINES
${CMAKE_CURRENT_SOURCE_DIR}/BackgroundColorCheck.xml
)
endif()
if (PARAVIEW_USE_MPI)
list(APPEND TESTS_WITH_BASELINES
......
......@@ -103,6 +103,8 @@ set (Module_SRCS
if("${VTK_RENDERING_BACKEND}" STREQUAL "OpenGL2")
add_definitions(-DVTKGL2)
list(APPEND Module_SRCS
vtkPointGaussianRepresentation.cxx)
endif()
if (PARAVIEW_ENABLE_PYTHON)
......
......@@ -22,6 +22,51 @@
vtkStandardNewMacro(vtkPointGaussianRepresentation)
namespace
{
std::vector<std::string> presetShaderStrings;
void InitializeShaderPresets()
{
presetShaderStrings.resize(vtkPointGaussianRepresentation::NUMBER_OF_PRESETS);
presetShaderStrings[vtkPointGaussianRepresentation::GAUSSIAN_BLUR] = "";
presetShaderStrings[vtkPointGaussianRepresentation::SPHERE] =
"//VTK::Color::Impl\n"
"float dist = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);\n"
"if (dist > 1.0) {\n"
" discard;\n"
"} else {\n"
" float scale = (1.0 - dist);\n"
" ambientColor *= scale;\n"
" diffuseColor *= scale;\n"
"}\n";
presetShaderStrings[vtkPointGaussianRepresentation::BLACK_EDGED_CIRCLE] =
"//VTK::Color::Impl\n"
"float dist = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);\n"
"if (dist > 1.0) {\n"
" discard;\n"
"} else if (dist > 0.8) {\n"
" ambientColor = vec3(0.0, 0.0, 0.0);\n"
" diffuseColor = vec3(0.0, 0.0, 0.0);\n"
"}\n";
presetShaderStrings[vtkPointGaussianRepresentation::PLAIN_CIRCLE] =
"//VTK::Color::Impl\n"
"float dist = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);\n"
"if (dist > 1.0) {\n"
" discard;\n"
"};\n";
presetShaderStrings[vtkPointGaussianRepresentation::TRIANGLE] = "//VTK::Color::Impl\n";
presetShaderStrings[vtkPointGaussianRepresentation::SQUARE_OUTLINE] =
"//VTK::Color::Impl\n"
"if (abs(offsetVCVSOutput.x) > 2.2 || abs(offsetVCVSOutput.y) > 2.2) {\n"
" discard;\n"
"}\n"
"if (abs(offsetVCVSOutput.x) < 1.5 && abs(offsetVCVSOutput.y) < 1.5) {\n"
" discard;\n"
"}\n";
}
}
//----------------------------------------------------------------------------
vtkPointGaussianRepresentation::vtkPointGaussianRepresentation()
{
......@@ -32,6 +77,7 @@ vtkPointGaussianRepresentation::vtkPointGaussianRepresentation()
this->LastScaleArray = NULL;
this->OpacityByArray = false;
this->LastOpacityArray = NULL;
InitializeShaderPresets();
}
//----------------------------------------------------------------------------
......@@ -243,6 +289,12 @@ void vtkPointGaussianRepresentation::SetCustomShader(const char* shaderString)
this->Mapper->SetSplatShaderCode(shaderString);
}
//----------------------------------------------------------------------------
void vtkPointGaussianRepresentation::SelectShaderPreset(int preset)
{
this->SetCustomShader(presetShaderStrings[preset].c_str());
}
//----------------------------------------------------------------------------
void vtkPointGaussianRepresentation::SetSplatSize(double radius)
{
......
#ifndef VTKPOINTGAUSSIANREPRESENTATION_H
#define VTKPOINTGAUSSIANREPRESENTATION_H
/*=========================================================================
Program: ParaView
Module: vtkPointGaussianRepresentation.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 vtkPointGaussianRepresentation
// .SECTION Description
// Representation for showing point data as sprites, including gaussian
// splats, spheres, or some custom shaded representation.
#ifndef vtkPointGaussianRepresentation_h
#define vtkPointGaussianRepresentation_h
#include "vtkPVDataRepresentation.h"
#include "vtkWeakPointer.h" // for weak pointer
#include "vtkSmartPointer.h" // for smart pointer
#include "vtkSmartPointer.h" // needed for smart pointer
#include "vtkPVClientServerCoreRenderingModule.h" // needed for exports
class vtkActor;
class vtkPointGaussianMapper;
......@@ -11,7 +30,7 @@ class vtkScalarsToColors;
class vtkPolyData;
class vtkPiecewiseFunction;
class vtkPointGaussianRepresentation : public vtkPVDataRepresentation
class VTKPVCLIENTSERVERCORERENDERING_EXPORT vtkPointGaussianRepresentation : public vtkPVDataRepresentation
{
public:
vtkTypeMacro(vtkPointGaussianRepresentation, vtkPVDataRepresentation)
......@@ -86,6 +105,23 @@ public:
// the scale array is disabled. Defaults to 1.
virtual void SetSplatSize(double radius);
// Description:
// An enum specifying some preset fragment shaders
enum ShaderPresets
{
GAUSSIAN_BLUR, // This is the default
SPHERE, // Points shaded to look (something) like a sphere lit from the view direction
BLACK_EDGED_CIRCLE, // Camera facing, flat circle, rimmed in black
PLAIN_CIRCLE, // Same as above, but without the black edge
TRIANGLE, // Camera facing, flat triangle
SQUARE_OUTLINE, // Camera facing, flat square, with empty center
NUMBER_OF_PRESETS // !!! THIS MUST ALWAYS BE THE LAST PRESET ENUM !!!
};
// Description:
// Allows to select one of several preset options for shading the points
void SelectShaderPreset(int preset);
// Description:
// Sets the snippet of fragment shader code used to color the sprites.
void SetCustomShader(const char* shaderString);
......@@ -154,6 +190,10 @@ protected:
char* LastOpacityArray;
vtkSetStringMacro(LastOpacityArray);
private:
vtkPointGaussianRepresentation(const vtkPointGaussianRepresentation&); // Not implemented
void operator=(const vtkPointGaussianRepresentation&); // Not implemented
};
#endif // VTKPOINTGAUSSIANREPRESENTATION_H
#endif // vtkPointGaussianRepresentation_h
......@@ -3628,7 +3628,6 @@
panel_visibility_default_for_representation="volume" />
</ExposedProperties>
</SubProxy>
<Hints>
<!-- pqDisplayRepresentationWidget respects this hint to put out
a warning for the user before switching to this type of Representation.
......
#--------------------------------------------------
# Find and Use ParaView
#--------------------------------------------------
if (ParaView_SOURCE_DIR)
include_directories( ${PARAVIEW_INCLUDE_DIRS} ${VTK_INCLUDE_DIRS})
else()
find_package(ParaView REQUIRED)
include(${PARAVIEW_USE_FILE})
endif()
add_paraview_plugin(PointGaussian "1.0"
SERVER_MANAGER_XML PointGaussian.xml
SERVER_MANAGER_SOURCES
vtkPointGaussianRepresentation.cxx
vtkPointGaussianRepresentation.h
)
# Add testing if necessary
if (BUILD_TESTING)
add_subdirectory(Testing)
endif()
\ No newline at end of file
This diff is collapsed.
INCLUDE(ParaViewTestingMacros)
set(POINT_GAUSSIAN_MODULE_TESTS
${CMAKE_CURRENT_SOURCE_DIR}/BackgroundColorCheck.xml
)
IF (PARAVIEW_BUILD_QT_GUI AND BUILD_SHARED_LIBS AND "${VTK_RENDERING_BACKEND}" STREQUAL "OpenGL2")
add_client_tests("pv"
LOAD_PLUGIN "PointGaussian"
BASELINE_DIR ${PARAVIEW_TEST_BASELINE_DIR}
TEST_SCRIPTS ${POINT_GAUSSIAN_MODULE_TESTS}
)
ENDIF ()
if ("${VTK_RENDERING_BACKEND}" STREQUAL "OpenGL2")
pv_plugin(PointGaussian
DESCRIPTION "Render Gaussian blurs for points"
DEFAULT_ENABLED)
endif()
......@@ -7,13 +7,13 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<height>377</height>
</rect>
</property>
<property name="windowTitle">
<string>Edit Transfer Function</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0,0">
<item>
<widget class="QLabel" name="Label">
<property name="text">
......@@ -31,6 +31,54 @@
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="title">
<string>Piece wise ranges</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QDoubleSpinBox" name="minX">
<property name="minimum">
<double>-10000000.000000000000000</double>
</property>
<property name="maximum">
<double>10000000.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QDoubleSpinBox" name="maxX">
<property name="minimum">
<double>-10000000.000000000000000</double>
</property>
<property name="maximum">
<double>10000000.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<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>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="ButtonBox">
<property name="orientation">
......
......@@ -39,9 +39,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "vtkPiecewiseFunction.h"
#include "vtkSmartPointer.h"
#include "vtkSMProperty.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMProxy.h"
#include "vtkSMProxyListDomain.h"
#include "vtkSMProxyProperty.h"
#include "vtkSMTransferFunctionProxy.h"
#include <QDebug>
#include <QVBoxLayout>
......@@ -56,7 +58,7 @@ namespace
Ui::TransferFunctionWidgetPropertyWidgetDialog Ui;
public:
pqTransferFunctionWidgetPropertyWidgetDialog(
const QString& label,
const QString& label, double* xrange,
vtkPiecewiseFunction* transferFunction, QWidget* parentWdg=NULL) :
QDialog(parentWdg),
TransferFunction(transferFunction)
......@@ -67,6 +69,11 @@ public:
this->Ui.Label->text().arg(label));
this->Ui.TransferFunctionEditor->initialize(NULL, false,
this->TransferFunction.GetPointer(), true);
this->Ui.minX->setValue(xrange[0]);
this->Ui.maxX->setValue(xrange[1]);
QObject::connect(this->Ui.minX, SIGNAL(valueChanged(double)), parentWdg, SLOT(minXChanged(double)));
QObject::connect(this->Ui.maxX, SIGNAL(valueChanged(double)), parentWdg, SLOT(maxXChanged(double)));
}
~pqTransferFunctionWidgetPropertyWidgetDialog()
{
......@@ -80,6 +87,9 @@ pqTransferFunctionWidgetPropertyWidget::pqTransferFunctionWidgetPropertyWidget(v
: pqPropertyWidget(smProxy, pWidget),
Property(proxyProperty)
{
xRange[0] = 0.0;
xRange[1] = 1.0;
QVBoxLayout *l = new QVBoxLayout;
l->setMargin(0);
......@@ -97,6 +107,41 @@ pqTransferFunctionWidgetPropertyWidget::~pqTransferFunctionWidgetPropertyWidget(
{
}
void pqTransferFunctionWidgetPropertyWidget::minXChanged(double newMinX)
{
xRange[0] = newMinX;
}
void pqTransferFunctionWidgetPropertyWidget::maxXChanged(double newMaxX)
{
xRange[1] = newMaxX;
}
void pqTransferFunctionWidgetPropertyWidget::propagateProxyPointsProperty(vtkSMTransferFunctionProxy* transferFunctionProxy)
{
vtkSMProxy* pxy = static_cast<vtkSMProxy*>(transferFunctionProxy);
vtkObjectBase* object = pxy->GetClientSideObject();
vtkPiecewiseFunction* transferFunction = vtkPiecewiseFunction::SafeDownCast(object);
int numPoints = transferFunction->GetSize();
std::vector<double> functionPoints(numPoints * 4);
double* pts = &functionPoints[0];
for (int i = 0; i < numPoints; ++i)
{
int idx = i * 4;
transferFunction->GetNodeValue(i, pts + idx);
}
vtkSMPropertyHelper(pxy, "Points").Set(pts, numPoints * 4);
transferFunctionProxy->UpdateVTKObjects();
}
void pqTransferFunctionWidgetPropertyWidget::updateTransferFunctionRanges(vtkSMTransferFunctionProxy* transferFunctionProxy)
{
transferFunctionProxy->RescaleTransferFunction(xRange[0], xRange[1], false);
}
void pqTransferFunctionWidgetPropertyWidget::buttonClicked()
{
vtkSMProxyProperty *proxyProperty = vtkSMProxyProperty::SafeDownCast(this->Property);
......@@ -117,15 +162,22 @@ void pqTransferFunctionWidgetPropertyWidget::buttonClicked()
qDebug() << "error, no proxy property";
return;
}
vtkSMTransferFunctionProxy* transferFunctionProxy = vtkSMTransferFunctionProxy::SafeDownCast(pxy);
vtkObjectBase *object = pxy->GetClientSideObject();
vtkPiecewiseFunction *transferFunction =
vtkPiecewiseFunction::SafeDownCast(object);
pqTransferFunctionWidgetPropertyWidgetDialog dialog(
this->Property->GetXMLLabel(), transferFunction, this);
this->Property->GetXMLLabel(), &xRange[0], transferFunction, this);
dialog.exec();
// These next two lines constitute an attempt to work-around the BUG
// mentioned below. Now the vtkPiecewiseFunction change does work in
// client-server mode.
propagateProxyPointsProperty(transferFunctionProxy);
updateTransferFunctionRanges(transferFunctionProxy);
// BUG: we are never propagating the vtkPiecewiseFunction change to the
// SMProperty on the proxy!!! This will never work in client-server mode.
emit this->changeAvailable();
......
......@@ -35,6 +35,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "pqApplicationComponentsModule.h" // for export macros
#include "pqPropertyWidget.h"
class vtkSMTransferFunctionProxy;
/// A property widget for editing a transfer function.
///
/// To use this widget for a property add the
......@@ -51,9 +53,15 @@ public:
private slots:
void buttonClicked();
void minXChanged(double newMinX);
void maxXChanged(double newMaxX);
private:
vtkSMProperty* Property;
double xRange[2];
void propagateProxyPointsProperty(vtkSMTransferFunctionProxy* tfp);
void updateTransferFunctionRanges(vtkSMTransferFunctionProxy* tfp);
};
#endif // _pqTransferFunctionWidgetPropertyWidget_h
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment