Paraview与VTK学习笔记(六)//representation篇

之前的几篇学习笔记,讲了关于Render的事情,详细叙述了在Paraview中的一个从前端Python到后台vtk库的一个渲染调用的过程。下面我们来看一下数据的事情。

首先我们来看在之前提高过的simple.py中的Show():

def Show(proxy=None, view=None, **params):
    """Turns the visibility of a given pipeline object on in the given view.
    If pipeline object and/or view are not specified, active objects are used."""
    if proxy == None:
        proxy = GetActiveSource()
    if proxy == None:
        raise RuntimeError, "Show() needs a proxy argument or that an active source is set."
    if not view:
        # it here's now active view, controller.Show() will create a new preferred view.
        # if possible.
        view = active_objects.view
    controller = servermanager.ParaViewPipelineController()
    rep = controller.Show(proxy, proxy.Port, view)
    if rep == None:
        raise RuntimeError, "Could not create a representation object for proxy %s" % proxy.GetXMLLabel()
    for param in params.keys():
        setattr(rep, param, params[param])
    return rep
在这段代码中,controller=servermanager.ParaViewPipelineController():

class ParaViewPipelineController(object):
    """ParaViewPipelineController wraps vtkSMParaViewPipelineController class
    to manage conversion of arguments passed around from Pyhton Proxy objects to
    vtkSMProxy instances are vice-versa."""
    def __init__(self):
        """Constructor. Creates a new instance of
        vtkSMParaViewPipelineController."""
        self.SMController = vtkSMParaViewPipelineController()
可以看到他的构造函数,是调用了vtkSMParaViewPiplineController()这个类的构造函数,所以controller就是一个vtkSMParaViewPiplineController类的一个对象。但是不知道为什么在这个类中根本找不到这个方法Show。这有一点走不通,下面我们来看与它有相似意义的一段函数:

def CreateRepresentation(aProxy, view, **extraArgs):
    """Creates a representation for the proxy and adds it to the render
    module.

    This method can also be used to initialize properties by passing
    keyword arguments where the key is the name of the property.In addition
    registrationGroup and registrationName (optional) can be specified (as
    keyword arguments) to automatically register the proxy with the proxy
    manager.

    This method tries to create the best possible representation for the given
    proxy in the given view. Additionally, the user can specify proxyName
    (optional) to create a representation of a particular type."""

    global rendering
    if not aProxy:
        raise RuntimeError, "proxy argument cannot be None."
    if not view:
        raise RuntimeError, "view argument cannot be None."
    if "proxyName" in extraArgs:
      display = CreateProxy("representations", extraArgs['proxyName'], None)
      del extraArgs['proxyName']
    else:
      display = view.SMProxy.CreateDefaultRepresentation(aProxy.SMProxy, 0)
      if display:
        display.UnRegister(None)
    if not display:
        return None
    extraArgs['proxy'] = display
    proxy = rendering.__dict__[display.GetXMLName()](**extraArgs)
    proxy.Input = aProxy
    proxy.UpdateVTKObjects()
    view.Representations.append(proxy)
    return proxy
这个函数主要是给这个(source)代理对象创建一个representation,并且把这个representation加到render module(view)上。这个aProxy也就是我们的source,然后去他的管理代理对象,在同样的管理代理下创建一个representation代表这个source。设置view的代理的Input=source的代理,并且设置view的representation。根据我们之前的经验,对于rendering._dict_[display.GetXMLName()](**extraArgs)这个函数明显是创建一个representation代理。

display = view.SMProxy.CreateDefaultRepresentation(aProxy.SMProxy, 0)
这个函数的意思是在view的服务器管理对象中创建一个representation。这个函数是:

vtkSMRepresentationProxy* vtkSMViewProxy::CreateDefaultRepresentation(
  vtkSMProxy* proxy, int outputPort)
{
  assert("The session should be valid" && this->Session);

  vtkSMSourceProxy* producer = vtkSMSourceProxy::SafeDownCast(proxy);
  if (
    (producer == NULL) ||
    (outputPort < 0) ||
    (static_cast(producer->GetNumberOfOutputPorts()) <= outputPort) ||
    (producer->GetSession() != this->GetSession()))
    {
    return NULL;
    }

  // Update with time from the view to ensure we have up-to-date data.
  double view_time = vtkSMPropertyHelper(this, "ViewTime").GetAsDouble();
  producer->UpdatePipeline(view_time);

  const char* representationType =
    this->GetRepresentationType(producer, outputPort);
  if (!representationType)
    {
    return NULL;
    }

  vtkSMSessionProxyManager* pxm = this->GetSessionProxyManager();
  vtkSmartPointer p;
  p.TakeReference(pxm->NewProxy("representations", representationType));
  vtkSMRepresentationProxy* repr = vtkSMRepresentationProxy::SafeDownCast(p);
  if (repr)
    {
    repr->Register(this);
    return repr;
    }
  vtkWarningMacro("Failed to create representation (representations,"
    << representationType <<").");
  return NULL;
}
显然producer是一个根据这个source创建的vtkSMSourceProxy,然后获取数据的更新时间,然后根据这个时间,我们更新所有的source。以保证我们的数据是最新的。最后在创建相应的representation对象。并且注册它。
我们来看:
producer->UpdatePipeline(view_time);

void vtkSMSourceProxy::UpdatePipeline(double time)
{
  int i;


  this->CreateOutputPorts();
  int num = this->GetNumberOfOutputPorts();
  for (i=0; i < num; ++i)
    {
    this->GetOutputPort(i)->UpdatePipeline(time);
    }


  // When calling UpdatePipeline() we check if this->NeedsUpdate is true and
  // call the real update only if that's the case. We don't do that when one
  // uses UpdatePipeline(time) since we can never be too sure what time was
  // used. In that case, we assume the pipeline needs update and hence we should
  // set the NeedsUpdate ivar to true as well. Otherwise PostUpdateData()
  // doesn't fire the necessary events and that can cause problems (BUG
  // #12571).
  this->NeedsUpdate = true;
  this->PostUpdateData();
  //this->InvalidateDataInformation();
}
首先它创建了很多的输出端口:

void vtkSMSourceProxy::CreateOutputPorts()
{
  if (this->OutputPortsCreated && this->GetNumberOfOutputPorts())
    {
    return;
    }
  this->OutputPortsCreated = 1;

  // This will only create objects if they are not already created.
  // This happens when connecting a filter to a source which is not
  // initialized. In other situations, SetInput() creates the VTK
  // objects before this gets called.
  this->CreateVTKObjects();

  // We simply set/replace the Port pointers in the
  // this->PInternals->OutputPorts. This ensures that the port names,
  // port documentation is preserved.

  // Create one output port proxy for each output of the filter
  int numOutputs = this->GetNumberOfAlgorithmOutputPorts();

  // Ensure that output ports size matches the number of output ports provided
  // by the algorithm.
  this->PInternals->ResizeOutputPorts(numOutputs);
  for (int j=0; jSetPortIndex(j);
    opPort->SetSourceProxy(this);
    this->PInternals->OutputPorts[j].Port = opPort;
    opPort->Delete();
    }
}
这个函数只会在输出端口还没创建时,这种情况一般是给一个source加上一个filter。其他情况,都是用SetInput实现对象的建立。给每一个filter的输出创建一个输出端口。
然后对于每一个输出端口都进行流水线的更新。
 for (int i=0; i < num; ++i)
    {
    this->GetOutputPort(i)->UpdatePipeline(time);
    }
这里面其实是这样的:


void vtkSMOutputPort::UpdatePipeline(double time)
{
  this->UpdatePipelineInternal(time, true);
}

void vtkSMOutputPort::UpdatePipelineInternal(double time,
                                             bool doTime)
{
  this->SourceProxy->GetSession()->PrepareProgress();
  vtkClientServerStream stream;
  stream << vtkClientServerStream::Invoke
         << SIPROXY(this->SourceProxy)
         << "UpdatePipeline"
         << this->PortIndex << time << (doTime? 1 : 0)
         << vtkClientServerStream::End;
  this->SourceProxy->ExecuteStream(stream);
  this->SourceProxy->GetSession()->CleanupPendingProgress();
}
经过实践发现,数据一开始的获得,其直接就调用了UpdatePipeline和UpdatePipelineInternal这两个函数,然后就创建了一个Reader,所以数据source的读取,明显是在representation建立之前。而在这之后就执行render。所以这个过程只是做把数据绑到view上的工作。数据在这之前就已经读取进去了。这个函数中,又和我们之前学习到的一样,最后又调用到了vtkclientServerInterpreter::ProcessCommandInvoke(~~)这个函数。那么接下来他是执行那个函数呢?经过测试应该是执行到了vtkSISourceProxy这个类。
这个我们留到下次再说。继续这里的。

从上面的代码我们可以看到,首先建立一个display,然后把这个display给他创建一个相应的代理对象。然后在renMoudule
的Representation属性中把这个Representation产生的代理对象加入进去。这样就算这个source成为了这个view的一个属性了。

我们再看这一段代码:

  const char* representationType =
    this->GetRepresentationType(producer, outputPort);
const char* vtkSMViewProxy::GetRepresentationType(
  vtkSMSourceProxy* producer, int outputPort)
{
  assert(producer &&
         static_cast(producer->GetNumberOfOutputPorts()) > outputPort);

  // Process producer hints to see if indicates what type of representation
  // to create for this view.
  if (const char* reprName = vtkGetRepresentationNameFromHints(
      this->GetXMLName(), producer->GetHints(), outputPort))
    {
    return reprName;
    }

首先如果能从这个producer也就是我们的source的代理对象获取提示直接构建representation给这个view,那就直接返回

  // check if we have default representation name specified in XML.
  if (this->DefaultRepresentationName)
    {
    vtkSMSessionProxyManager* pxm = this->GetSessionProxyManager();
    vtkSMProxy* prototype = pxm->GetPrototypeProxy(
      "representations", this->DefaultRepresentationName);
    if (prototype)
      {
      vtkSMProperty* inputProp = prototype->GetProperty("Input");
      vtkSMUncheckedPropertyHelper helper(inputProp);
      helper.Set(producer, outputPort);
      bool acceptable = (inputProp->IsInDomains() > 0);
      helper.SetNumberOfElements(0);

      if (acceptable)
        {
        return this->DefaultRepresentationName;
        }
      }
    }

  return NULL;
}
如果不能根据XMLName和source和输出端口获取。那么如果我们有默认的representation name,可以根据服务器代理管理对象和获取一个prototype,然后检测它是否可用。如果可用则返回这个Name。


你可能感兴趣的:(Paraview与VTK学习笔记(六)//representation篇)