<commit_before>#include "AliEventPoolManager.h"

ClassImp(AliEventPool)

void AliEventPool::PrintInfo() const
{
  cout << Form("%20s: %d events", "Pool capacity", fMixDepth) << endl;
  cout << Form("%20s: %d events, %d tracks", "Current size",
	       GetCurrentNEvents(), NTracksInPool()) << endl;
  cout << Form("%20s: %.1f to %.1f", "Sub-event mult.", fMultMin, fMultMax) << endl;
  cout << Form("%20s: %.1f to %.1f", "Z-vtx range", fZvtxMin, fZvtxMax) << endl;

  return;
}

Bool_t AliEventPool::EventMatchesBin(Int_t mult, Double_t zvtx) const
{
  return EventMatchesBin((Double_t) mult, zvtx);
}

Bool_t AliEventPool::EventMatchesBin(Double_t mult, Double_t zvtx) const
{
  // Lower bin limit included; upper limit excluded.

  Bool_t multOK = (mult >= fMultMin && mult < fMultMax);
  Bool_t zvtxOK = (zvtx >= fZvtxMin && zvtx < fZvtxMax);
  return (multOK && zvtxOK);
}

Int_t AliEventPool::NTracksInPool() const
{
  // Number of tracks for this cent, zvtx bin; possibly includes many
  // events.

  Int_t ntrk=0;
  for (Int_t i=0; i<(Int_t)fEvents.size(); ++i) {
    ntrk += fNTracksInEvent.at(i);
  }
  return ntrk;
}

Int_t AliEventPool::SetEventMultRange(Int_t multMin, Int_t multMax)
{
  fMultMin = (Double_t)multMin;
  fMultMax = (Double_t)multMax;
  return 0;
}

Int_t AliEventPool::SetEventMultRange(Double_t multMin, Double_t multMax)
{
  fMultMin = multMin;
  fMultMax = multMax;
  return 0;
}

Int_t AliEventPool::SetEventZvtxRange(Double_t zvtxMin, Double_t zvtxMax)
{
  fZvtxMin = zvtxMin;
  fZvtxMax = zvtxMax;
  return 0;
}

Int_t AliEventPool::GlobalEventIndex(Int_t j) const
{
  // Index returned from passing local pool event index.

  if (j < 0 || j >= (Int_t)fEventIndex.size()) {
    cout << "ERROR in AliEventPool::GlobalEventIndex(): "
	 << " Invalid index " << j << endl;
    return -99;
  }
  return fEventIndex.at(j);
}

Int_t AliEventPool::UpdatePool(TObjArray *trk)
{
  // A rolling buffer (a double-ended queue) is updated by removing
  // the oldest event, and appending the newest.

  static Int_t iEvent = -1;
  iEvent++;

  Int_t mult = trk->GetEntries();
  Int_t nTrk = NTracksInPool();

  if (nTrk < fTargetTrackDepth && ((nTrk + mult) >= fTargetTrackDepth))
    fNTimes++;

  // remove 0th element before appending this event
  Bool_t removeFirstEvent = 0;
  if (nTrk>fTargetTrackDepth) {
    Int_t nTrksFirstEvent= fNTracksInEvent.front();
    Int_t diff = nTrk - nTrksFirstEvent + mult;
    if (diff>fTargetTrackDepth)
      removeFirstEvent = 1;
  }
  if (removeFirstEvent) {
    TObjArray *fa = fEvents.front();
    delete fa;
    fEvents.pop_front();         // remove first track array
    fNTracksInEvent.pop_front(); // remove first int
    fEventIndex.pop_front();
  }

  fNTracksInEvent.push_back(mult);
  fEvents.push_back(trk);
  fEventIndex.push_back(iEvent);

  if (fNTimes==1) {
    fFirstFilled = kTRUE;
    if (1||AliEventPool::fDebug) {
      cout << "\nPool " << MultBinIndex() << ", " << ZvtxBinIndex()
           << " ready at event "<< iEvent;
      PrintInfo();
      cout << endl;
    }
    fNTimes++; // See this message exactly once/pool
  } else {
    fFirstFilled = kFALSE;
  }

  fWasUpdated = true;

  if (AliEventPool::fDebug) {
    cout << " Event " << fEventIndex.back();
    cout << " PoolDepth = " << GetCurrentNEvents();
    cout << " NTracksInCurrentEvent = " << NTracksInCurrentEvent();
  }

  return fEvents.size();
}

TObject* AliEventPool::GetRandomTrack() const
{
  // Get any random track from the pool, sampled with uniform probability.

  UInt_t ranEvt = gRandom->Integer(fEvents.size());
  TObjArray *tca = fEvents.at(ranEvt);
  UInt_t ranTrk = gRandom->Integer(tca->GetEntries());
  TObject *trk = (TObject*)tca->At(ranTrk);
  return trk;
}

TObjArray* AliEventPool::GetEvent(Int_t i) const
{
  if (i<0 || i>=(Int_t)fEvents.size()) {
    cout << "AliEventPool::GetEvent("
	 << i << "): Invalid index" << endl;
    return 0x0;
  }

  TObjArray *tca = fEvents.at(i);
  return tca;
}

TObjArray* AliEventPool::GetRandomEvent() const
{
  UInt_t ranEvt = gRandom->Integer(fEvents.size());
  TObjArray *tca = fEvents.at(ranEvt);
  return tca;
}

Int_t AliEventPool::NTracksInEvent(Int_t iEvent) const
{
  // Return number of tracks in iEvent, which is the local pool index.

  Int_t n = -1;
  Int_t curEvent = fEventIndex.back();
  Int_t offset = curEvent - iEvent;
  Int_t pos = fEventIndex.size() - offset - 1;

  if (offset==0)
    n = fNTracksInEvent.back();
  else if (offset < 0 || iEvent < 0) {
    n = 0;
  }
  else if (offset > 0 && offset <= (int)fEventIndex.size()) {
    n = fNTracksInEvent.at(pos);
  }
  else
    cout << "Event info no longer in memory" << endl;
  return n;
}

ClassImp(AliEventPoolManager)

AliEventPoolManager::AliEventPoolManager(Int_t depth,     Int_t minNTracks,
				   Int_t nMultBins, Double_t *multbins,
				   Int_t nZvtxBins, Double_t *zvtxbins) :
fDebug(0), fNMultBins(0), fNZvtxBins(0), fEvPool(0), fTargetTrackDepth(minNTracks)
{
  // Constructor.

  InitEventPools(depth, nMultBins, multbins, nZvtxBins, zvtxbins);
  cout << "AliEventPoolManager initialized." << endl;
}

Int_t AliEventPoolManager::InitEventPools(Int_t depth,
                                       Int_t nMultBins, Double_t *multbin,
                                       Int_t nZvtxBins, Double_t *zvtxbin)
{
  // Assign AliEventPoolManager members.

  fNMultBins = nMultBins;
  fNZvtxBins = nZvtxBins;

  for (Int_t iM=0; iM<nMultBins; iM++) {
    std::vector<AliEventPool*> evp;
    for (Int_t iZ=0; iZ<nZvtxBins; iZ++) {
      evp.push_back(new AliEventPool(depth,
                                         multbin[iM], multbin[iM+1],
                                         zvtxbin[iZ], zvtxbin[iZ+1] ));
    }
    fEvPool.push_back(evp);
  }

  for (Int_t iM=0; iM<nMultBins; iM++) {
    for (Int_t iZ=0; iZ<nZvtxBins; iZ++) {
      fEvPool.at(iM).at(iZ)->SetMultBinIndex(iM);
      fEvPool.at(iM).at(iZ)->SetZvtxBinIndex(iZ);
      fEvPool.at(iM).at(iZ)->SetTargetTrackDepth(fTargetTrackDepth);
    }
  }

  if (0) {
    cout << "fEvPool outer size: " << fEvPool.size() << endl;
    for (Int_t iM=0; iM<nMultBins; iM++) {
      for (Int_t iZ=0; iZ<nZvtxBins; iZ++) {
	if(fEvPool.at(iM).at(iZ)) {
	  cout << "multiplicity bin: " << iM;
	  cout << ", z-vertex bin: " << iZ;
	  fEvPool.at(iM).at(iZ)->PrintInfo();
	}
      }
    }
  }

  return fEvPool.size();
}

AliEventPool *AliEventPoolManager::GetEventPool(Int_t iMult, Int_t iZvtx) const
{
  if (iMult < 0 || iMult >= fNMultBins)
    return 0x0;
  if (iZvtx < 0 || iZvtx >= fNZvtxBins)
    return 0x0;
  return fEvPool.at(iMult).at(iZvtx);
}

AliEventPool *AliEventPoolManager::GetEventPool(Int_t centVal, Double_t zVtxVal) const
{
  return GetEventPool((Double_t)centVal, zVtxVal);
}

AliEventPool *AliEventPoolManager::GetEventPool(Double_t centVal, Double_t zVtxVal) const
{
  // Return appropriate pool for this centrality and z-vertex value.

  for (Int_t iM=0; iM<fNMultBins; iM++) {
    for (Int_t iZ=0; iZ<fNZvtxBins; iZ++) {
      AliEventPool* pool = GetEventPool(iM, iZ);
      if (pool->EventMatchesBin(centVal, zVtxVal))
	return pool;
    }
  }
  return 0x0;
}

Int_t AliEventPoolManager::UpdatePools(TObjArray *trk)
{
  // Call UpdatePool for all bins.

  for (Int_t iM=0; iM<fNMultBins; iM++) {
    for (Int_t iZ=0; iZ<fNZvtxBins; iZ++) {
      if (fEvPool.at(iM).at(iZ)->UpdatePool(trk) > -1)
        break;
    }
  }
  return 0;
}
<commit_msg>Forgotten debug statement<commit_after>#include "AliEventPoolManager.h"

ClassImp(AliEventPool)

void AliEventPool::PrintInfo() const
{
  cout << Form("%20s: %d events", "Pool capacity", fMixDepth) << endl;
  cout << Form("%20s: %d events, %d tracks", "Current size",
	       GetCurrentNEvents(), NTracksInPool()) << endl;
  cout << Form("%20s: %.1f to %.1f", "Sub-event mult.", fMultMin, fMultMax) << endl;
  cout << Form("%20s: %.1f to %.1f", "Z-vtx range", fZvtxMin, fZvtxMax) << endl;

  return;
}

Bool_t AliEventPool::EventMatchesBin(Int_t mult, Double_t zvtx) const
{
  return EventMatchesBin((Double_t) mult, zvtx);
}

Bool_t AliEventPool::EventMatchesBin(Double_t mult, Double_t zvtx) const
{
  // Lower bin limit included; upper limit excluded.

  Bool_t multOK = (mult >= fMultMin && mult < fMultMax);
  Bool_t zvtxOK = (zvtx >= fZvtxMin && zvtx < fZvtxMax);
  return (multOK && zvtxOK);
}

Int_t AliEventPool::NTracksInPool() const
{
  // Number of tracks for this cent, zvtx bin; possibly includes many
  // events.

  Int_t ntrk=0;
  for (Int_t i=0; i<(Int_t)fEvents.size(); ++i) {
    ntrk += fNTracksInEvent.at(i);
  }
  return ntrk;
}

Int_t AliEventPool::SetEventMultRange(Int_t multMin, Int_t multMax)
{
  fMultMin = (Double_t)multMin;
  fMultMax = (Double_t)multMax;
  return 0;
}

Int_t AliEventPool::SetEventMultRange(Double_t multMin, Double_t multMax)
{
  fMultMin = multMin;
  fMultMax = multMax;
  return 0;
}

Int_t AliEventPool::SetEventZvtxRange(Double_t zvtxMin, Double_t zvtxMax)
{
  fZvtxMin = zvtxMin;
  fZvtxMax = zvtxMax;
  return 0;
}

Int_t AliEventPool::GlobalEventIndex(Int_t j) const
{
  // Index returned from passing local pool event index.

  if (j < 0 || j >= (Int_t)fEventIndex.size()) {
    cout << "ERROR in AliEventPool::GlobalEventIndex(): "
	 << " Invalid index " << j << endl;
    return -99;
  }
  return fEventIndex.at(j);
}

Int_t AliEventPool::UpdatePool(TObjArray *trk)
{
  // A rolling buffer (a double-ended queue) is updated by removing
  // the oldest event, and appending the newest.

  static Int_t iEvent = -1;
  iEvent++;

  Int_t mult = trk->GetEntries();
  Int_t nTrk = NTracksInPool();

  if (nTrk < fTargetTrackDepth && ((nTrk + mult) >= fTargetTrackDepth))
    fNTimes++;

  // remove 0th element before appending this event
  Bool_t removeFirstEvent = 0;
  if (nTrk>fTargetTrackDepth) {
    Int_t nTrksFirstEvent= fNTracksInEvent.front();
    Int_t diff = nTrk - nTrksFirstEvent + mult;
    if (diff>fTargetTrackDepth)
      removeFirstEvent = 1;
  }
  if (removeFirstEvent) {
    TObjArray *fa = fEvents.front();
    delete fa;
    fEvents.pop_front();         // remove first track array
    fNTracksInEvent.pop_front(); // remove first int
    fEventIndex.pop_front();
  }

  fNTracksInEvent.push_back(mult);
  fEvents.push_back(trk);
  fEventIndex.push_back(iEvent);

  if (fNTimes==1) {
    fFirstFilled = kTRUE;
    if (AliEventPool::fDebug) {
      cout << "\nPool " << MultBinIndex() << ", " << ZvtxBinIndex()
           << " ready at event "<< iEvent;
      PrintInfo();
      cout << endl;
    }
    fNTimes++; // See this message exactly once/pool
  } else {
    fFirstFilled = kFALSE;
  }

  fWasUpdated = true;

  if (AliEventPool::fDebug) {
    cout << " Event " << fEventIndex.back();
    cout << " PoolDepth = " << GetCurrentNEvents();
    cout << " NTracksInCurrentEvent = " << NTracksInCurrentEvent();
  }

  return fEvents.size();
}

TObject* AliEventPool::GetRandomTrack() const
{
  // Get any random track from the pool, sampled with uniform probability.

  UInt_t ranEvt = gRandom->Integer(fEvents.size());
  TObjArray *tca = fEvents.at(ranEvt);
  UInt_t ranTrk = gRandom->Integer(tca->GetEntries());
  TObject *trk = (TObject*)tca->At(ranTrk);
  return trk;
}

TObjArray* AliEventPool::GetEvent(Int_t i) const
{
  if (i<0 || i>=(Int_t)fEvents.size()) {
    cout << "AliEventPool::GetEvent("
	 << i << "): Invalid index" << endl;
    return 0x0;
  }

  TObjArray *tca = fEvents.at(i);
  return tca;
}

TObjArray* AliEventPool::GetRandomEvent() const
{
  UInt_t ranEvt = gRandom->Integer(fEvents.size());
  TObjArray *tca = fEvents.at(ranEvt);
  return tca;
}

Int_t AliEventPool::NTracksInEvent(Int_t iEvent) const
{
  // Return number of tracks in iEvent, which is the local pool index.

  Int_t n = -1;
  Int_t curEvent = fEventIndex.back();
  Int_t offset = curEvent - iEvent;
  Int_t pos = fEventIndex.size() - offset - 1;

  if (offset==0)
    n = fNTracksInEvent.back();
  else if (offset < 0 || iEvent < 0) {
    n = 0;
  }
  else if (offset > 0 && offset <= (int)fEventIndex.size()) {
    n = fNTracksInEvent.at(pos);
  }
  else
    cout << "Event info no longer in memory" << endl;
  return n;
}

ClassImp(AliEventPoolManager)

AliEventPoolManager::AliEventPoolManager(Int_t depth,     Int_t minNTracks,
				   Int_t nMultBins, Double_t *multbins,
				   Int_t nZvtxBins, Double_t *zvtxbins) :
fDebug(0), fNMultBins(0), fNZvtxBins(0), fEvPool(0), fTargetTrackDepth(minNTracks)
{
  // Constructor.

  InitEventPools(depth, nMultBins, multbins, nZvtxBins, zvtxbins);
  cout << "AliEventPoolManager initialized." << endl;
}

Int_t AliEventPoolManager::InitEventPools(Int_t depth,
                                       Int_t nMultBins, Double_t *multbin,
                                       Int_t nZvtxBins, Double_t *zvtxbin)
{
  // Assign AliEventPoolManager members.

  fNMultBins = nMultBins;
  fNZvtxBins = nZvtxBins;

  for (Int_t iM=0; iM<nMultBins; iM++) {
    std::vector<AliEventPool*> evp;
    for (Int_t iZ=0; iZ<nZvtxBins; iZ++) {
      evp.push_back(new AliEventPool(depth,
                                         multbin[iM], multbin[iM+1],
                                         zvtxbin[iZ], zvtxbin[iZ+1] ));
    }
    fEvPool.push_back(evp);
  }

  for (Int_t iM=0; iM<nMultBins; iM++) {
    for (Int_t iZ=0; iZ<nZvtxBins; iZ++) {
      fEvPool.at(iM).at(iZ)->SetMultBinIndex(iM);
      fEvPool.at(iM).at(iZ)->SetZvtxBinIndex(iZ);
      fEvPool.at(iM).at(iZ)->SetTargetTrackDepth(fTargetTrackDepth);
    }
  }

  if (0) {
    cout << "fEvPool outer size: " << fEvPool.size() << endl;
    for (Int_t iM=0; iM<nMultBins; iM++) {
      for (Int_t iZ=0; iZ<nZvtxBins; iZ++) {
	if(fEvPool.at(iM).at(iZ)) {
	  cout << "multiplicity bin: " << iM;
	  cout << ", z-vertex bin: " << iZ;
	  fEvPool.at(iM).at(iZ)->PrintInfo();
	}
      }
    }
  }

  return fEvPool.size();
}

AliEventPool *AliEventPoolManager::GetEventPool(Int_t iMult, Int_t iZvtx) const
{
  if (iMult < 0 || iMult >= fNMultBins)
    return 0x0;
  if (iZvtx < 0 || iZvtx >= fNZvtxBins)
    return 0x0;
  return fEvPool.at(iMult).at(iZvtx);
}

AliEventPool *AliEventPoolManager::GetEventPool(Int_t centVal, Double_t zVtxVal) const
{
  return GetEventPool((Double_t)centVal, zVtxVal);
}

AliEventPool *AliEventPoolManager::GetEventPool(Double_t centVal, Double_t zVtxVal) const
{
  // Return appropriate pool for this centrality and z-vertex value.

  for (Int_t iM=0; iM<fNMultBins; iM++) {
    for (Int_t iZ=0; iZ<fNZvtxBins; iZ++) {
      AliEventPool* pool = GetEventPool(iM, iZ);
      if (pool->EventMatchesBin(centVal, zVtxVal))
	return pool;
    }
  }
  return 0x0;
}

Int_t AliEventPoolManager::UpdatePools(TObjArray *trk)
{
  // Call UpdatePool for all bins.

  for (Int_t iM=0; iM<fNMultBins; iM++) {
    for (Int_t iZ=0; iZ<fNZvtxBins; iZ++) {
      if (fEvPool.at(iM).at(iZ)->UpdatePool(trk) > -1)
        break;
    }
  }
  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Remove in-bunch pileup events in MC<commit_after><|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMarchingContourFilter.cxx

  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.

     THIS CLASS IS PATENTED UNDER UNITED STATES PATENT NUMBER 4,710,876
     "System and Method for the Display of Surface Structures Contained
     Within the Interior Region of a Solid Body".
     Application of this software for commercial purposes requires
     a license grant from GE. Contact:

         Carl B. Horton
         Sr. Counsel, Intellectual Property
         3000 N. Grandview Blvd., W-710
         Waukesha, WI  53188
         Phone:  (262) 513-4022
         E-Mail: Carl.Horton@med.ge.com

     for more information.

=========================================================================*/
#include "vtkMarchingContourFilter.h"

#include "vtkCell.h"
#include "vtkContourFilter.h"
#include "vtkContourValues.h"
#include "vtkImageMarchingCubes.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMarchingCubes.h"
#include "vtkMarchingSquares.h"
#include "vtkMergePoints.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkScalarTree.h"
#include "vtkStructuredPoints.h"

#include <math.h>

vtkCxxRevisionMacro(vtkMarchingContourFilter, "1.28");
vtkStandardNewMacro(vtkMarchingContourFilter);

// Construct object with initial range (0,1) and single contour value
// of 0.0.
vtkMarchingContourFilter::vtkMarchingContourFilter()
{
  this->ContourValues = vtkContourValues::New();

  this->ComputeNormals = 1;
  this->ComputeGradients = 0;
  this->ComputeScalars = 1;

  this->Locator = NULL;

  this->UseScalarTree = 0;
  this->ScalarTree = NULL;
}

vtkMarchingContourFilter::~vtkMarchingContourFilter()
{
  this->ContourValues->Delete();
  if ( this->Locator )
    {
    this->Locator->UnRegister(this);
    this->Locator = NULL;
    }
  if ( this->ScalarTree )
    {
    this->ScalarTree->Delete();
    }
}

// Overload standard modified time function. If contour values are modified,
// then this object is modified as well.
unsigned long vtkMarchingContourFilter::GetMTime()
{
  unsigned long mTime=this->Superclass::GetMTime();
  unsigned long time;

  if (this->ContourValues)
    {
    time = this->ContourValues->GetMTime();
    mTime = ( time > mTime ? time : mTime );
    }
  if (this->Locator)
    {
    time = this->Locator->GetMTime();
    mTime = ( time > mTime ? time : mTime );
    }

  return mTime;
}

//
// General contouring filter.  Handles arbitrary input.
//
int vtkMarchingContourFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and ouptut
  vtkDataSet *input = vtkDataSet::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkDataArray *inScalars;
  vtkIdType numCells;

  vtkDebugMacro(<< "Executing marching contour filter");

  numCells = input->GetNumberOfCells();
  inScalars = input->GetPointData()->GetScalars();
  if ( ! inScalars || numCells < 1 )
    {
    vtkErrorMacro(<<"No data to contour");
    return 1;
    }

  // If structured points, use more efficient algorithms
  if ( (input->GetDataObjectType() == VTK_STRUCTURED_POINTS))
    {
    if (inScalars->GetDataType() != VTK_BIT)
      {
      int dim = input->GetCell(0)->GetCellDimension();

      if ( input->GetCell(0)->GetCellDimension() >= 2 )
        {
        vtkDebugMacro(<< "Structured Points");
        this->StructuredPointsContour(dim, input, output);
        return 1;
        }
      }
    }

  if ( (input->GetDataObjectType() == VTK_IMAGE_DATA))
    {
    if (inScalars->GetDataType() != VTK_BIT)
      {
      int dim = input->GetCell(0)->GetCellDimension();

      if ( input->GetCell(0)->GetCellDimension() >= 2 )
        {
        vtkDebugMacro(<< "Image");
        this->ImageContour(dim, input, output);
        return 1;
        }
      }
    }

  vtkDebugMacro(<< "Unoptimized");
  this->DataSetContour(input, output);

  return 1;
}

void vtkMarchingContourFilter::StructuredPointsContour(int dim,
                                                       vtkDataSet *input,
                                                       vtkPolyData *thisOutput)
{
  vtkPolyData *output;
  int numContours=this->ContourValues->GetNumberOfContours();
  double *values=this->ContourValues->GetValues();

  if ( dim == 2 ) //marching squares
    {
    vtkMarchingSquares *msquares;
    int i;

    msquares = vtkMarchingSquares::New();
    msquares->SetInput((vtkImageData *)input);
    msquares->SetDebug(this->Debug);
    msquares->SetNumberOfContours(numContours);
    for (i=0; i < numContours; i++)
      {
      msquares->SetValue(i,values[i]);
      }

    msquares->Update();
    output = msquares->GetOutput();
    output->Register(this);
    msquares->Delete();
    }

  else //marching cubes
    {
    vtkMarchingCubes *mcubes;
    int i;

    mcubes = vtkMarchingCubes::New();
    mcubes->SetInput((vtkImageData *)input);
    mcubes->SetComputeNormals (this->ComputeNormals);
    mcubes->SetComputeGradients (this->ComputeGradients);
    mcubes->SetComputeScalars (this->ComputeScalars);
    mcubes->SetDebug(this->Debug);
    mcubes->SetNumberOfContours(numContours);
    for (i=0; i < numContours; i++)
      {
      mcubes->SetValue(i,values[i]);
      }

    mcubes->Update();
    output = mcubes->GetOutput();
    output->Register(this);
    mcubes->Delete();
    }

  thisOutput->CopyStructure(output);
  thisOutput->GetPointData()->ShallowCopy(output->GetPointData());
  output->UnRegister(this);
}

void vtkMarchingContourFilter::DataSetContour(vtkDataSet *input,
                                              vtkPolyData *output)
{
  int numContours=this->ContourValues->GetNumberOfContours();
  double *values=this->ContourValues->GetValues();

  vtkContourFilter *contour = vtkContourFilter::New();
  contour->SetInput((vtkImageData *)input);
  contour->SetComputeNormals (this->ComputeNormals);
  contour->SetComputeGradients (this->ComputeGradients);
  contour->SetComputeScalars (this->ComputeScalars);
  contour->SetDebug(this->Debug);
  contour->SetNumberOfContours(numContours);
  for (int i=0; i < numContours; i++)
    {
    contour->SetValue(i,values[i]);
    }

  contour->Update();
  output->ShallowCopy(contour->GetOutput());
  this->SetOutput(output);
  contour->Delete();
}

void vtkMarchingContourFilter::ImageContour(int dim, vtkDataSet *input,
                                            vtkPolyData *output)
{
  int numContours=this->ContourValues->GetNumberOfContours();
  double *values=this->ContourValues->GetValues();

  if ( dim == 2 ) //marching squares
    {
    vtkMarchingSquares *msquares;
    int i;

    msquares = vtkMarchingSquares::New();
    msquares->SetInput((vtkImageData *)input);
    msquares->SetOutput(output);
    msquares->SetDebug(this->Debug);
    msquares->SetNumberOfContours(numContours);
    for (i=0; i < numContours; i++)
      {
      msquares->SetValue(i,values[i]);
      }

    msquares->Update();
    this->SetOutput(output);
    msquares->Delete();
    }

  else //image marching cubes
    {
    vtkImageMarchingCubes *mcubes;
    int i;

    mcubes = vtkImageMarchingCubes::New();
    mcubes->SetInput((vtkImageData *)input);
    mcubes->SetOutput(output);
    mcubes->SetComputeNormals (this->ComputeNormals);
    mcubes->SetComputeGradients (this->ComputeGradients);
    mcubes->SetComputeScalars (this->ComputeScalars);
    mcubes->SetDebug(this->Debug);
    mcubes->SetNumberOfContours(numContours);
    for (i=0; i < numContours; i++)
      {
      mcubes->SetValue(i,values[i]);
      }

    mcubes->Update();
    this->SetOutput(output);
    mcubes->Delete();
    }
}

// Specify a spatial locator for merging points. By default,
// an instance of vtkMergePoints is used.
void vtkMarchingContourFilter::SetLocator(vtkPointLocator *locator)
{
  if ( this->Locator == locator )
    {
    return;
    }
  if ( this->Locator )
    {
    this->Locator->UnRegister(this);
    this->Locator = NULL;
    }
  if ( locator )
    {
    locator->Register(this);
    }
  this->Locator = locator;
  this->Modified();
}

void vtkMarchingContourFilter::CreateDefaultLocator()
{
  if ( this->Locator == NULL )
    {
    this->Locator = vtkMergePoints::New();
    }
}

void vtkMarchingContourFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Compute Gradients: " << (this->ComputeGradients ? "On\n" : "Off\n");
  os << indent << "Compute Normals: " << (this->ComputeNormals ? "On\n" : "Off\n");
  os << indent << "Compute Scalars: " << (this->ComputeScalars ? "On\n" : "Off\n");
  os << indent << "Use Scalar Tree: " << (this->UseScalarTree ? "On\n" : "Off\n");

  this->ContourValues->PrintSelf(os,indent.GetNextIndent());

  if ( this->Locator )
    {
    os << indent << "Locator: " << this->Locator << "\n";
    }
  else
    {
    os << indent << "Locator: (none)\n";
    }
}
<commit_msg>ENH: avoid calling SetOutput - get rid of VTK errors<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMarchingContourFilter.cxx

  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.

     THIS CLASS IS PATENTED UNDER UNITED STATES PATENT NUMBER 4,710,876
     "System and Method for the Display of Surface Structures Contained
     Within the Interior Region of a Solid Body".
     Application of this software for commercial purposes requires
     a license grant from GE. Contact:

         Carl B. Horton
         Sr. Counsel, Intellectual Property
         3000 N. Grandview Blvd., W-710
         Waukesha, WI  53188
         Phone:  (262) 513-4022
         E-Mail: Carl.Horton@med.ge.com

     for more information.

=========================================================================*/
#include "vtkMarchingContourFilter.h"

#include "vtkCell.h"
#include "vtkContourFilter.h"
#include "vtkContourValues.h"
#include "vtkImageMarchingCubes.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMarchingCubes.h"
#include "vtkMarchingSquares.h"
#include "vtkMergePoints.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkScalarTree.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkStructuredPoints.h"

#include <math.h>

vtkCxxRevisionMacro(vtkMarchingContourFilter, "1.29");
vtkStandardNewMacro(vtkMarchingContourFilter);

// Construct object with initial range (0,1) and single contour value
// of 0.0.
vtkMarchingContourFilter::vtkMarchingContourFilter()
{
  this->ContourValues = vtkContourValues::New();

  this->ComputeNormals = 1;
  this->ComputeGradients = 0;
  this->ComputeScalars = 1;

  this->Locator = NULL;

  this->UseScalarTree = 0;
  this->ScalarTree = NULL;
}

vtkMarchingContourFilter::~vtkMarchingContourFilter()
{
  this->ContourValues->Delete();
  if ( this->Locator )
    {
    this->Locator->UnRegister(this);
    this->Locator = NULL;
    }
  if ( this->ScalarTree )
    {
    this->ScalarTree->Delete();
    }
}

// Overload standard modified time function. If contour values are modified,
// then this object is modified as well.
unsigned long vtkMarchingContourFilter::GetMTime()
{
  unsigned long mTime=this->Superclass::GetMTime();
  unsigned long time;

  if (this->ContourValues)
    {
    time = this->ContourValues->GetMTime();
    mTime = ( time > mTime ? time : mTime );
    }
  if (this->Locator)
    {
    time = this->Locator->GetMTime();
    mTime = ( time > mTime ? time : mTime );
    }

  return mTime;
}

//
// General contouring filter.  Handles arbitrary input.
//
int vtkMarchingContourFilter::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and ouptut
  vtkDataSet *input = vtkDataSet::SafeDownCast(
    inInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkDataArray *inScalars;
  vtkIdType numCells;

  vtkDebugMacro(<< "Executing marching contour filter");

  numCells = input->GetNumberOfCells();
  inScalars = input->GetPointData()->GetScalars();
  if ( ! inScalars || numCells < 1 )
    {
    vtkErrorMacro(<<"No data to contour");
    return 1;
    }

  // If structured points, use more efficient algorithms
  if ( (input->GetDataObjectType() == VTK_STRUCTURED_POINTS))
    {
    if (inScalars->GetDataType() != VTK_BIT)
      {
      int dim = input->GetCell(0)->GetCellDimension();

      if ( input->GetCell(0)->GetCellDimension() >= 2 )
        {
        vtkDebugMacro(<< "Structured Points");
        this->StructuredPointsContour(dim, input, output);
        return 1;
        }
      }
    }

  if ( (input->GetDataObjectType() == VTK_IMAGE_DATA))
    {
    if (inScalars->GetDataType() != VTK_BIT)
      {
      int dim = input->GetCell(0)->GetCellDimension();

      if ( input->GetCell(0)->GetCellDimension() >= 2 )
        {
        vtkDebugMacro(<< "Image");
        this->ImageContour(dim, input, output);
        return 1;
        }
      }
    }

  vtkDebugMacro(<< "Unoptimized");
  this->DataSetContour(input, output);

  return 1;
}

void vtkMarchingContourFilter::StructuredPointsContour(int dim,
                                                       vtkDataSet *input,
                                                       vtkPolyData *thisOutput)
{
  vtkPolyData *output;
  int numContours=this->ContourValues->GetNumberOfContours();
  double *values=this->ContourValues->GetValues();

  if ( dim == 2 ) //marching squares
    {
    vtkMarchingSquares *msquares;
    int i;

    msquares = vtkMarchingSquares::New();
    msquares->SetInput((vtkImageData *)input);
    msquares->SetDebug(this->Debug);
    msquares->SetNumberOfContours(numContours);
    for (i=0; i < numContours; i++)
      {
      msquares->SetValue(i,values[i]);
      }

    msquares->Update();
    output = msquares->GetOutput();
    output->Register(this);
    msquares->Delete();
    }

  else //marching cubes
    {
    vtkMarchingCubes *mcubes;
    int i;

    mcubes = vtkMarchingCubes::New();
    mcubes->SetInput((vtkImageData *)input);
    mcubes->SetComputeNormals (this->ComputeNormals);
    mcubes->SetComputeGradients (this->ComputeGradients);
    mcubes->SetComputeScalars (this->ComputeScalars);
    mcubes->SetDebug(this->Debug);
    mcubes->SetNumberOfContours(numContours);
    for (i=0; i < numContours; i++)
      {
      mcubes->SetValue(i,values[i]);
      }

    mcubes->Update();
    output = mcubes->GetOutput();
    output->Register(this);
    mcubes->Delete();
    }

  thisOutput->CopyStructure(output);
  thisOutput->GetPointData()->ShallowCopy(output->GetPointData());
  output->UnRegister(this);
}

void vtkMarchingContourFilter::DataSetContour(vtkDataSet *input,
                                              vtkPolyData *output)
{
  int numContours=this->ContourValues->GetNumberOfContours();
  double *values=this->ContourValues->GetValues();

  vtkContourFilter *contour = vtkContourFilter::New();
  contour->SetInput((vtkImageData *)input);
  contour->SetComputeNormals (this->ComputeNormals);
  contour->SetComputeGradients (this->ComputeGradients);
  contour->SetComputeScalars (this->ComputeScalars);
  contour->SetDebug(this->Debug);
  contour->SetNumberOfContours(numContours);
  for (int i=0; i < numContours; i++)
    {
    contour->SetValue(i,values[i]);
    }

  contour->Update();
  output->ShallowCopy(contour->GetOutput());
  this->SetOutput(output);
  contour->Delete();
}

void vtkMarchingContourFilter::ImageContour(int dim, vtkDataSet *input,
                                            vtkPolyData *output)
{
  int numContours=this->ContourValues->GetNumberOfContours();
  double *values=this->ContourValues->GetValues();
  vtkPolyData *contourOutput;

  if ( dim == 2 ) //marching squares
    {
    vtkMarchingSquares *msquares;
    int i;

    msquares = vtkMarchingSquares::New();
    msquares->SetInput((vtkImageData *)input);
    msquares->SetDebug(this->Debug);
    msquares->SetNumberOfContours(numContours);
    for (i=0; i < numContours; i++)
      {
      msquares->SetValue(i,values[i]);
      }

    contourOutput = msquares->GetOutput();
    msquares->Update();
    output->ShallowCopy(contourOutput);
    msquares->Delete();
    }

  else //image marching cubes
    {
    vtkImageMarchingCubes *mcubes;
    int i;

    mcubes = vtkImageMarchingCubes::New();
    mcubes->SetInput((vtkImageData *)input);
    mcubes->SetComputeNormals (this->ComputeNormals);
    mcubes->SetComputeGradients (this->ComputeGradients);
    mcubes->SetComputeScalars (this->ComputeScalars);
    mcubes->SetDebug(this->Debug);
    mcubes->SetNumberOfContours(numContours);
    for (i=0; i < numContours; i++)
      {
      mcubes->SetValue(i,values[i]);
      }

    contourOutput = mcubes->GetOutput();
    mcubes->Update();
    output->ShallowCopy(contourOutput);
    mcubes->Delete();
    }
}

// Specify a spatial locator for merging points. By default,
// an instance of vtkMergePoints is used.
void vtkMarchingContourFilter::SetLocator(vtkPointLocator *locator)
{
  if ( this->Locator == locator )
    {
    return;
    }
  if ( this->Locator )
    {
    this->Locator->UnRegister(this);
    this->Locator = NULL;
    }
  if ( locator )
    {
    locator->Register(this);
    }
  this->Locator = locator;
  this->Modified();
}

void vtkMarchingContourFilter::CreateDefaultLocator()
{
  if ( this->Locator == NULL )
    {
    this->Locator = vtkMergePoints::New();
    }
}

void vtkMarchingContourFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "Compute Gradients: " << (this->ComputeGradients ? "On\n" : "Off\n");
  os << indent << "Compute Normals: " << (this->ComputeNormals ? "On\n" : "Off\n");
  os << indent << "Compute Scalars: " << (this->ComputeScalars ? "On\n" : "Off\n");
  os << indent << "Use Scalar Tree: " << (this->UseScalarTree ? "On\n" : "Off\n");

  this->ContourValues->PrintSelf(os,indent.GetNextIndent());

  if ( this->Locator )
    {
    os << indent << "Locator: " << this->Locator << "\n";
    }
  else
    {
    os << indent << "Locator: (none)\n";
    }
}
<|endoftext|>


<commit_before>/*******************************************************************************
 *  Copyright 2012-2019 Esri
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 ******************************************************************************/

#include "ArcGISArView.h"
#include "TransformationMatrix.h"
#include "TransformationMatrixCameraController.h"
#include <QQuickWindow>
#include <QScreen>

using namespace Esri::ArcGISRuntime;
using namespace Esri::ArcGISRuntime::Toolkit;
using namespace Esri::ArcGISRuntime::Toolkit::Internal;

/*!
  \class ArcGISArView
  \ingroup ArcGISQtToolkitAR
  \inmodule ArcGISQtToolkit
  \since Esri::ArcGISRuntime 100.6
  \brief A scene view for displaying ARKit/ARCore features on mobile devices.

  The Augmented Reality (AR) toolkit provides support for ARKit for iOS and
  ArCore for Android.
  This toolkit component allows quick and easy integration
  of AR into your application for a variety of scenarios.

  See \l {https://github.com/Esri/arcgis-runtime-toolkit-qt/blob/ArcGISARView/Common/AR/Ar.md} {additional details about using the ArcGISArView toolkit component}.
 */

/*!
  \brief A constructor that accepts an optional \a parent object.
 */
ArcGISArView::ArcGISArView(QQuickItem* parent):
  ArcGISArViewInterface(parent),
  m_tmcc(new TransformationMatrixCameraController(this)),
  m_initialTransformation(TransformationMatrix::createIdentityMatrix(this))
{
  connect(m_tmcc, &TransformationMatrixCameraController::originCameraChanged, this, &ArcGISArView::originCameraChanged);
}

/*!
  \internal

  \list
  \li \a renderVideoFeed - Set to \c true to render the camera frames in the background.
  \li \a tryUsingArKit - Set to \c true to use the AR framework, depending of the platform (ARKit
  in Android and ARKit in iOS).
  \li \a parent - optional parent object.
  \endlist
 */
ArcGISArView::ArcGISArView(bool renderVideoFeed, bool tryUsingArKit, QQuickItem* parent):
  ArcGISArViewInterface(renderVideoFeed, tryUsingArKit, parent),
  m_tmcc(new TransformationMatrixCameraController(this))
{
  connect(m_tmcc, &TransformationMatrixCameraController::originCameraChanged, this, &ArcGISArView::originCameraChanged);
}

/*!
   \brief The destructor.
 */
ArcGISArView::~ArcGISArView()
{
}

/*!
  \brief Gets the origin camera.
 */
Camera ArcGISArView::originCamera() const
{
  return Camera(m_originCamera);
}

/*!
  \property ArcGISArView::originCamera
  \brief Sets the origin camera of this ArcGISArView.
 */
void ArcGISArView::setOriginCamera(const Camera& originCamera)
{
  if (m_originCamera == originCamera)
    return;

  m_originCamera = originCamera;
  m_tmcc->setOriginCamera(originCamera);
  // don't emit originCameraChanged, this signal is emited by the core runtime
}

/*!
  \property ArcGISArView::sceneView
  \brief Gets the SceneView associated with this ArcGISArView.
 */
SceneQuickView* ArcGISArView::sceneView() const
{
  return m_sceneView;
}

/*!
  \brief Sets the scene view to \a sceneView.

  The space effect of the scene view is set to \c SpaceEffect::Transparent
  and the atmosphere effect is set to \c AtmosphereEffect::None.
 */
void ArcGISArView::setSceneView(SceneQuickView* sceneView)
{
  if (sceneView == m_sceneView)
    return;

  m_sceneView = sceneView;
  m_sceneView->setSpaceEffect(SpaceEffect::Transparent);
  m_sceneView->setAtmosphereEffect(AtmosphereEffect::None);
  m_sceneView->setManualRendering(true);
  m_sceneView->setCameraController(m_tmcc);

  connect(m_sceneView, &SceneQuickView::touched, this, [this](QTouchEvent& event)
  {
    setInitialTransformation(event.touchPoints().first().lastScreenPos().toPoint());
  });

  emit sceneViewChanged();
}

/*!
  \brief Sets the initial transformation used to offset the \l originCamera.

  The initial transformation is based on an AR point determined via existing plane hit detection
  from `screenPoint`. If an AR point cannot be determined, this method will return \c false.

  \list
    \li \a screenPoint - The screen point to determine the initialTransformation from.
  \endlist
 */
void ArcGISArView::setInitialTransformation(const QPoint& screenPoint)
{
  // Use the `hitTestInternal` method to get the matrix of `screenPoint`.
  const std::array<double, 7> hitResult = hitTestInternal(screenPoint.x(), screenPoint.y());
  // quaternionW can never be 0, this indicates an error occurred
  if (hitResult[3] == 0)
    return;

  // Set the `initialTransformation` as the AGSTransformationMatrix.identity - hit test matrix.
  const auto hitMatrix = std::unique_ptr<TransformationMatrix>(
        TransformationMatrix::createWithQuaternionAndTranslation(0.0, 0.0, 0.0, 1.0, hitResult[4], hitResult[5], hitResult[6]));
  Q_CHECK_PTR(hitMatrix.get());

  m_initialTransformation = TransformationMatrix::createIdentityMatrix()->subtractTransformation(hitMatrix.get(), this);
  Q_CHECK_PTR(m_initialTransformation);
}

/*!
  \brief Gets the location in the real world space corresponding to the screen
   point \a screenPoint.
 */
Point ArcGISArView::screenToLocation(const QPoint& screenPoint) const
{
  if (!m_sceneView)
    return Point();

  const std::array<double, 7> hitResult = hitTestInternal(screenPoint.x(), screenPoint.y());
  if (hitResult[0] == 0)
    return Point();

  auto hitMatrix = std::unique_ptr<TransformationMatrix>(
        TransformationMatrix::createWithQuaternionAndTranslation(
          hitResult[0], hitResult[1], hitResult[2], hitResult[3], hitResult[4], hitResult[5], hitResult[6]));

  auto currentViewpointMatrix = std::unique_ptr<TransformationMatrix>(
        m_sceneView->currentViewpointCamera().transformationMatrix());

  auto finalMatrix = std::unique_ptr<TransformationMatrix>(currentViewpointMatrix->addTransformation(hitMatrix.get()));
  return Camera(finalMatrix.get()).location();
}

/*!
  \brief Register the QML-creatable types provided by QR toolkit.

  This static function registers the QML types \l ArcGISArView and
  \c LocationDataSource in the QML engine.
  This function must be called before using the QML types.
 */
void ArcGISArView::qmlRegisterTypes()
{
  qmlRegisterType<Esri::ArcGISRuntime::Toolkit::ArcGISArView>("Esri.ArcGISArToolkit", 1, 0, "ArcGISArView");
  qmlRegisterType<Esri::ArcGISRuntime::Toolkit::LocationDataSource>("Esri.ArcGISArToolkit", 1, 0, "LocationDataSource");
}

/*!
  \internal
 */
void ArcGISArView::setTransformationMatrixInternal(double quaternionX, double quaternionY, double quaternionZ, double quaternionW,
                                                   double translationX, double translationY, double translationZ)
{
  auto matrix = std::unique_ptr<TransformationMatrix>(TransformationMatrix::createWithQuaternionAndTranslation(
                                                        quaternionX, quaternionY, quaternionZ, quaternionW,
                                                        translationX, translationY, translationZ));
  Q_CHECK_PTR(matrix.get());
  Q_CHECK_PTR(m_initialTransformation);
  auto finalMatrix = std::unique_ptr<TransformationMatrix>(m_initialTransformation->addTransformation(matrix.get()));

  Q_CHECK_PTR(m_tmcc);
  m_tmcc->setTransformationMatrix(finalMatrix.get());
}

/*!
  \internal
 */
void ArcGISArView::setFieldOfViewInternal(double xFocalLength, double yFocalLength,
                                          double xPrincipal, double yPrincipal,
                                          double xImageSize, double yImageSize)
{
  if (!m_sceneView)
    return;

  // get the screen orientation
  const Qt::ScreenOrientations orientation = window()->screen()->orientation();
  const DeviceOrientation deviceOrientation = toDeviceOrientation(orientation);

  // set the field of view
  m_sceneView->setFieldOfViewFromLensIntrinsics(xFocalLength, yFocalLength, xPrincipal, yPrincipal,
                                                xImageSize, yImageSize, deviceOrientation);
}

/*!
  \internal
 */
void ArcGISArView::renderFrameInternal()
{
  if (!m_sceneView)
    return;

  m_sceneView->renderFrame();
}

/*!
  \internal
 */
void ArcGISArView::setTranslationFactorInternal(double translationFactor)
{
  m_tmcc->setTranslationFactor(translationFactor);
}

/*!
  \internal
 */
void ArcGISArView::setLocationInternal(double latitude, double longitude, double altitude)
{
  if (m_tmcc->originCamera().isEmpty())
  {
    // create a new origin camera
    m_tmcc->setOriginCamera(Camera(latitude, longitude, altitude, 0.0, 90.0, 0.0));
  }
  else
  {
    // update the origin camera
    const Camera oldCamera = m_tmcc->originCamera();
    m_tmcc->setOriginCamera(Camera(latitude, longitude, altitude, oldCamera.heading(), 90.0, 0.0));
  }

  m_tmcc->setTransformationMatrix(TransformationMatrix::createIdentityMatrix(this));
}

/*!
  \internal
 */
void ArcGISArView::setHeadingInternal(double heading)
{
  if (m_tmcc->originCamera().isEmpty())
  {
    // create a new origin camera
    m_tmcc->setOriginCamera(Camera(0.0, 0.0, 0.0, heading, 90.0, 0.0));
  }
  else
  {
    // update the origin camera
    const Point oldLocation = m_tmcc->originCamera().location();
    m_tmcc->setOriginCamera(Camera(oldLocation.y(), oldLocation.x(), oldLocation.z(), heading, 90.0, 0.0));
  }
  m_tmcc->setTransformationMatrix(TransformationMatrix::createIdentityMatrix(this));
}

/*!
  \internal

  Resets the device tracking and related properties.
 */
void ArcGISArView::resetTrackingInternal()
{
  setOriginCamera(Camera());

  m_initialTransformation = TransformationMatrix::createIdentityMatrix(this);

  m_tmcc->setTransformationMatrix(m_initialTransformation);
}

/*!
  \internal

  Cast from Qt's screen orientation to ArcGIS Runtime's screen orientation.
 */
DeviceOrientation ArcGISArView::toDeviceOrientation(Qt::ScreenOrientations orientation)
{
  switch (orientation)
  {
    case Qt::PortraitOrientation:
      return DeviceOrientation::Portrait;
    case Qt::LandscapeOrientation:
      return DeviceOrientation::LandscapeRight;
    case Qt::InvertedPortraitOrientation:
      return DeviceOrientation::ReversePortrait;
    case Qt::InvertedLandscapeOrientation:
      return DeviceOrientation::LandscapeLeft;
    default:
      return DeviceOrientation::Portrait;
  }
}

// signals

/*!
  \fn void ArcGISArView::originCameraChanged();
  \brief Signal emitted when the \l originCamera property changes.
 */

/*!
  \fn void ArcGISArView::sceneViewChanged();
  \brief Signal emitted when the \l sceneView property changes.
 */

<commit_msg>Update AR.md link to point to master branch<commit_after>/*******************************************************************************
 *  Copyright 2012-2019 Esri
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 ******************************************************************************/

#include "ArcGISArView.h"
#include "TransformationMatrix.h"
#include "TransformationMatrixCameraController.h"
#include <QQuickWindow>
#include <QScreen>

using namespace Esri::ArcGISRuntime;
using namespace Esri::ArcGISRuntime::Toolkit;
using namespace Esri::ArcGISRuntime::Toolkit::Internal;

/*!
  \class ArcGISArView
  \ingroup ArcGISQtToolkitAR
  \inmodule ArcGISQtToolkit
  \since Esri::ArcGISRuntime 100.6
  \brief A scene view for displaying ARKit/ARCore features on mobile devices.

  The Augmented Reality (AR) toolkit provides support for ARKit for iOS and
  ArCore for Android.
  This toolkit component allows quick and easy integration
  of AR into your application for a variety of scenarios.

  See \l {https://github.com/Esri/arcgis-runtime-toolkit-qt/blob/master/Common/AR/Ar.md} {additional details about using the ArcGISArView toolkit component}.
 */

/*!
  \brief A constructor that accepts an optional \a parent object.
 */
ArcGISArView::ArcGISArView(QQuickItem* parent):
  ArcGISArViewInterface(parent),
  m_tmcc(new TransformationMatrixCameraController(this)),
  m_initialTransformation(TransformationMatrix::createIdentityMatrix(this))
{
  connect(m_tmcc, &TransformationMatrixCameraController::originCameraChanged, this, &ArcGISArView::originCameraChanged);
}

/*!
  \internal

  \list
  \li \a renderVideoFeed - Set to \c true to render the camera frames in the background.
  \li \a tryUsingArKit - Set to \c true to use the AR framework, depending of the platform (ARKit
  in Android and ARKit in iOS).
  \li \a parent - optional parent object.
  \endlist
 */
ArcGISArView::ArcGISArView(bool renderVideoFeed, bool tryUsingArKit, QQuickItem* parent):
  ArcGISArViewInterface(renderVideoFeed, tryUsingArKit, parent),
  m_tmcc(new TransformationMatrixCameraController(this))
{
  connect(m_tmcc, &TransformationMatrixCameraController::originCameraChanged, this, &ArcGISArView::originCameraChanged);
}

/*!
   \brief The destructor.
 */
ArcGISArView::~ArcGISArView()
{
}

/*!
  \brief Gets the origin camera.
 */
Camera ArcGISArView::originCamera() const
{
  return Camera(m_originCamera);
}

/*!
  \property ArcGISArView::originCamera
  \brief Sets the origin camera of this ArcGISArView.
 */
void ArcGISArView::setOriginCamera(const Camera& originCamera)
{
  if (m_originCamera == originCamera)
    return;

  m_originCamera = originCamera;
  m_tmcc->setOriginCamera(originCamera);
  // don't emit originCameraChanged, this signal is emited by the core runtime
}

/*!
  \property ArcGISArView::sceneView
  \brief Gets the SceneView associated with this ArcGISArView.
 */
SceneQuickView* ArcGISArView::sceneView() const
{
  return m_sceneView;
}

/*!
  \brief Sets the scene view to \a sceneView.

  The space effect of the scene view is set to \c SpaceEffect::Transparent
  and the atmosphere effect is set to \c AtmosphereEffect::None.
 */
void ArcGISArView::setSceneView(SceneQuickView* sceneView)
{
  if (sceneView == m_sceneView)
    return;

  m_sceneView = sceneView;
  m_sceneView->setSpaceEffect(SpaceEffect::Transparent);
  m_sceneView->setAtmosphereEffect(AtmosphereEffect::None);
  m_sceneView->setManualRendering(true);
  m_sceneView->setCameraController(m_tmcc);

  connect(m_sceneView, &SceneQuickView::touched, this, [this](QTouchEvent& event)
  {
    setInitialTransformation(event.touchPoints().first().lastScreenPos().toPoint());
  });

  emit sceneViewChanged();
}

/*!
  \brief Sets the initial transformation used to offset the \l originCamera.

  The initial transformation is based on an AR point determined via existing plane hit detection
  from `screenPoint`. If an AR point cannot be determined, this method will return \c false.

  \list
    \li \a screenPoint - The screen point to determine the initialTransformation from.
  \endlist
 */
void ArcGISArView::setInitialTransformation(const QPoint& screenPoint)
{
  // Use the `hitTestInternal` method to get the matrix of `screenPoint`.
  const std::array<double, 7> hitResult = hitTestInternal(screenPoint.x(), screenPoint.y());
  // quaternionW can never be 0, this indicates an error occurred
  if (hitResult[3] == 0)
    return;

  // Set the `initialTransformation` as the AGSTransformationMatrix.identity - hit test matrix.
  const auto hitMatrix = std::unique_ptr<TransformationMatrix>(
        TransformationMatrix::createWithQuaternionAndTranslation(0.0, 0.0, 0.0, 1.0, hitResult[4], hitResult[5], hitResult[6]));
  Q_CHECK_PTR(hitMatrix.get());

  m_initialTransformation = TransformationMatrix::createIdentityMatrix()->subtractTransformation(hitMatrix.get(), this);
  Q_CHECK_PTR(m_initialTransformation);
}

/*!
  \brief Gets the location in the real world space corresponding to the screen
   point \a screenPoint.
 */
Point ArcGISArView::screenToLocation(const QPoint& screenPoint) const
{
  if (!m_sceneView)
    return Point();

  const std::array<double, 7> hitResult = hitTestInternal(screenPoint.x(), screenPoint.y());
  if (hitResult[0] == 0)
    return Point();

  auto hitMatrix = std::unique_ptr<TransformationMatrix>(
        TransformationMatrix::createWithQuaternionAndTranslation(
          hitResult[0], hitResult[1], hitResult[2], hitResult[3], hitResult[4], hitResult[5], hitResult[6]));

  auto currentViewpointMatrix = std::unique_ptr<TransformationMatrix>(
        m_sceneView->currentViewpointCamera().transformationMatrix());

  auto finalMatrix = std::unique_ptr<TransformationMatrix>(currentViewpointMatrix->addTransformation(hitMatrix.get()));
  return Camera(finalMatrix.get()).location();
}

/*!
  \brief Register the QML-creatable types provided by QR toolkit.

  This static function registers the QML types \l ArcGISArView and
  \c LocationDataSource in the QML engine.
  This function must be called before using the QML types.
 */
void ArcGISArView::qmlRegisterTypes()
{
  qmlRegisterType<Esri::ArcGISRuntime::Toolkit::ArcGISArView>("Esri.ArcGISArToolkit", 1, 0, "ArcGISArView");
  qmlRegisterType<Esri::ArcGISRuntime::Toolkit::LocationDataSource>("Esri.ArcGISArToolkit", 1, 0, "LocationDataSource");
}

/*!
  \internal
 */
void ArcGISArView::setTransformationMatrixInternal(double quaternionX, double quaternionY, double quaternionZ, double quaternionW,
                                                   double translationX, double translationY, double translationZ)
{
  auto matrix = std::unique_ptr<TransformationMatrix>(TransformationMatrix::createWithQuaternionAndTranslation(
                                                        quaternionX, quaternionY, quaternionZ, quaternionW,
                                                        translationX, translationY, translationZ));
  Q_CHECK_PTR(matrix.get());
  Q_CHECK_PTR(m_initialTransformation);
  auto finalMatrix = std::unique_ptr<TransformationMatrix>(m_initialTransformation->addTransformation(matrix.get()));

  Q_CHECK_PTR(m_tmcc);
  m_tmcc->setTransformationMatrix(finalMatrix.get());
}

/*!
  \internal
 */
void ArcGISArView::setFieldOfViewInternal(double xFocalLength, double yFocalLength,
                                          double xPrincipal, double yPrincipal,
                                          double xImageSize, double yImageSize)
{
  if (!m_sceneView)
    return;

  // get the screen orientation
  const Qt::ScreenOrientations orientation = window()->screen()->orientation();
  const DeviceOrientation deviceOrientation = toDeviceOrientation(orientation);

  // set the field of view
  m_sceneView->setFieldOfViewFromLensIntrinsics(xFocalLength, yFocalLength, xPrincipal, yPrincipal,
                                                xImageSize, yImageSize, deviceOrientation);
}

/*!
  \internal
 */
void ArcGISArView::renderFrameInternal()
{
  if (!m_sceneView)
    return;

  m_sceneView->renderFrame();
}

/*!
  \internal
 */
void ArcGISArView::setTranslationFactorInternal(double translationFactor)
{
  m_tmcc->setTranslationFactor(translationFactor);
}

/*!
  \internal
 */
void ArcGISArView::setLocationInternal(double latitude, double longitude, double altitude)
{
  if (m_tmcc->originCamera().isEmpty())
  {
    // create a new origin camera
    m_tmcc->setOriginCamera(Camera(latitude, longitude, altitude, 0.0, 90.0, 0.0));
  }
  else
  {
    // update the origin camera
    const Camera oldCamera = m_tmcc->originCamera();
    m_tmcc->setOriginCamera(Camera(latitude, longitude, altitude, oldCamera.heading(), 90.0, 0.0));
  }

  m_tmcc->setTransformationMatrix(TransformationMatrix::createIdentityMatrix(this));
}

/*!
  \internal
 */
void ArcGISArView::setHeadingInternal(double heading)
{
  if (m_tmcc->originCamera().isEmpty())
  {
    // create a new origin camera
    m_tmcc->setOriginCamera(Camera(0.0, 0.0, 0.0, heading, 90.0, 0.0));
  }
  else
  {
    // update the origin camera
    const Point oldLocation = m_tmcc->originCamera().location();
    m_tmcc->setOriginCamera(Camera(oldLocation.y(), oldLocation.x(), oldLocation.z(), heading, 90.0, 0.0));
  }
  m_tmcc->setTransformationMatrix(TransformationMatrix::createIdentityMatrix(this));
}

/*!
  \internal

  Resets the device tracking and related properties.
 */
void ArcGISArView::resetTrackingInternal()
{
  setOriginCamera(Camera());

  m_initialTransformation = TransformationMatrix::createIdentityMatrix(this);

  m_tmcc->setTransformationMatrix(m_initialTransformation);
}

/*!
  \internal

  Cast from Qt's screen orientation to ArcGIS Runtime's screen orientation.
 */
DeviceOrientation ArcGISArView::toDeviceOrientation(Qt::ScreenOrientations orientation)
{
  switch (orientation)
  {
    case Qt::PortraitOrientation:
      return DeviceOrientation::Portrait;
    case Qt::LandscapeOrientation:
      return DeviceOrientation::LandscapeRight;
    case Qt::InvertedPortraitOrientation:
      return DeviceOrientation::ReversePortrait;
    case Qt::InvertedLandscapeOrientation:
      return DeviceOrientation::LandscapeLeft;
    default:
      return DeviceOrientation::Portrait;
  }
}

// signals

/*!
  \fn void ArcGISArView::originCameraChanged();
  \brief Signal emitted when the \l originCamera property changes.
 */

/*!
  \fn void ArcGISArView::sceneViewChanged();
  \brief Signal emitted when the \l sceneView property changes.
 */

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_X86_INTERRUPTS_HH__
#define __ARCH_X86_INTERRUPTS_HH__

#include "arch/x86/faults.hh"
#include "cpu/thread_context.hh"

namespace X86ISA
{

class Interrupts
{
  public:
    Interrupts()
    {
        clear_all();
    }

    int InterruptLevel(uint64_t softint)
    {
        panic("Interrupts::InterruptLevel unimplemented!\n");
        return 0;
    }

    void post(int int_num, int index)
    {
        panic("Interrupts::post unimplemented!\n");
    }

    void clear(int int_num, int index)
    {
        panic("Interrupts::clear unimplemented!\n");
    }

    void clear_all()
    {
        warn("Interrupts::clear_all unimplemented!\n");
    }

    bool check_interrupts(ThreadContext * tc) const
    {
        panic("Interrupts::check_interrupts unimplemented!\n");
        return false;
    }

    Fault getInterrupt(ThreadContext * tc)
    {
        panic("Interrupts::getInterrupt unimplemented!\n");
        return NoFault;
    }

    void updateIntrInfo(ThreadContext * tc)
    {
        panic("Interrupts::updateIntrInfo unimplemented!\n");
    }

    uint64_t get_vec(int int_num)
    {
        panic("Interrupts::get_vec unimplemented!\n");
        return 0;
    }

    void serialize(std::ostream & os)
    {
        panic("Interrupts::serialize unimplemented!\n");
    }

    void unserialize(Checkpoint * cp, const std::string & section)
    {
        panic("Interrupts::unserialize unimplemented!\n");
    }
};

};

#endif // __ARCH_X86_INTERRUPTS_HH__
<commit_msg>X86: Make the Interrupts class complain less.<commit_after>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_X86_INTERRUPTS_HH__
#define __ARCH_X86_INTERRUPTS_HH__

#include "arch/x86/faults.hh"
#include "cpu/thread_context.hh"

namespace X86ISA
{

class Interrupts
{
  public:
    Interrupts()
    {
        clear_all();
    }

    int InterruptLevel(uint64_t softint)
    {
        panic("Interrupts::InterruptLevel unimplemented!\n");
        return 0;
    }

    void post(int int_num, int index)
    {
        panic("Interrupts::post unimplemented!\n");
    }

    void clear(int int_num, int index)
    {
        warn("Interrupts::clear unimplemented!\n");
    }

    void clear_all()
    {
        warn("Interrupts::clear_all unimplemented!\n");
    }

    bool check_interrupts(ThreadContext * tc) const
    {
        return false;
    }

    Fault getInterrupt(ThreadContext * tc)
    {
        return NoFault;
    }

    void updateIntrInfo(ThreadContext * tc)
    {
        panic("Interrupts::updateIntrInfo unimplemented!\n");
    }

    uint64_t get_vec(int int_num)
    {
        panic("Interrupts::get_vec unimplemented!\n");
        return 0;
    }

    void serialize(std::ostream & os)
    {
        panic("Interrupts::serialize unimplemented!\n");
    }

    void unserialize(Checkpoint * cp, const std::string & section)
    {
        panic("Interrupts::unserialize unimplemented!\n");
    }
};

};

#endif // __ARCH_X86_INTERRUPTS_HH__
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/find_if.hpp>

#include "clustering_bounds_comparator.hh"
#include "database.hh"
#include "db/system_keyspace.hh"
#include "dht/i_partitioner.hh"
#include "mutation_reader.hh"
#include "partition_range_compat.hh"
#include "range.hh"
#include "service/storage_service.hh"
#include "stdx.hh"
#include "streamed_mutation.hh"
#include "sstables/sstables.hh"

namespace db {

namespace size_estimates {

class size_estimates_mutation_reader final : public mutation_reader::impl {
    struct token_range {
        bytes start;
        bytes end;
    };
    schema_ptr _schema;
    const dht::partition_range& _prange;
    const query::partition_slice& _slice;
    using ks_range = std::vector<sstring>;
    stdx::optional<ks_range> _keyspaces;
    ks_range::const_iterator _current_partition;
    streamed_mutation::forwarding _fwd;
public:
    size_estimates_mutation_reader(schema_ptr schema, const dht::partition_range& prange, const query::partition_slice& slice, streamed_mutation::forwarding fwd)
            : _schema(schema)
            , _prange(prange)
            , _slice(slice)
            , _fwd(fwd)
    { }

    virtual future<streamed_mutation_opt> operator()() override {
        // For each specified range, estimate (crudely) mean partition size and partitions count.
        auto& db = service::get_local_storage_proxy().get_db().local();
        if (!_keyspaces) {
            _keyspaces = get_keyspaces(*_schema, db, _prange);
            _current_partition = _keyspaces->begin();
        }
        if (_current_partition == _keyspaces->end()) {
            return make_ready_future<streamed_mutation_opt>();
        }
        return get_local_ranges().then([&db, this] (auto&& ranges) {
            auto estimates = this->estimates_for_current_keyspace(db, std::move(ranges));
            auto mutations = db::system_keyspace::make_size_estimates_mutation(*_current_partition, std::move(estimates));
            ++_current_partition;
            return streamed_mutation_opt(streamed_mutation_from_mutation(std::move(mutations), _fwd));
        });
    }
    /**
     * Returns the primary ranges for the local node.
     * Used for testing as well.
     */
    static future<std::vector<token_range>> get_local_ranges() {
        auto& ss = service::get_local_storage_service();
        return ss.get_local_tokens().then([&ss] (auto&& tokens) {
            auto ranges = ss.get_token_metadata().get_primary_ranges_for(std::move(tokens));
            std::vector<token_range> local_ranges;
            auto to_bytes = [](const stdx::optional<dht::token_range::bound>& b) {
                assert(b);
                return utf8_type->decompose(dht::global_partitioner().to_sstring(b->value()));
            };
            // We merge the ranges to be compatible with how Cassandra shows it's size estimates table.
            // All queries will be on that table, where all entries are text and there's no notion of
            // token ranges form the CQL point of view.
            auto left_inf = boost::find_if(ranges, [] (auto&& r) {
                return !r.start() || r.start()->value() == dht::minimum_token();
            });
            auto right_inf = boost::find_if(ranges, [] (auto&& r) {
                return !r.end() || r.start()->value() == dht::maximum_token();
            });
            if (left_inf != right_inf && left_inf != ranges.end() && right_inf != ranges.end()) {
                local_ranges.push_back(token_range{to_bytes(right_inf->start()), to_bytes(left_inf->end())});
                ranges.erase(left_inf);
                ranges.erase(right_inf);
            }
            for (auto&& r : ranges) {
                local_ranges.push_back(token_range{to_bytes(r.start()), to_bytes(r.end())});
            }
            boost::sort(local_ranges, [] (auto&& tr1, auto&& tr2) {
                return utf8_type->less(tr1.start, tr2.start);
            });
            return local_ranges;
        });
    }
private:
    struct virtual_row {
        const bytes& cf_name;
        const token_range& tokens;
        clustering_key_prefix as_key() const {
            return clustering_key_prefix::from_exploded(std::vector<bytes_view>{cf_name, tokens.start, tokens.end});
        }
    };
    struct virtual_row_comparator {
        schema_ptr _schema;
        virtual_row_comparator(schema_ptr schema) : _schema(schema) { }
        bool operator()(const clustering_key_prefix& key1, const clustering_key_prefix& key2) {
            return clustering_key_prefix::prefix_equality_less_compare(*_schema)(key1, key2);
        }
        bool operator()(const virtual_row& row, const clustering_key_prefix& key) {
            return operator()(row.as_key(), key);
        }
        bool operator()(const clustering_key_prefix& key, const virtual_row& row) {
            return operator()(key, row.as_key());
        }
    };
    class virtual_row_iterator : public std::iterator<std::input_iterator_tag, const virtual_row> {
        std::reference_wrapper<const std::vector<bytes>> _cf_names;
        std::reference_wrapper<const std::vector<token_range>> _ranges;
        size_t _cf_names_idx = 0;
        size_t _ranges_idx = 0;
    public:
        struct end_iterator_tag {};
        virtual_row_iterator(const std::vector<bytes>& cf_names, const std::vector<token_range>& ranges)
                : _cf_names(std::ref(cf_names))
                , _ranges(std::ref(ranges))
        { }
        virtual_row_iterator(const std::vector<bytes>& cf_names, const std::vector<token_range>& ranges, end_iterator_tag)
                : _cf_names(std::ref(cf_names))
                , _ranges(std::ref(ranges))
                , _cf_names_idx(cf_names.size())
                , _ranges_idx(ranges.size())
        { }
        virtual_row_iterator& operator++() {
            if (++_ranges_idx == _ranges.get().size() && ++_cf_names_idx < _cf_names.get().size()) {
                _ranges_idx = 0;
            }
            return *this;
        }
        virtual_row_iterator operator++(int) {
            virtual_row_iterator i(*this);
            ++(*this);
            return i;
        }
        const value_type operator*() const {
            return { _cf_names.get()[_cf_names_idx], _ranges.get()[_ranges_idx] };
        }
        bool operator==(const virtual_row_iterator& i) const {
            return _cf_names_idx == i._cf_names_idx
                && _ranges_idx == i._ranges_idx;
        }
        bool operator!=(const virtual_row_iterator& i) const {
            return !(*this == i);
        }
    };

    std::vector<db::system_keyspace::range_estimates>
    estimates_for_current_keyspace(const database& db, std::vector<token_range> local_ranges) const {
        auto pkey = partition_key::from_single_value(*_schema, utf8_type->decompose(*_current_partition));
        auto cfs = db.find_keyspace(*_current_partition).metadata()->cf_meta_data();
        auto cf_names = boost::copy_range<std::vector<bytes>>(cfs | boost::adaptors::transformed([] (auto&& cf) {
            return utf8_type->decompose(cf.first);
        }));
        boost::sort(cf_names, [] (auto&& n1, auto&& n2) {
            return utf8_type->less(n1, n2);
        });
        std::vector<db::system_keyspace::range_estimates> estimates;
        for (auto& range : _slice.row_ranges(*_schema, pkey)) {
            auto rows = boost::make_iterator_range(
                    virtual_row_iterator(cf_names, local_ranges),
                    virtual_row_iterator(cf_names, local_ranges, virtual_row_iterator::end_iterator_tag()));
            auto rows_to_estimate = range.slice(rows, virtual_row_comparator(_schema));
            for (auto&& r : rows_to_estimate) {
                auto& cf = db.find_column_family(*_current_partition, utf8_type->to_string(r.cf_name));
                estimates.push_back(estimate(cf, r.tokens));
                if (estimates.size() >= _slice.partition_row_limit()) {
                    return estimates;
                }
            }
        }
        return estimates;
    }

    /**
     * Returns the keyspaces, ordered by name, as selected by the partition_range.
     */
    static ks_range get_keyspaces(const schema& s, const database& db, dht::partition_range range) {
        struct keyspace_less_comparator {
            const schema& _s;
            keyspace_less_comparator(const schema& s) : _s(s) { }
            dht::ring_position as_ring_position(const sstring& ks) {
                auto pkey = partition_key::from_single_value(_s, utf8_type->decompose(ks));
                return dht::global_partitioner().decorate_key(_s, std::move(pkey));
            }
            bool operator()(const sstring& ks1, const sstring& ks2) {
                return as_ring_position(ks1).less_compare(_s, as_ring_position(ks2));
            }
            bool operator()(const sstring& ks, const dht::ring_position& rp) {
                return as_ring_position(ks).less_compare(_s, rp);
            }
            bool operator()(const dht::ring_position& rp, const sstring& ks) {
                return rp.less_compare(_s, as_ring_position(ks));
            }
        };
        auto keyspaces = db.get_non_system_keyspaces();
        auto cmp = keyspace_less_comparator(s);
        boost::sort(keyspaces, cmp);
        return boost::copy_range<ks_range>(range.slice(keyspaces, std::move(cmp)));
    }

    /**
     * Makes a wrapping range of ring_position from a nonwrapping range of token, used to select sstables.
     */
    static dht::partition_range as_ring_position_range(dht::token_range& r) {
        stdx::optional<range<dht::ring_position>::bound> start_bound, end_bound;
        if (r.start()) {
            start_bound = {{ dht::ring_position(r.start()->value(), dht::ring_position::token_bound::start), r.start()->is_inclusive() }};
        }
        if (r.end()) {
            end_bound = {{ dht::ring_position(r.end()->value(), dht::ring_position::token_bound::end), r.end()->is_inclusive() }};
        }
        return dht::partition_range(std::move(start_bound), std::move(end_bound), r.is_singular());
    }

    /**
     * Add a new range_estimates for the specified range, considering the sstables associated with `cf`.
     */
    static system_keyspace::range_estimates estimate(const column_family& cf, const token_range& r) {
        int64_t count{0};
        utils::estimated_histogram hist{0};
        auto from_bytes = [] (auto& b) {
            return dht::global_partitioner().from_sstring(utf8_type->to_string(b));
        };
        dht::token_range_vector ranges;
        compat::unwrap_into(
            wrapping_range<dht::token>({{ from_bytes(r.start) }}, {{ from_bytes(r.end) }}),
            dht::token_comparator(),
            [&] (auto&& rng) { ranges.push_back(std::move(rng)); });
        for (auto&& r : ranges) {
            auto rp_range = as_ring_position_range(r);
            for (auto&& sstable : cf.select_sstables(rp_range)) {
                count += sstable->estimated_keys_for_range(r);
                hist.merge(sstable->get_stats_metadata().estimated_row_size);
            }
        }
        return {cf.schema(), r.start, r.end, count, count > 0 ? hist.mean() : 0};
    }
};

struct virtual_reader {
    mutation_reader operator()(schema_ptr schema,
            const dht::partition_range& range,
            const query::partition_slice& slice,
            const io_priority_class& pc,
            tracing::trace_state_ptr trace_state,
            streamed_mutation::forwarding fwd,
            mutation_reader::forwarding fwd_mr) {
        return make_mutation_reader<size_estimates_mutation_reader>(schema, range, slice, fwd);
    }
};

} // namespace size_estimates

} // namespace db
<commit_msg>size_estimates: convert reader to flat mutation readers<commit_after>/*
 * Copyright (C) 2016 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <boost/range/adaptor/indirected.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/find_if.hpp>

#include "clustering_bounds_comparator.hh"
#include "database.hh"
#include "db/system_keyspace.hh"
#include "dht/i_partitioner.hh"
#include "mutation_reader.hh"
#include "partition_range_compat.hh"
#include "range.hh"
#include "service/storage_service.hh"
#include "stdx.hh"
#include "streamed_mutation.hh"
#include "sstables/sstables.hh"

namespace db {

namespace size_estimates {

class size_estimates_mutation_reader final : public flat_mutation_reader::impl {
    struct token_range {
        bytes start;
        bytes end;
    };
    schema_ptr _schema;
    const dht::partition_range* _prange;
    const query::partition_slice& _slice;
    using ks_range = std::vector<sstring>;
    stdx::optional<ks_range> _keyspaces;
    ks_range::const_iterator _current_partition;
    streamed_mutation::forwarding _fwd;
    flat_mutation_reader_opt _partition_reader;
public:
    size_estimates_mutation_reader(schema_ptr schema, const dht::partition_range& prange, const query::partition_slice& slice, streamed_mutation::forwarding fwd)
            : impl(schema)
            , _schema(std::move(schema))
            , _prange(&prange)
            , _slice(slice)
            , _fwd(fwd)
    { }

private:
    future<> get_next_partition() {
        // For each specified range, estimate (crudely) mean partition size and partitions count.
        auto& db = service::get_local_storage_proxy().get_db().local();
        if (!_keyspaces) {
            _keyspaces = get_keyspaces(*_schema, db, *_prange);
            _current_partition = _keyspaces->begin();
        }
        if (_current_partition == _keyspaces->end()) {
            _end_of_stream = true;
            return make_ready_future<>();
        }
        return get_local_ranges().then([&db, this] (auto&& ranges) {
            auto estimates = this->estimates_for_current_keyspace(db, std::move(ranges));
            auto mutations = db::system_keyspace::make_size_estimates_mutation(*_current_partition, std::move(estimates));
            ++_current_partition;
            std::vector<mutation> ms;
            ms.emplace_back(std::move(mutations));
            _partition_reader = flat_mutation_reader_from_mutations(std::move(ms), _fwd);
        });
    }
public:
    virtual future<> fill_buffer() override {
        return do_until([this] { return is_end_of_stream() || is_buffer_full(); }, [this] {
            if (!_partition_reader) {
                return get_next_partition();
            }
            return _partition_reader->consume_pausable([this] (mutation_fragment mf) {
                push_mutation_fragment(std::move(mf));
                return stop_iteration(is_buffer_full());
            }).then([this] {
                if (_partition_reader->is_end_of_stream() && _partition_reader->is_buffer_empty()) {
                    _partition_reader = stdx::nullopt;
                }
            });
        });
    }
    virtual void next_partition() override {
        clear_buffer_to_next_partition();
        if (is_buffer_empty()) {
            _partition_reader = stdx::nullopt;
        }
    }
    virtual future<> fast_forward_to(const dht::partition_range& pr) override {
        clear_buffer();
        _prange = ≺
        _keyspaces = stdx::nullopt;
        _partition_reader = stdx::nullopt;
        _end_of_stream = false;
        return make_ready_future<>();
    }
    virtual future<> fast_forward_to(position_range pr) override {
        forward_buffer_to(pr.start());
        _end_of_stream = false;
        if (_partition_reader) {
            return _partition_reader->fast_forward_to(std::move(pr));
        }
        return make_ready_future<>();
    }
    /**
     * Returns the primary ranges for the local node.
     * Used for testing as well.
     */
    static future<std::vector<token_range>> get_local_ranges() {
        auto& ss = service::get_local_storage_service();
        return ss.get_local_tokens().then([&ss] (auto&& tokens) {
            auto ranges = ss.get_token_metadata().get_primary_ranges_for(std::move(tokens));
            std::vector<token_range> local_ranges;
            auto to_bytes = [](const stdx::optional<dht::token_range::bound>& b) {
                assert(b);
                return utf8_type->decompose(dht::global_partitioner().to_sstring(b->value()));
            };
            // We merge the ranges to be compatible with how Cassandra shows it's size estimates table.
            // All queries will be on that table, where all entries are text and there's no notion of
            // token ranges form the CQL point of view.
            auto left_inf = boost::find_if(ranges, [] (auto&& r) {
                return !r.start() || r.start()->value() == dht::minimum_token();
            });
            auto right_inf = boost::find_if(ranges, [] (auto&& r) {
                return !r.end() || r.start()->value() == dht::maximum_token();
            });
            if (left_inf != right_inf && left_inf != ranges.end() && right_inf != ranges.end()) {
                local_ranges.push_back(token_range{to_bytes(right_inf->start()), to_bytes(left_inf->end())});
                ranges.erase(left_inf);
                ranges.erase(right_inf);
            }
            for (auto&& r : ranges) {
                local_ranges.push_back(token_range{to_bytes(r.start()), to_bytes(r.end())});
            }
            boost::sort(local_ranges, [] (auto&& tr1, auto&& tr2) {
                return utf8_type->less(tr1.start, tr2.start);
            });
            return local_ranges;
        });
    }
private:
    struct virtual_row {
        const bytes& cf_name;
        const token_range& tokens;
        clustering_key_prefix as_key() const {
            return clustering_key_prefix::from_exploded(std::vector<bytes_view>{cf_name, tokens.start, tokens.end});
        }
    };
    struct virtual_row_comparator {
        schema_ptr _schema;
        virtual_row_comparator(schema_ptr schema) : _schema(schema) { }
        bool operator()(const clustering_key_prefix& key1, const clustering_key_prefix& key2) {
            return clustering_key_prefix::prefix_equality_less_compare(*_schema)(key1, key2);
        }
        bool operator()(const virtual_row& row, const clustering_key_prefix& key) {
            return operator()(row.as_key(), key);
        }
        bool operator()(const clustering_key_prefix& key, const virtual_row& row) {
            return operator()(key, row.as_key());
        }
    };
    class virtual_row_iterator : public std::iterator<std::input_iterator_tag, const virtual_row> {
        std::reference_wrapper<const std::vector<bytes>> _cf_names;
        std::reference_wrapper<const std::vector<token_range>> _ranges;
        size_t _cf_names_idx = 0;
        size_t _ranges_idx = 0;
    public:
        struct end_iterator_tag {};
        virtual_row_iterator(const std::vector<bytes>& cf_names, const std::vector<token_range>& ranges)
                : _cf_names(std::ref(cf_names))
                , _ranges(std::ref(ranges))
        { }
        virtual_row_iterator(const std::vector<bytes>& cf_names, const std::vector<token_range>& ranges, end_iterator_tag)
                : _cf_names(std::ref(cf_names))
                , _ranges(std::ref(ranges))
                , _cf_names_idx(cf_names.size())
                , _ranges_idx(ranges.size())
        { }
        virtual_row_iterator& operator++() {
            if (++_ranges_idx == _ranges.get().size() && ++_cf_names_idx < _cf_names.get().size()) {
                _ranges_idx = 0;
            }
            return *this;
        }
        virtual_row_iterator operator++(int) {
            virtual_row_iterator i(*this);
            ++(*this);
            return i;
        }
        const value_type operator*() const {
            return { _cf_names.get()[_cf_names_idx], _ranges.get()[_ranges_idx] };
        }
        bool operator==(const virtual_row_iterator& i) const {
            return _cf_names_idx == i._cf_names_idx
                && _ranges_idx == i._ranges_idx;
        }
        bool operator!=(const virtual_row_iterator& i) const {
            return !(*this == i);
        }
    };

    std::vector<db::system_keyspace::range_estimates>
    estimates_for_current_keyspace(const database& db, std::vector<token_range> local_ranges) const {
        auto pkey = partition_key::from_single_value(*_schema, utf8_type->decompose(*_current_partition));
        auto cfs = db.find_keyspace(*_current_partition).metadata()->cf_meta_data();
        auto cf_names = boost::copy_range<std::vector<bytes>>(cfs | boost::adaptors::transformed([] (auto&& cf) {
            return utf8_type->decompose(cf.first);
        }));
        boost::sort(cf_names, [] (auto&& n1, auto&& n2) {
            return utf8_type->less(n1, n2);
        });
        std::vector<db::system_keyspace::range_estimates> estimates;
        for (auto& range : _slice.row_ranges(*_schema, pkey)) {
            auto rows = boost::make_iterator_range(
                    virtual_row_iterator(cf_names, local_ranges),
                    virtual_row_iterator(cf_names, local_ranges, virtual_row_iterator::end_iterator_tag()));
            auto rows_to_estimate = range.slice(rows, virtual_row_comparator(_schema));
            for (auto&& r : rows_to_estimate) {
                auto& cf = db.find_column_family(*_current_partition, utf8_type->to_string(r.cf_name));
                estimates.push_back(estimate(cf, r.tokens));
                if (estimates.size() >= _slice.partition_row_limit()) {
                    return estimates;
                }
            }
        }
        return estimates;
    }

    /**
     * Returns the keyspaces, ordered by name, as selected by the partition_range.
     */
    static ks_range get_keyspaces(const schema& s, const database& db, dht::partition_range range) {
        struct keyspace_less_comparator {
            const schema& _s;
            keyspace_less_comparator(const schema& s) : _s(s) { }
            dht::ring_position as_ring_position(const sstring& ks) {
                auto pkey = partition_key::from_single_value(_s, utf8_type->decompose(ks));
                return dht::global_partitioner().decorate_key(_s, std::move(pkey));
            }
            bool operator()(const sstring& ks1, const sstring& ks2) {
                return as_ring_position(ks1).less_compare(_s, as_ring_position(ks2));
            }
            bool operator()(const sstring& ks, const dht::ring_position& rp) {
                return as_ring_position(ks).less_compare(_s, rp);
            }
            bool operator()(const dht::ring_position& rp, const sstring& ks) {
                return rp.less_compare(_s, as_ring_position(ks));
            }
        };
        auto keyspaces = db.get_non_system_keyspaces();
        auto cmp = keyspace_less_comparator(s);
        boost::sort(keyspaces, cmp);
        return boost::copy_range<ks_range>(range.slice(keyspaces, std::move(cmp)));
    }

    /**
     * Makes a wrapping range of ring_position from a nonwrapping range of token, used to select sstables.
     */
    static dht::partition_range as_ring_position_range(dht::token_range& r) {
        stdx::optional<range<dht::ring_position>::bound> start_bound, end_bound;
        if (r.start()) {
            start_bound = {{ dht::ring_position(r.start()->value(), dht::ring_position::token_bound::start), r.start()->is_inclusive() }};
        }
        if (r.end()) {
            end_bound = {{ dht::ring_position(r.end()->value(), dht::ring_position::token_bound::end), r.end()->is_inclusive() }};
        }
        return dht::partition_range(std::move(start_bound), std::move(end_bound), r.is_singular());
    }

    /**
     * Add a new range_estimates for the specified range, considering the sstables associated with `cf`.
     */
    static system_keyspace::range_estimates estimate(const column_family& cf, const token_range& r) {
        int64_t count{0};
        utils::estimated_histogram hist{0};
        auto from_bytes = [] (auto& b) {
            return dht::global_partitioner().from_sstring(utf8_type->to_string(b));
        };
        dht::token_range_vector ranges;
        compat::unwrap_into(
            wrapping_range<dht::token>({{ from_bytes(r.start) }}, {{ from_bytes(r.end) }}),
            dht::token_comparator(),
            [&] (auto&& rng) { ranges.push_back(std::move(rng)); });
        for (auto&& r : ranges) {
            auto rp_range = as_ring_position_range(r);
            for (auto&& sstable : cf.select_sstables(rp_range)) {
                count += sstable->estimated_keys_for_range(r);
                hist.merge(sstable->get_stats_metadata().estimated_row_size);
            }
        }
        return {cf.schema(), r.start, r.end, count, count > 0 ? hist.mean() : 0};
    }
};

struct virtual_reader {
    flat_mutation_reader operator()(schema_ptr schema,
            const dht::partition_range& range,
            const query::partition_slice& slice,
            const io_priority_class& pc,
            tracing::trace_state_ptr trace_state,
            streamed_mutation::forwarding fwd,
            mutation_reader::forwarding fwd_mr) {
        return make_flat_mutation_reader<size_estimates_mutation_reader>(schema, range, slice, fwd);
    }
};

} // namespace size_estimates

} // namespace db
<|endoftext|>