Newer
Older
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2015 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2015-2016 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// OpenFOAM includes
#include "fieldVisualisationBase.H"
#include "runTimePostProcessing.H"
// VTK includes
#include "vtkArrowSource.h"
Andrew Heather
committed
#include "vtkCellData.h"
#include "vtkColorTransferFunction.h"
#include "vtkFloatArray.h"
#include "vtkGlyph3D.h"
#include "vtkLookupTable.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderer.h"
#include "vtkScalarBarActor.h"
#include "vtkSmartPointer.h"
#include "vtkSphereSource.h"
#include "vtkTextActor.h"
#include "vtkTextProperty.h"
Andrew Heather
committed
#include "vtkCellDataToPointData.h"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
namespace Foam
{
template<>
const char* NamedEnum
<
functionObjects::fieldVisualisationBase::colourByType,
2
>::names[] =
{
"colour",
"field"
};
template<>
const char* NamedEnum
<
functionObjects::fieldVisualisationBase::colourMapType,
4
>::names[] =
{
"rainbow",
"blueWhiteRed",
"fire",
"greyscale"
};
}
const Foam::NamedEnum
<
Foam::functionObjects::fieldVisualisationBase::colourByType,
2
>
Foam::functionObjects::fieldVisualisationBase::colourByTypeNames;
const Foam::NamedEnum
<
Foam::functionObjects::fieldVisualisationBase::colourMapType,
4
>
Foam::functionObjects::fieldVisualisationBase::colourMapTypeNames;
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::functionObjects::fieldVisualisationBase::setColourMap
(
vtkLookupTable* lut
) const
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
{
label nColours = 256;
lut->SetNumberOfColors(nColours);
vtkSmartPointer<vtkColorTransferFunction> ctf =
vtkSmartPointer<vtkColorTransferFunction>::New();
switch (colourMap_)
{
case cmRainbow:
{
ctf->SetColorSpaceToHSV();
ctf->AddRGBPoint(0, 0, 0, 1);
ctf->AddRGBPoint(0.5, 0, 1, 0);
ctf->AddRGBPoint(1, 1, 0, 0);
break;
}
case cmBlueWhiteRed:
{
// Values taken from ParaView settings
ctf->SetColorSpaceToDiverging();
ctf->AddRGBPoint(0.0, 0.231373, 0.298039, 0.752941);
ctf->AddRGBPoint(0.5, 0.865003, 0.865003, 0.865003);
ctf->AddRGBPoint(1.0, 0.705882, 0.0156863, 0.14902);
break;
}
case cmFire:
{
// Values taken from ParaView settings
ctf->SetColorSpaceToRGB();
ctf->AddRGBPoint(0, 0, 0, 0);
ctf->AddRGBPoint(0.4, 0.901961, 0, 0);
ctf->AddRGBPoint(0.8, 0.901961, 0.901961, 0);
ctf->AddRGBPoint(1, 1, 1, 1);
break;
}
case cmGreyscale:
{
ctf->SetColorSpaceToRGB();
ctf->AddRGBPoint(0, 0, 0, 0);
ctf->AddRGBPoint(1, 1, 1, 1);
break;
}
}
for (label i = 0; i < nColours; i++)
{
double* c = ctf->GetColor(scalar(i)/scalar(nColours));
lut->SetTableValue(i, c[0], c[1], c[2], 1.0);
}
}
void Foam::functionObjects::fieldVisualisationBase::addScalarBar
(
const scalar position,
vtkRenderer* renderer,
vtkLookupTable* lut
) const
{
Andrew Heather
committed
// Add scalar bar legend
if (!scalarBar_.visible_)
{
return;
}
vtkSmartPointer<vtkScalarBarActor> sbar =
vtkSmartPointer<vtkScalarBarActor>::New();
sbar->SetLookupTable(lut);
sbar->SetNumberOfLabels(scalarBar_.numberOfLabels_);
const vector textColour = colours_["text"]->value(position);
Andrew Heather
committed
// Work-around to supply our own scalarbar title
Andrew Heather
committed
// - Default scalar bar title text is scales by the scalar bar box
// dimensions so if the title is a long string, the text is shrunk to fit
// Instead, suppress title and set the title using a vtkTextActor
vtkSmartPointer<vtkTextActor> titleActor =
vtkSmartPointer<vtkTextActor>::New();
sbar->SetTitle(" ");
titleActor->SetInput(scalarBar_.title_.c_str());
titleActor->GetTextProperty()->SetFontFamilyToArial();
titleActor->GetTextProperty()->SetFontSize(3*scalarBar_.fontSize_);
titleActor->GetTextProperty()->SetJustificationToCentered();
titleActor->GetTextProperty()->SetVerticalJustificationToBottom();
titleActor->GetTextProperty()->BoldOn();
titleActor->GetTextProperty()->ItalicOff();
titleActor->GetTextProperty()->SetColor
(
textColour[0],
textColour[1],
textColour[2]
);
titleActor->GetPositionCoordinate()->
SetCoordinateSystemToNormalizedViewport();
Andrew Heather
committed
// How to use the standard scalar bar text
// sbar->SetTitle(scalarBar_.title_.c_str());
// sbar->GetTitleTextProperty()->SetColor
// (
// textColour[0],
// textColour[1],
// textColour[2]
// );
// sbar->GetTitleTextProperty()->SetFontSize(scalarBar_.fontSize_);
// sbar->GetTitleTextProperty()->ShadowOff();
// sbar->GetTitleTextProperty()->BoldOn();
// sbar->GetTitleTextProperty()->ItalicOff();
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
sbar->GetLabelTextProperty()->SetColor
(
textColour[0],
textColour[1],
textColour[2]
);
sbar->GetLabelTextProperty()->SetFontSize(scalarBar_.fontSize_);
sbar->GetLabelTextProperty()->ShadowOff();
sbar->GetLabelTextProperty()->BoldOff();
sbar->GetLabelTextProperty()->ItalicOff();
sbar->SetLabelFormat(scalarBar_.labelFormat_.c_str());
sbar->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport();
sbar->GetPositionCoordinate()->SetValue
(
scalarBar_.position_.first(),
scalarBar_.position_.second()
);
if (scalarBar_.vertical_)
{
sbar->SetOrientationToVertical();
sbar->SetWidth(0.1);
sbar->SetHeight(0.75);
sbar->SetTextPositionToSucceedScalarBar();
}
else
{
sbar->SetOrientationToHorizontal();
Andrew Heather
committed
// Adjustments since not using scalarbar title property
sbar->SetWidth(0.75);
sbar->SetHeight(0.07);
sbar->SetBarRatio(0.5);
Andrew Heather
committed
// sbar->SetHeight(0.1);
// sbar->SetTitleRatio(0.01);
sbar->SetTextPositionToPrecedeScalarBar();
}
titleActor->GetPositionCoordinate()->SetValue
(
scalarBar_.position_.first() + 0.5*sbar->GetWidth(),
scalarBar_.position_.second() + sbar->GetHeight()
);
Andrew Heather
committed
// sbar->DrawFrameOn();
// sbar->DrawBackgroundOn();
// sbar->UseOpacityOff();
// sbar->VisibilityOff();
sbar->VisibilityOn();
renderer->AddActor(sbar);
renderer->AddActor2D(titleActor);
}
void Foam::functionObjects::fieldVisualisationBase::setField
(
const scalar position,
const word& colourFieldName,
vtkPolyDataMapper* mapper,
vtkRenderer* renderer,
vtkPolyData* pData
) const
{
mapper->InterpolateScalarsBeforeMappingOn();
switch (colourBy_)
{
case cbColour:
{
mapper->ScalarVisibilityOff();
break;
}
case cbField:
{
Andrew Heather
committed
// Create look-up table for colours
vtkSmartPointer<vtkLookupTable> lut =
vtkSmartPointer<vtkLookupTable>::New();
setColourMap(lut);
lut->SetVectorMode(vtkScalarsToColors::MAGNITUDE);
Andrew Heather
committed
// Configure the mapper
Andrew Heather
committed
const char* fieldName = colourFieldName.c_str();
mapper->SelectColorArray(fieldName);
// Set to use either point or cell data
// Note: if both point and cell data exists, preferentially
// choosing point data. This is often the case when using
// glyphs
if (pData->GetPointData()->HasArray(fieldName) == 1)
{
mapper->SetScalarModeToUsePointFieldData();
}
else if (pData->GetCellData()->HasArray(fieldName) == 1)
{
mapper->SetScalarModeToUseCellFieldData();
}
else
{
WarningInFunction
<< "Unable to determine cell or point data type "
<< "- assuming point data";
mapper->SetScalarModeToUsePointFieldData();
}
mapper->SetScalarRange(range_.first(), range_.second());
mapper->SetColorModeToMapScalars();
mapper->SetLookupTable(lut);
mapper->ScalarVisibilityOn();
Andrew Heather
committed
// Add the bar
addScalarBar(position, renderer, lut);
break;
}
}
mapper->Modified();
}
void Foam::functionObjects::fieldVisualisationBase::addGlyphs
(
const scalar position,
const word& scaleFieldName,
const word& colourFieldName,
const scalar maxGlyphLength,
vtkPolyData* data,
vtkActor* actor,
vtkRenderer* renderer
) const
{
vtkSmartPointer<vtkGlyph3D> glyph = vtkSmartPointer<vtkGlyph3D>::New();
vtkSmartPointer<vtkPolyDataMapper> glyphMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
glyphMapper->SetInputConnection(glyph->GetOutputPort());
glyph->SetInputData(data);
glyph->ScalingOn();
bool ok = true;
Andrew Heather
committed
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
// Determine whether we have scalar or vector data
label nComponents = -1;
const char* scaleFieldNameChar = scaleFieldName.c_str();
if (data->GetPointData()->HasArray(scaleFieldNameChar) == 1)
{
nComponents =
data->GetPointData()->GetArray(scaleFieldNameChar)
->GetNumberOfComponents();
}
else if (data->GetCellData()->HasArray(scaleFieldNameChar) == 1)
{
// Need to convert cell data to point data
vtkSmartPointer<vtkCellDataToPointData> cellToPoint =
vtkSmartPointer<vtkCellDataToPointData>::New();
cellToPoint->SetInputData(data);
cellToPoint->Update();
vtkDataSet* pds = cellToPoint->GetOutput();
vtkDataArray* pData = pds->GetPointData()->GetArray(scaleFieldNameChar);
// Store in main vtkPolyData
data->GetPointData()->AddArray(pData);
nComponents = pData->GetNumberOfComponents();
}
else
{
WarningInFunction
<< "Glyphs can only be added to scalar or vector data. "
<< "Unable to process field " << scaleFieldName << endl;
return;
}
if (nComponents == 1)
{
vtkSmartPointer<vtkSphereSource> sphere =
vtkSmartPointer<vtkSphereSource>::New();
sphere->SetCenter(0, 0, 0);
sphere->SetRadius(0.5);
Andrew Heather
committed
// Setting higher resolution slows the rendering significantly
// sphere->SetPhiResolution(20);
// sphere->SetThetaResolution(20);
glyph->SetSourceConnection(sphere->GetOutputPort());
if (maxGlyphLength > 0)
{
double range[2];
Andrew Heather
committed
// Can use values to find range
// vtkDataArray* values =
// data->GetPointData()->GetScalars(scaleFieldNameChar);
// values->GetRange(range);
Andrew Heather
committed
// Set range accoding to user-supplied limits
range[0] = range_.first();
range[1] = range_.second();
glyph->ClampingOn();
glyph->SetRange(range);
Andrew Heather
committed
// If range[0] != min(value), maxGlyphLength behaviour will not
// be correct...
glyph->SetScaleFactor(maxGlyphLength);
}
else
{
glyph->SetScaleFactor(1);
}
glyph->SetScaleModeToScaleByScalar();
glyph->OrientOff();
glyph->SetColorModeToColorByScalar();
glyph->SetInputArrayToProcess
(
0, // scalars
0,
0,
vtkDataObject::FIELD_ASSOCIATION_POINTS,
Andrew Heather
committed
scaleFieldNameChar
);
}
else if (nComponents == 3)
{
vtkSmartPointer<vtkArrowSource> arrow =
vtkSmartPointer<vtkArrowSource>::New();
arrow->SetTipResolution(10);
arrow->SetTipRadius(0.1);
arrow->SetTipLength(0.35);
arrow->SetShaftResolution(10);
arrow->SetShaftRadius(0.03);
glyph->SetSourceConnection(arrow->GetOutputPort());
if (maxGlyphLength > 0)
{
vtkDataArray* values =
Andrew Heather
committed
data->GetPointData()->GetVectors(scaleFieldNameChar);
double range[6];
values->GetRange(range);
Andrew Heather
committed
// Attempt to set range for vectors...
Andrew Heather
committed
// scalar x0 = sqrt(sqr(range_.first())/3.0);
// scalar x1 = sqrt(sqr(range_.second())/3.0);
// range[0] = x0;
// range[1] = x0;
// range[2] = x0;
// range[3] = x1;
// range[4] = x1;
// range[5] = x1;
glyph->ClampingOn();
glyph->SetRange(range);
glyph->SetScaleFactor(maxGlyphLength);
}
else
{
glyph->SetScaleFactor(1);
}
glyph->SetScaleModeToScaleByVector();
glyph->OrientOn();
glyph->SetVectorModeToUseVector();
glyph->SetColorModeToColorByVector();
glyph->SetInputArrayToProcess
(
1, // vectors
0,
0,
vtkDataObject::FIELD_ASSOCIATION_POINTS,
Andrew Heather
committed
scaleFieldNameChar
);
}
else
{
<< "Glyphs can only be added to scalar and vector fields."
<< " Field " << scaleFieldName << " has " << nComponents
<< " components" << endl;
ok = false;
}
if (ok)
{
glyph->Update();
setField(position, colourFieldName, glyphMapper, renderer, data);
glyphMapper->Update();
actor->SetMapper(glyphMapper);
renderer->AddActor(actor);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::fieldVisualisationBase::fieldVisualisationBase
(
const dictionary& dict,
Andrew Heather
committed
const HashPtrTable<Function1<vector>, word>& colours
)
:
colours_(colours),
Andrew Heather
committed
fieldName_(dict.lookup("field")),
colourBy_(cbColour),
colourMap_(cmRainbow),
range_()
{
colourBy_ = colourByTypeNames.read(dict.lookup("colourBy"));
switch (colourBy_)
{
case cbColour:
{
scalarBar_.visible_ = false;
break;
}
case cbField:
{
dict.lookup("range") >> range_;
if (dict.found("colourMap"))
{
colourMap_ = colourMapTypeNames.read(dict.lookup("colourMap"));
}
const dictionary& sbarDict = dict.subDict("scalarBar");
sbarDict.lookup("visible") >> scalarBar_.visible_;
if (scalarBar_.visible_)
{
sbarDict.lookup("vertical") >> scalarBar_.vertical_;
sbarDict.lookup("position") >> scalarBar_.position_;
sbarDict.lookup("title") >> scalarBar_.title_;
sbarDict.lookup("fontSize") >> scalarBar_.fontSize_;
sbarDict.lookup("labelFormat") >> scalarBar_.labelFormat_;
sbarDict.lookup("numberOfLabels") >> scalarBar_.numberOfLabels_;
}
break;
}
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::functionObjects::fieldVisualisationBase::~fieldVisualisationBase()
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Andrew Heather
committed
const Foam::HashPtrTable<Foam::Function1<Foam::vector>, Foam::word>&
Foam::functionObjects::fieldVisualisationBase::colours() const
{
return colours_;
}
const Foam::word&
Foam::functionObjects::fieldVisualisationBase::fieldName() const
{
return fieldName_;
}
// ************************************************************************* //