<commit_before>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "ModuleThreshold.h"

#include "DataSource.h"
#include "DoubleSliderWidget.h"
#include "Utilities.h"
#include "pqProxiesWidget.h"
#include "pqSignalAdaptors.h"
#include "pqStringVectorPropertyWidget.h"
#include "pqWidgetRangeDomain.h"

#include "vtkDataObject.h"
#include "vtkNew.h"
#include "vtkSMPVRepresentationProxy.h"
#include "vtkSMParaViewPipelineControllerWithRendering.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"
#include "vtkSMViewProxy.h"
#include "vtkSmartPointer.h"

#include <QCheckBox>
#include <QComboBox>
#include <QFormLayout>
#include <QVBoxLayout>

namespace tomviz {

ModuleThreshold::ModuleThreshold(QObject* parentObject) : Module(parentObject)
{}

ModuleThreshold::~ModuleThreshold()
{
  finalize();
}

QIcon ModuleThreshold::icon() const
{
  return QIcon(":/pqWidgets/Icons/pqThreshold.svg");
}

bool ModuleThreshold::initialize(DataSource* data, vtkSMViewProxy* vtkView)
{
  if (!Module::initialize(data, vtkView)) {
    return false;
  }

  auto producer = data->proxy();

  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;

  vtkSMSessionProxyManager* pxm = producer->GetSessionProxyManager();

  // Create the contour filter.
  vtkSmartPointer<vtkSMProxy> proxy;
  proxy.TakeReference(pxm->NewProxy("filters", "Threshold"));

  m_thresholdFilter = vtkSMSourceProxy::SafeDownCast(proxy);
  Q_ASSERT(m_thresholdFilter);
  controller->PreInitializeProxy(m_thresholdFilter);
  vtkSMPropertyHelper(m_thresholdFilter, "Input").Set(producer);
  controller->PostInitializeProxy(m_thresholdFilter);
  controller->RegisterPipelineProxy(m_thresholdFilter);

  vtkSMPropertyHelper(m_thresholdFilter, "ThresholdMethod").Set("Between");

  // Update min/max to avoid thresholding the full dataset.
  vtkSMPropertyHelper lowerProp(m_thresholdFilter, "LowerThreshold");
  vtkSMPropertyHelper upperProp(m_thresholdFilter, "UpperThreshold");

  double range[2], newRange[2];
  lowerProp.Get(&range[0]);
  upperProp.Get(&range[1]);

  double delta = (range[1] - range[0]);
  double mid = ((range[0] + range[1]) / 2.0);
  newRange[0] = mid - 0.1 * delta;
  newRange[1] = mid + 0.1 * delta;

  lowerProp.Set(newRange[0]);
  upperProp.Set(newRange[1]);

  m_thresholdFilter->UpdateVTKObjects();

  // Create the representation for it.
  m_thresholdRepresentation = controller->Show(m_thresholdFilter, 0, vtkView);
  Q_ASSERT(m_thresholdRepresentation);
  vtkSMRepresentationProxy::SetRepresentationType(m_thresholdRepresentation,
                                                  "Surface");
  vtkSMPropertyHelper(m_thresholdRepresentation, "Position")
    .Set(data->displayPosition(), 3);
  vtkSMPropertyHelper(m_thresholdRepresentation, "Orientation")
    .Set(data->displayOrientation(), 3);
  updateColorMap();
  m_thresholdRepresentation->UpdateVTKObjects();

  // Give the proxy a friendly name for the GUI/Python world.
  if (auto p = convert<pqProxy*>(proxy)) {
    p->rename(label());
  }

  connect(data, SIGNAL(activeScalarsChanged()), SLOT(onScalarArrayChanged()));
  onScalarArrayChanged();

  return true;
}

void ModuleThreshold::updateColorMap()
{
  Q_ASSERT(m_thresholdRepresentation);

  // by default, use the data source's color/opacity maps.
  vtkSMPropertyHelper(m_thresholdRepresentation, "LookupTable").Set(colorMap());
  vtkSMPropertyHelper(m_thresholdRepresentation, "ScalarOpacityFunction")
    .Set(opacityMap());

  m_thresholdRepresentation->UpdateVTKObjects();
}

bool ModuleThreshold::finalize()
{
  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  controller->UnRegisterProxy(m_thresholdRepresentation);
  controller->UnRegisterProxy(m_thresholdFilter);
  m_thresholdFilter = nullptr;
  m_thresholdRepresentation = nullptr;
  return true;
}

bool ModuleThreshold::setVisibility(bool val)
{
  Q_ASSERT(m_thresholdRepresentation);
  vtkSMPropertyHelper(m_thresholdRepresentation, "Visibility").Set(val ? 1 : 0);
  m_thresholdRepresentation->UpdateVTKObjects();

  Module::setVisibility(val);

  return true;
}

bool ModuleThreshold::visibility() const
{
  if (m_thresholdRepresentation) {
    return vtkSMPropertyHelper(m_thresholdRepresentation, "Visibility")
             .GetAsInt() != 0;
  } else {
    return false;
  }
}

void ModuleThreshold::addToPanel(QWidget* panel)
{
  Q_ASSERT(m_thresholdFilter);
  Q_ASSERT(m_thresholdRepresentation);

  if (panel->layout()) {
    delete panel->layout();
  }

  QVBoxLayout* layout = new QVBoxLayout;

  pqStringVectorPropertyWidget* arraySelection =
    new pqStringVectorPropertyWidget(
      m_thresholdFilter->GetProperty("SelectInputScalars"),
      m_thresholdFilter);
  layout->addWidget(arraySelection);

  auto lowerProp = m_thresholdFilter->GetProperty("LowerThreshold");
  auto upperProp = m_thresholdFilter->GetProperty("UpperThreshold");

  auto* lowerSlider = new DoubleSliderWidget(true);
  auto* upperSlider = new DoubleSliderWidget(true);

  // Only update when the user releases the slider
  lowerSlider->setSliderTracking(false);
  upperSlider->setSliderTracking(false);
<commit_msg>Add clamping functions to threshold range<commit_after>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "ModuleThreshold.h"

#include "DataSource.h"
#include "DoubleSliderWidget.h"
#include "Utilities.h"
#include "pqProxiesWidget.h"
#include "pqSignalAdaptors.h"
#include "pqStringVectorPropertyWidget.h"
#include "pqWidgetRangeDomain.h"

#include "vtkDataObject.h"
#include "vtkNew.h"
#include "vtkSMPVRepresentationProxy.h"
#include "vtkSMParaViewPipelineControllerWithRendering.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"
#include "vtkSMViewProxy.h"
#include "vtkSmartPointer.h"

#include <QCheckBox>
#include <QComboBox>
#include <QFormLayout>
#include <QVBoxLayout>

namespace tomviz {

ModuleThreshold::ModuleThreshold(QObject* parentObject) : Module(parentObject)
{}

ModuleThreshold::~ModuleThreshold()
{
  finalize();
}

QIcon ModuleThreshold::icon() const
{
  return QIcon(":/pqWidgets/Icons/pqThreshold.svg");
}

bool ModuleThreshold::initialize(DataSource* data, vtkSMViewProxy* vtkView)
{
  if (!Module::initialize(data, vtkView)) {
    return false;
  }

  auto producer = data->proxy();

  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;

  vtkSMSessionProxyManager* pxm = producer->GetSessionProxyManager();

  // Create the contour filter.
  vtkSmartPointer<vtkSMProxy> proxy;
  proxy.TakeReference(pxm->NewProxy("filters", "Threshold"));

  m_thresholdFilter = vtkSMSourceProxy::SafeDownCast(proxy);
  Q_ASSERT(m_thresholdFilter);
  controller->PreInitializeProxy(m_thresholdFilter);
  vtkSMPropertyHelper(m_thresholdFilter, "Input").Set(producer);
  controller->PostInitializeProxy(m_thresholdFilter);
  controller->RegisterPipelineProxy(m_thresholdFilter);

  vtkSMPropertyHelper(m_thresholdFilter, "ThresholdMethod").Set("Between");

  // Update min/max to avoid thresholding the full dataset.
  vtkSMPropertyHelper lowerProp(m_thresholdFilter, "LowerThreshold");
  vtkSMPropertyHelper upperProp(m_thresholdFilter, "UpperThreshold");

  double range[2], newRange[2];
  lowerProp.Get(&range[0]);
  upperProp.Get(&range[1]);

  double delta = (range[1] - range[0]);
  double mid = ((range[0] + range[1]) / 2.0);
  newRange[0] = mid - 0.1 * delta;
  newRange[1] = mid + 0.1 * delta;

  lowerProp.Set(newRange[0]);
  upperProp.Set(newRange[1]);

  m_thresholdFilter->UpdateVTKObjects();

  // Create the representation for it.
  m_thresholdRepresentation = controller->Show(m_thresholdFilter, 0, vtkView);
  Q_ASSERT(m_thresholdRepresentation);
  vtkSMRepresentationProxy::SetRepresentationType(m_thresholdRepresentation,
                                                  "Surface");
  vtkSMPropertyHelper(m_thresholdRepresentation, "Position")
    .Set(data->displayPosition(), 3);
  vtkSMPropertyHelper(m_thresholdRepresentation, "Orientation")
    .Set(data->displayOrientation(), 3);
  updateColorMap();
  m_thresholdRepresentation->UpdateVTKObjects();

  // Give the proxy a friendly name for the GUI/Python world.
  if (auto p = convert<pqProxy*>(proxy)) {
    p->rename(label());
  }

  connect(data, SIGNAL(activeScalarsChanged()), SLOT(onScalarArrayChanged()));
  onScalarArrayChanged();

  return true;
}

void ModuleThreshold::updateColorMap()
{
  Q_ASSERT(m_thresholdRepresentation);

  // by default, use the data source's color/opacity maps.
  vtkSMPropertyHelper(m_thresholdRepresentation, "LookupTable").Set(colorMap());
  vtkSMPropertyHelper(m_thresholdRepresentation, "ScalarOpacityFunction")
    .Set(opacityMap());

  m_thresholdRepresentation->UpdateVTKObjects();
}

bool ModuleThreshold::finalize()
{
  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  controller->UnRegisterProxy(m_thresholdRepresentation);
  controller->UnRegisterProxy(m_thresholdFilter);
  m_thresholdFilter = nullptr;
  m_thresholdRepresentation = nullptr;
  return true;
}

bool ModuleThreshold::setVisibility(bool val)
{
  Q_ASSERT(m_thresholdRepresentation);
  vtkSMPropertyHelper(m_thresholdRepresentation, "Visibility").Set(val ? 1 : 0);
  m_thresholdRepresentation->UpdateVTKObjects();

  Module::setVisibility(val);

  return true;
}

bool ModuleThreshold::visibility() const
{
  if (m_thresholdRepresentation) {
    return vtkSMPropertyHelper(m_thresholdRepresentation, "Visibility")
             .GetAsInt() != 0;
  } else {
    return false;
  }
}

void ModuleThreshold::addToPanel(QWidget* panel)
{
  Q_ASSERT(m_thresholdFilter);
  Q_ASSERT(m_thresholdRepresentation);

  if (panel->layout()) {
    delete panel->layout();
  }

  QVBoxLayout* layout = new QVBoxLayout;

  pqStringVectorPropertyWidget* arraySelection =
    new pqStringVectorPropertyWidget(
      m_thresholdFilter->GetProperty("SelectInputScalars"),
      m_thresholdFilter);
  layout->addWidget(arraySelection);

  auto lowerProp = m_thresholdFilter->GetProperty("LowerThreshold");
  auto upperProp = m_thresholdFilter->GetProperty("UpperThreshold");

  auto* lowerSlider = new DoubleSliderWidget(true);
  auto* upperSlider = new DoubleSliderWidget(true);

  auto clampLower = [lowerSlider, upperSlider]() {
    if (lowerSlider->value() > upperSlider->value()) {
      lowerSlider->setValue(upperSlider->value());
    }
  };

  auto clampUpper = [lowerSlider, upperSlider]() {
    if (lowerSlider->value() > upperSlider->value()) {
      upperSlider->setValue(lowerSlider->value());
    }
  };

  connect(lowerSlider, &DoubleSliderWidget::valueEdited, upperSlider,
          clampUpper);
  connect(upperSlider, &DoubleSliderWidget::valueEdited, lowerSlider,
          clampLower);

  // Only update when the user releases the slider
  lowerSlider->setSliderTracking(false);
  upperSlider->setSliderTracking(false);

{'fraction_non_alphanumeric': 0.1202136326604508, 'fraction_numerical': 0.004526115687516973, 'mean_word_length': 5.823965410747375, 'pattern_counts': {'":': 2, '<': 19, '<?xml version=': 0, '>': 77, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6796370', 'n_tokens_mistral': 3431, 'n_tokens_neox': 3369, 'n_words': 611}