CLODMeshGenerator::CLODMeshGenerator() : GeometryGeneratorBase()
{
    vertexCount    = 0;
    faceCount      = 0;
    patchID        = 0;
    meshNumber     = 0; // Needed for progress calculation
    meshAttributes = mlU3D::MESH_ATTRIBUTES_DEFAULT;

    _wem = NULL;
    ML_CHECK_NEW(_wem, WEM());
}
//! Write one block to file stream. (private)
bool U3DFileWriter::_writeBlockToFileStream(U3DDataBlockWriter& block, std::ofstream& ofstream)
{
    bool Success = false;

    MLuint32 flushBufferSize = block.getNumTotalBytes();

    mlU3D::DataBlockFundamental* flushBuffer = NULL;
    ML_CHECK_NEW(flushBuffer, mlU3D::DataBlockFundamental[flushBufferSize]);
    memset(flushBuffer, 0, flushBufferSize);

    if (NULL != flushBuffer)
    {
        // Add Block type, Data size & Meta data Size
        mlU3D::DataBlockFundamental flushBufferIndex = 0;
        flushBuffer[flushBufferIndex] = block.blockType;

        flushBufferIndex++;
        flushBuffer[flushBufferIndex] = block.getDataSizeWithChildDataBytes();

        flushBufferIndex++;
        flushBuffer[flushBufferIndex] = block.getMetaDataSizeWithoutPadding();

        flushBufferIndex++;


        // Add Data
        mlU3D::DataVector data = block.getData();
        for (mlU3D::DataBlockFundamental i = 0; i < block.getDataSize(); i++)
        {
            flushBuffer[flushBufferIndex] = data[i];
            flushBufferIndex++;
        }

        // Add Meta data
        mlU3D::DataVector metaData = block.getMetaData();
        for (mlU3D::DataBlockFundamental i = 0; i < block.getMetaDataSize(); i++)
        {
            flushBuffer[flushBufferIndex] = metaData[i];
            flushBufferIndex++;
        }
    }
    else
    {
        flushBufferSize = 0;
    }

    if ((0 != flushBufferSize) && (block.blockType != 0))
    {
        try
        {
            ofstream.write(reinterpret_cast<char*>(flushBuffer), flushBufferSize);
            ofstream.flush();
            Success = true;
        }
        catch (...)
        {
            // Ignore errors
        }
    }

    ML_DELETE_ARRAY(flushBuffer);

    return Success;
}
void TileSphere::addPoint(float* position) 
{
    ML_TRACE_IN("void TileSphere::addPoint(float* position) ");

    // Adds a point into the tile sphere.
    float minX=0, maxX=0, minY=0, maxY=0, minZ=0, maxZ=0;

    int counter = 0;

    // If the sphere has sub spheres, add point into the according sub sphere.
    if (_hasSubSpheresFlag) {
        for (counter = 0; counter < _cubicPartition; counter++) {
            _tileSpheres[counter]._getBB(minX, maxX, minY, maxY, minZ, maxZ);

            if ((*(position)     >= minX) && 
                (*(position)     <= maxX) &&
                (*(position + 1) >= minY) &&
                (*(position + 1) <= maxY) &&
                (*(position + 2) >= minZ) &&
                (*(position + 2) <= maxZ))
            {
                _tileSpheres[counter].addPoint(position);
            }
        }
    } else {
        // If there is no further sub-division, integrate point into subset.
        _subset[_numEntries] = position;
        _numEntries++;
        // If capacity is reached, establish sub spheres and transfer the containing points.
        if (_numEntries == static_cast<unsigned int>(_maxEntries)) {
            // Establish further sub spheres.
            if (_hasSubSpheresFlag == false) {
                ML_DELETE_ARR(_tileSpheres);
                ML_CHECK_NEW (_tileSpheres, TileSphere[_cubicPartition]);
                _hasSubSpheresFlag = true;
            }

            int xCounter=0, yCounter=0, zCounter=0;

            float partitionDiv = 1.0f / static_cast<float>(_partition);

            float stepX = (_maxX - _minX) * partitionDiv;
            float stepY = (_maxY - _minY) * partitionDiv;
            float stepZ = (_maxZ - _minZ) * partitionDiv;

            float newMaxX = 0.0f;
            float newMaxY = 0.0f;
            float newMaxZ = 0.0f;

            // Constitute BBs for the sub spheres.
            for (xCounter = 0; xCounter < _partition; xCounter++) {
                for (yCounter = 0; yCounter < _partition; yCounter++) {
                    for (zCounter = 0; zCounter < _partition; zCounter++) {
                        _tileSpheres[counter].setParameter(_minimalDistance, _partition, _numEntries, _error);

                        // to avoid rounding errors, take the real maximum value at the upper border
                        newMaxX = (xCounter+1 < _partition) ? (_minX + stepX * xCounter + stepX) : _maxX;
                        newMaxY = (yCounter+1 < _partition) ? (_minY + stepY * yCounter + stepY) : _maxY;
                        newMaxZ = (zCounter+1 < _partition) ? (_minZ + stepZ * zCounter + stepZ) : _maxZ;

                        _tileSpheres[counter].setBB(
                            _minX + stepX * xCounter,
                            newMaxX,
                            _minY + stepY * yCounter,
                            newMaxY,
                            _minZ + stepZ * zCounter,
                            newMaxZ);

                        counter++;
                    }
                }
            }
            // Transfer points
            for (counter = 0; counter < _maxEntries; counter++){
                addPoint(_subset[counter]);
            }
        }
    }
}
示例#4
0
void SavePRC::savePRCToFileStream(std::ofstream& ofstream)
{
  _progressFld->setFloatValue(0.0f);

  WEMPtr saveWEM = NULL;
  ML_CHECK_NEW(saveWEM,WEM());

  // Clear object info vector;
  _prcObjectInfoVector.clear();

  // Clear geometry vectors
  _pointSetsGeometryVector.clear();
  _lineSetsGeometryVector.clear();

  PRCMeshInfoVector meshInfoVector;

  // Stores the model bounding box data & its center. Shall be modified only with UpdateBoundingBox() method!
  ModelBoundingBoxStruct modelBoundingBox;
  modelBoundingBox.start.x = ML_DOUBLE_MAX;
  modelBoundingBox.start.y = ML_DOUBLE_MAX;
  modelBoundingBox.start.z = ML_DOUBLE_MAX;
  modelBoundingBox.end.x   = ML_DOUBLE_MAX * -1;
  modelBoundingBox.end.y   = ML_DOUBLE_MAX * -1;
  modelBoundingBox.end.z   = ML_DOUBLE_MAX * -1;

  // Get default parameters from field values
  //defaultValues = getDefaultValuesFromFields(); 
  
  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  
  _statusFld->setStringValue("Analyzing input data.");

  // Scan all data from input field and collect base info for point sets.
  PreProcessPointSetData(modelBoundingBox);

  // Scan all data from input field and collect base info for line sets.
  PreProcessLineSetData(modelBoundingBox);

  // Scan all WEM patches, triangulate them if necessary and collect base info.
  PreProcessMeshData(saveWEM, meshInfoVector, modelBoundingBox);

  
  GroupNodeVector groupNodes = assemblePRCGroupNodeInfo(_prcObjectInfoVector);
  mapParentTreeNodeIDs(_prcObjectInfoVector, groupNodes);

  _modelTree = assemblePRCModelTreeInfo(groupNodes);

  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  _progressFld->setFloatValue(0.1f);

  PRCFile outPRCFile(ofstream);

  PRCModelTreeNode modelRootNode = getNodeFromPRCModelTree(_modelTree, 0);

  WriteNodeModelsToPRCFile(outPRCFile, modelRootNode);





  outPRCFile.finish();


  _progressFld->setFloatValue(1.0f);

}
示例#5
0
void CSODistance::_process()
{   
  ML_TRACE_IN("void CSODistance::_process()");

  _outputXMarkerList->clearList();

  // Delete all created CurveData objects
  while ( !_outputCurveList->getCurveList().empty() ) {
    ML_DELETE( _outputCurveList->getCurveList().back() );
    _outputCurveList->getCurveList().pop_back();
  }

  if (_csoList0 != NULL) {

    int nCSOs = _csoList0->numCSO();

    double minDistance = 0.0;
    double maxDistance = 0.0;
    double avgDistance = 0.0;
    double stdDevDistance = 0.0;

    std::stringstream distances;
    distances << _tableHeader  << std::endl;


    switch ( _modeFld->getEnumValue() ){
      case FIRST2 :
      {
        if ((nCSOs >= 2) && (_csoList0->getCSOAt(0)->getIsFinished()) && (_csoList0->getCSOAt(1)->getIsFinished())) {
          std::vector<vec3>pointSet1;
          std::vector<vec3>pointSet2;
          
          _csoList0->getCSOAt(0)->fillPathPointCoordinatesFlattened(pointSet1);
          _csoList0->getCSOAt(1)->fillPathPointCoordinatesFlattened(pointSet2);

           Vector3 minPoint1,minPoint2,maxPoint1,maxPoint2;

           MinimalDistancePointClouds* pointSetsMinDist = NULL;
           ML_CHECK_NEW(pointSetsMinDist, MinimalDistancePointClouds);
           
           pointSetsMinDist->setPointSets(pointSet1, pointSet2);
           pointSetsMinDist->setNumEntries(200);
           pointSetsMinDist->computeDistance(minPoint1,minPoint2);

           minDistance = sqrt((minPoint1[0]-minPoint2[0])*(minPoint1[0]-minPoint2[0]) + 
                              (minPoint1[1]-minPoint2[1])*(minPoint1[1]-minPoint2[1]) + 
                              (minPoint1[2]-minPoint2[2])*(minPoint1[2]-minPoint2[2]));
                    


          _minimumDistanceFld->setFloatValue( static_cast<float>(minDistance));

          _outputXMarkerList->appendItem(XMarker( vec6(minPoint1[0],minPoint1[1],minPoint1[2],0.5f,0.0f,0.0f),
                                                  vec3(minPoint2[0]-minPoint1[0],minPoint2[1]-minPoint1[1],minPoint2[2]-minPoint1[2]),
                                                  0,""));
          distances << _csoList0->getCSOAt(0)->getId() << "," 
                    << _csoList0->getCSOAt(1)->getId() << "," 
                    << minDistance << "," 
                    << maxDistance << "," 
                    << avgDistance << "," 
                    << stdDevDistance 
                    << std::endl;
        } else {
          _minimumDistancePoint1Fld->setVec3fValue(vec3(0.0,0.0,0.0));
          _minimumDistancePoint2Fld->setVec3fValue(vec3(0.0,0.0,0.0));
          _minimumDistanceFld->setFloatValue(0.0f);
          _distancesFld->setStringValue( _tableHeader );
        }
        break;
      }
      case INPLANE:
      case INDEX:
      {
        CurveData *outputCurve = new CurveData;
        double    *yValues     = new double[ nCSOs ];

        double minDist = ML_DOUBLE_MAX;
        vec3 point1;
        vec3 point2;
        double averageMinDistance = 0.0;
        double averageMeanDistance = 0.0;
        double averageMaxDistance = 0.0;
        for ( int iCSO = 0; iCSO<nCSOs; ++iCSO ){
          CSO* currentCSO = _csoList0->getCSOAt( iCSO );
          CSO* matchingCSO = _findMatchingCSO(iCSO);
          if (!matchingCSO) {continue;}

          std::vector<vec3>pointSet1;
          std::vector<vec3>pointSet2;
          currentCSO->fillPathPointCoordinatesFlattened(pointSet1);
          matchingCSO->fillPathPointCoordinatesFlattened(pointSet2);

          Vector3 minPoint1,minPoint2,maxPoint1,maxPoint2;

          _getDistances( pointSet1, pointSet2,
                         minDistance,maxDistance,avgDistance,stdDevDistance,
                         minPoint1,minPoint2,maxPoint1,maxPoint2);

          averageMinDistance  += minDistance;
          averageMeanDistance += avgDistance;
          averageMaxDistance  += maxDistance;

          distances << currentCSO->getId()  << "," 
                    << matchingCSO->getId() << "," 
                    << minDistance << "," 
                    << maxDistance << "," 
                    << avgDistance << "," 
                    << stdDevDistance 
                    << std::endl;

          if ( minDistance < minDist ){
            minDist = minDistance;
            point1 = minPoint1;
            point2 = minPoint2;
          }

          _outputXMarkerList->appendItem(XMarker( vec6(minPoint1[0],minPoint1[1],minPoint1[2],0.5f,0.0f,0.0f),
                                                  vec3(minPoint2[0]-minPoint1[0],minPoint2[1]-minPoint1[1],minPoint2[2]-minPoint1[2]),
                                                  currentCSO->getId(),""));

          switch ( _curveStatistic->getEnumValue() ){
            case MIN:
              yValues[ iCSO ] = minDistance;
              break;
            case MAX:
              yValues[ iCSO ] = maxDistance;
              break;
            case MEAN:
              yValues[ iCSO ] = avgDistance;
              break;
            case STDEV:
              yValues[ iCSO ] = stdDevDistance;
              break;
            default:
              break;
          } 
        } // iCSO
        averageMinDistance  /= (nCSOs != 0 ? nCSOs : 1.0);
        averageMeanDistance /= (nCSOs != 0 ? nCSOs : 1.0);
        averageMaxDistance  /= (nCSOs != 0 ? nCSOs : 1.0);

        outputCurve->setY( nCSOs, yValues);
        delete[] yValues;
        _outputCurveList->getCurveList().push_back( outputCurve );
        _distancesFld->setStringValue( distances.str() );
        _minimumDistancePoint1Fld->setVec3fValue(point1);
        _minimumDistancePoint2Fld->setVec3fValue(point2);
        _minimumDistanceFld->setFloatValue( static_cast<float>(minDistance) );

        _AverageMinimumDistanceFld->setDoubleValue( averageMinDistance  );
        _AverageMeanDistanceFld->setDoubleValue(    averageMeanDistance );
        _AverageMaxDistanceFld->setDoubleValue(     averageMaxDistance  );



        break;
      }
    default:
      break;
    }

  } else {
    _minimumDistancePoint1Fld->setVec3fValue(vec3(0.0,0.0,0.0));
    _minimumDistancePoint2Fld->setVec3fValue(vec3(0.0,0.0,0.0));
    _minimumDistanceFld->setFloatValue(0.0f);
    _distancesFld->setStringValue( _tableHeader );
  }

  _outputXMarkerListFld->setBaseValue(_outputXMarkerList);
  _outputCurveListFld->touch();

}
示例#6
0
CSODistance::CSODistance() : BaseOp(0, 0)
{
  ML_TRACE_IN("CSODistance::CSODistance(int numInImages, int numOutImages) : BaseOp(numInImages, numOutImages)");

  handleNotificationOff();

  _csoList0 = NULL;
  _csoList1 = NULL;
  _tableHeader = "Id1,Id2,min,max,mean,stdDev";

  FieldContainer* fieldC = getFieldContainer();
  ML_CHECK(fieldC);

  (_input0CSOFld = fieldC->addBase("inCSOList"))->setBaseValue(NULL);
  (_input1CSOFld = fieldC->addBase("inCSOList1"))->setBaseValue(NULL);

  //////////////////////////////////////////////////////////////////////////

  char* distanceModes[LASTMODE];
  distanceModes[ FIRST2 ] = "First 2 CSOs";
  distanceModes[ INPLANE ] = "Match in plane";
  distanceModes[ INDEX ] = "Match index";
  _modeFld = fieldC->addEnum("mode",distanceModes,LASTMODE);
  _modeFld->setEnumValue( FIRST2 );

  //////////////////////////////////////////////////////////////////////////

  (_minimumDistanceFld = fieldC->addFloat("minimumDistance"))->setFloatValue(0);
  (_minimumDistancePoint1Fld = fieldC->addVec3f("minimumDistancePoint1"))->setVec3fValue(vec3(0.0,0.0,0.0));
  (_minimumDistancePoint2Fld = fieldC->addVec3f("minimumDistancePoint2"))->setVec3fValue(vec3(0.0,0.0,0.0));
  _distancesFld = addString("distances",_tableHeader );

  _AverageMinimumDistanceFld = addDouble("averageMinimumDistance", 0.0 );
  _AverageMeanDistanceFld    = addDouble("averageMeanDistance", 0.0 );
  _AverageMaxDistanceFld     = addDouble("averageMaximumDistance", 0.0 );

  //////////////////////////////////////////////////////////////////////////

  _tolleranceFld = addDouble("tollerance", 0.0001 );

  //////////////////////////////////////////////////////////////////////////

  _applyFld = fieldC->addNotify("apply");
  (_autoApplyFld = fieldC->addBool("autoApply"))->setBoolValue(true);
  _statusFld = fieldC->addString("status");
  _statusFld->setStringValue("Ready");

  //////////////////////////////////////////////////////////////////////////

  (_listenToRepaintNotificationsFld          = fieldC->addBool("listenToRepaintNotifications"))
    ->setBoolValue(false);
  (_listenToFinishingNotificationsFld        = fieldC->addBool("listenToFinishingNotifications"))
    ->setBoolValue(true);
  (_listenToSelectionChangedNotificationsFld = fieldC->addBool("listenToSelectionChangedNotifications"))
    ->setBoolValue(false);

  char* statisticsNames[LASTSTATISTIC];
  statisticsNames[ MIN ] = "Minimum";
  statisticsNames[ MAX ] = "Maximum";
  statisticsNames[ MEAN ] = "Mean";
  statisticsNames[ STDEV ] = "StDev";
  _curveStatistic = addEnum("curveStatistic",statisticsNames,LASTSTATISTIC );

  _isInNotificationCB = false; 	
  
  ML_CHECK_NEW(_outputXMarkerList,XMarkerList());

	(_outputXMarkerListFld = getFieldContainer()->addBase("outputXMarkerList"))->setBaseValue(NULL);

  _outputCurveList = new CurveList;
  (_outputCurveListFld = getFieldContainer()->addBase("outputCurveList"))->setBaseValue( _outputCurveList );

  handleNotificationOn();
}
void DicomSurfaceSegmentationLoad::_addMeshToOutput(const int meshNumber)
{
	if(meshNumber >= _dicomMeshesVector.size())
  {
		return;
  }

  int meshesIDStartValue = (int)_meshesIDStartValueFld->getIntValue();

	const Element3D meshElement     = _dicomMeshesVector[meshNumber];

	const std::string segmentLabel  = meshElement.getSegmentLabel();	 
  const Coordinates3D meshSurface = meshElement.getReferencedSurface();

  const std::vector<Vector3> wemPositions              = meshSurface.getCoordinates();
	const std::vector<unsigned long> meshPositionIndices = meshSurface.getCoordinateIndices();
	const std::vector<Vector3> meshNormals               = meshSurface.getNormals();

	WEMTrianglePatch* newPatch = NULL;
	ML_CHECK_NEW(newPatch, WEMTrianglePatch());

  // Add WEM nodes
	for (unsigned long p = 0; p < wemPositions.size(); p++) 
  {
		WEMNode* newNode = newPatch->addNode();

		newNode->setPosition(wemPositions[p]);

		if(!meshNormals.empty())
    {
			newNode->setNormal(meshNormals[p]);
    }
		else
    {
			newNode->computeNormal();
    }
	}

  // Add WEM faces
	for (size_t f = 0; f < meshPositionIndices.size(); f += 3) 
  {
		WEMTriangle* newFace = newPatch->addTriangle();

		for (unsigned int i = 0; i < 3; i++) 
    {
			WEMNode* node = newPatch->getNodeAt(meshPositionIndices[f+i]);
			newFace->setNode(i, node);
			node->addFace(newFace);
		}

		newFace->computeNormal();
	}
	
	newPatch->setLabel(segmentLabel);
	//newPatch->setId(_outWEM->getCurrentWEMPatchId());
	newPatch->setId(meshesIDStartValue + meshNumber);
	newPatch->setType(_type);

	ML_NAMESPACE::WEMPrimitiveValueList* primitiveValueList = newPatch->createOrGetPrimitiveValueList("LUT");
	primitiveValueList->setValue(0, static_cast<double>(meshNumber));

	newPatch->buildEdgeConnectivity();
	_outWEM->addWEMPatch(newPatch);
	_finish(newPatch);
}
void GraphToFibers::_updateOutput()
{
  _outNodePositions.clearList();
  _outNodePositions.selectItemAt(-1);
  _outEdgePositions.clearList();
  _outEdgePositions.selectItemAt(-1);
  _outEdgeConnections.clearList();
  _outEdgeConnections.selectItemAt(-1);

  int nodeCount = 0;
  int edgeCount = 0;

  int  currentEdgePositionNum = 0;

  // Work on a local copy of the graph, because the smoothing will change it
  Graph* vesselGraph = NULL;
  ML_CHECK_NEW(vesselGraph, Graph(_inGraph));

  vesselGraph->purifyGraph();
  //vesselGraph->setRootIdToAllChildren();

  vesselGraph->closeSkeletonGaps();

  // smooth the graph
  const int numSmoothingPasses = 3;
  const float smoothingFactor = 0.7;
  //const Graph::EdgeIterator endEdge();
  for (Graph::EdgeIterator iter = vesselGraph->beginEdge(); iter != vesselGraph->endEdge(); ++iter)
  {
    static_cast<VesselEdge*>(*iter)->smooth(numSmoothingPasses, smoothingFactor, smoothingFactor);
  }

  // Iterate over all root nodes
  for (Graph::ConstNodeIterator iter = vesselGraph->beginRoot(); iter != vesselGraph->endRoot(); iter++)
  {

  }

  // Iterate over all nodes
  for (Graph::ConstNodeIterator i = vesselGraph->beginNode(); i != vesselGraph->endNode(); i++)
  {
    const VesselNode* thisNode = *i;
    const Vector3 thisNodePos = thisNode->getPos();

    //thisNode->getDepNode(); // Get dependent node via edge with index i.
    //thisNode->edges();
    //thisNode->getId();
    //thisNode->getLabel();

    // Add node markers
    XMarker thisNodeMarker(thisNodePos);
    std::string nodeName = "Node #" + mlPDF::intToString(nodeCount);
    thisNodeMarker.setName(nodeName.c_str());
    thisNodeMarker.type = 0;
    _outNodePositions.appendItem(thisNodeMarker);

    // Add edge markers & connections
    const size_t thisNodeEdgesNum = thisNode->getEdgeNum(); // Get Number of edges dependent to the node.
    for (size_t e = 0; e < thisNodeEdgesNum; e++)
    {
      const VesselEdge* thisNodeEdge = thisNode->getDepEdge(e); // Get the pointer of edge with index i. 

      if (thisNodeEdge)
      {
        bool newBranch = true;

        const size_t numSkeletons = thisNodeEdge->numSkeletons();

        for (size_t s = 0; s < numSkeletons; s++)
        {
          const Skeleton* thisSkeleton = thisNodeEdge->skeleton(s);

          Vector3 thisSkeletonPos = thisSkeleton->getPos(); 
          XMarker thisVesselEdgeMarker(thisSkeletonPos);
          thisVesselEdgeMarker.type = 0; // edgeCount;
          std::string edgeName = "Centerlines";
          //std::string edgeName = "Edge #" + mlPDF::intToString(edgeCount);
          thisVesselEdgeMarker.setName(edgeName.c_str());
          _outEdgePositions.appendItem(thisVesselEdgeMarker);

          /*
          if (s < numSkeletons - 1)
          {
            IndexPair thisVesselEdgeConnection((int)s, (int)s + 1);
            thisVesselEdgeConnection.type = edgeCount;
            _outEdgeConnections.appendItem(thisVesselEdgeConnection);
          }
          */

          if (!newBranch)
          {
            IndexPair thisVesselEdgeConnection(currentEdgePositionNum - 1, currentEdgePositionNum);
            thisVesselEdgeConnection.type = 0; 
            _outEdgeConnections.appendItem(thisVesselEdgeConnection);
          }

          currentEdgePositionNum++;
          newBranch = false;

        }

        edgeCount++;

      }

    }

    nodeCount++;
  }

  ML_DELETE(vesselGraph);

  _outNodePositionsFld->touch();
  _outEdgePositionsFld->touch();
  _outEdgeConnectionsFld->touch();
  _createFibers();
}
ML_START_NAMESPACE


//***********************************************************************************


void SavePRC::PreProcessMeshData(WEMPtr saveWEM, 
							                   PRCMeshInfoVector &meshInfoVector,
                                 ModelBoundingBoxStruct& boundingBox)
{
  if (!_inWEM) 
  { 
    return; 
  }

  MLuint32 meshNumber = 0;

  bool simpleMode = _simpleModeMeshFld->getBoolValue();

  StringVector meshSpecificationsVector;

  if (simpleMode)
  {
    //meshSpecificationsVector.push_back("<U3DMesh>");
  }
  else
  {
    meshSpecificationsVector = getObjectSpecificationsStringFromUI(_meshSpecificationFld, "<Mesh>");
  }

  // Scan all WEM patches, triangulate them if necessary and collect base info.
  WEMPatch*           wemPatch = NULL;
  WEMTrianglePatch*   addedTrianglePatch = NULL;

  _statusFld->setStringValue("Analyzing mesh specification and input WEM.");

  const MLuint32 numberOfWEMPatches = _inWEM->getNumWEMPatches();

  for (MLuint32 i = 0; i < numberOfWEMPatches; i++)
  {
    PRCMeshInfoStruct   thisWEMMeshInfo;

    wemPatch = _inWEM->getWEMPatchAt(i); 
    addedTrianglePatch = NULL;
    const unsigned int newId = saveWEM->getCurrentWEMPatchId();

    if (wemPatch->getNumFaces() > 0)
    {

      if (wemPatch->getPatchType() != WEM_PATCH_TRIANGLES)
      {
        WEMTrianglePatch* triangulatedPatch = NULL;

        ML_CHECK_NEW(triangulatedPatch,WEMTrianglePatch());
        wemPatch->triangulate(triangulatedPatch, WEM_TRIANGULATION_STRIP);
        addedTrianglePatch = saveWEM->addWEMPatchCopy(triangulatedPatch);
        addedTrianglePatch->computeBoundingBox();
        ML_DELETE(triangulatedPatch);
      }
      else
      {
        addedTrianglePatch = saveWEM->addWEMPatchCopy(reinterpret_cast<WEMTrianglePatch*>(wemPatch));
      }

      if (addedTrianglePatch != NULL) 
      {
        addedTrianglePatch->setId(newId);

        // Adjust properties of main WEM bounding box
        WEMBoundingBox* thisWEMPatchBoundingBox = addedTrianglePatch->getBoundingBox();
        ModelBoundingBoxStruct newboundingBox;
        newboundingBox.start = thisWEMPatchBoundingBox->getMin();
        newboundingBox.end   = thisWEMPatchBoundingBox->getMax();
        UpdateBoundingBox(boundingBox, newboundingBox);

	      std::string wemDescription = addedTrianglePatch->getDescription();
        std::string wemLabel = addedTrianglePatch->getLabel();

        SpecificationParametersStruct thisSpecificationParameters;

        // Create an artificial meshSpecificationVector if only WEM label & description shall be used 
        if (simpleMode)
        {
          meshSpecificationsVector.clear();

          // Parse WEM label & description...
          std::string u3dModelName       = getSpecificParameterFromWEMDescription(wemDescription, "ModelName");
          std::string u3dGroupName       = getSpecificParameterFromWEMDescription(wemDescription, "GroupName");
          std::string u3dGroupPath       = "";
          if ("" != u3dModelName)
          {
            u3dGroupPath = "/" + u3dModelName + "/";
          }
          if ("" != u3dGroupName)
          {
            if ("" == u3dGroupPath)
            {
              u3dGroupPath += "/";
            }
            u3dGroupPath += u3dGroupName + "/";
          }

          std::string displayName = wemLabel;
          if (displayName == "") {
            displayName = "Mesh " + intToString(i+1);
          }

          // ...and write data into meshSpecification string
          std::string meshSpecificationsString = "<U3DMesh>";
          meshSpecificationsString += "<WEMLabel>" + wemLabel + "</WEMLabel>";
          meshSpecificationsString += "<ObjectName>" + displayName + "</ObjectName>";
          meshSpecificationsString += "<GroupPath>" + u3dGroupPath + "</GroupPath>";
          meshSpecificationsString += "<Color>" + getSpecificParameterFromWEMDescription(wemDescription, "Color") + "</Color>";
          meshSpecificationsString += "<SpecularColor>" + getSpecificParameterFromWEMDescription(wemDescription, "SpecularColor") + "</SpecularColor>";
          meshSpecificationsString += "<ModelVisibility>3</ModelVisibility>";

          // Add meshSpecification string to meshSpecificationVector
          meshSpecificationsVector.push_back(meshSpecificationsString);
        }

        for (int thisSpecificationIndex = 0; thisSpecificationIndex < meshSpecificationsVector.size(); thisSpecificationIndex++)
        {
          thisSpecificationParameters = getAllSpecificationParametersFromString(meshSpecificationsVector[thisSpecificationIndex]);
          if (thisSpecificationParameters.WEMLabel == wemLabel)
          {
            PRCObjectInfoStruct thisPRCObjectInfo = CreateNewPRCObjectInfo(i,PRCOBJECTTYPE_MESH, thisSpecificationParameters.ObjectName, defaultValues);
            thisPRCObjectInfo.GroupPath        = thisSpecificationParameters.GroupPath;
            thisPRCObjectInfo.ParentTreeNodeID = -1;
            thisPRCObjectInfo.RGBAColor        = getColorVec4(thisSpecificationParameters.Color, Vector4(0));  // If alpha = 0 -> Adobe doesn't render;
            _prcObjectInfoVector.push_back(thisPRCObjectInfo);



            // Collect mesh info
            thisWEMMeshInfo.DiffuseColorCount    = 0;    // This is not really needed in this version
            thisWEMMeshInfo.SpecularColorCount   = 0;    // This is not really needed in this version
            thisWEMMeshInfo.TextureCoordCount    = 0;    // This is not really needed in this version
            thisWEMMeshInfo.DefaultAmbientColor  = defaultValues.defaultMaterialAmbientColor;
            thisWEMMeshInfo.DefaultSpecularColor = defaultValues.defaultMaterialSpecularColor;
            thisWEMMeshInfo.DefaultDiffuseColor  = defaultValues.defaultMaterialDiffuseColorWithTransparency;
            thisWEMMeshInfo.DefaultEmissiveColor = defaultValues.defaultMaterialEmissiveColor;            
            thisWEMMeshInfo.FaceCount = addedTrianglePatch->getNumFaces();
            thisWEMMeshInfo.NormalCount = addedTrianglePatch->getNumFaces();
            thisWEMMeshInfo.VertexCount = addedTrianglePatch->getNumNodes();            
            thisWEMMeshInfo.PatchID = addedTrianglePatch->getId();
  //          thisWEMMeshInfo.MeshAttributes = U3D_MESH_ATTRIBUTES_DEFAULT;
  //          thisWEMMeshInfo.MeshAttributes |= ( (thisWEMMeshInfo.NormalCount == 0) ? U3D_MESH_ATTRIBUTES_EXCLUDENORMALS : 0 );
  //          thisWEMMeshInfo.ShadingAttributes = U3D_SHADINGATTRIBUTES_NONE;  
  //          thisWEMMeshInfo.ShadingAttributes |= ( (thisWEMMeshInfo.DiffuseColorCount > 0) ? U3D_SHADINGATTRIBUTES_DIFFUSECOLORS : 0 );   // Should not happen in this version
  //          thisWEMMeshInfo.ShadingAttributes |= ( (thisWEMMeshInfo.SpecularColorCount > 0) ? U3D_SHADINGATTRIBUTES_SPECULARCOLORS : 0 ); // Should not happen in this version
  //          thisWEMMeshInfo.ResourceName = thisPRCObjectInfo.ResourceName;
            thisWEMMeshInfo.MeshNumber = meshNumber++;

	          meshInfoVector.push_back(thisWEMMeshInfo);           
          }
        }

      }  // if (addedTrianglePatch != NULL)

    }  // if (wemPatch->getNumFaces() > 0)

    wemPatch = NULL;
  }

}