Commit 0e6e9e30 authored by Yumin Yuan's avatar Yumin Yuan Committed by David Thompson
Browse files

Added an Import op to polygon session.

The new Import operator will use vtk readers to read files like shape, poly, vtk or vtp, map files etc, then invoke CreateEdge operatorusing point coordinates of line cells from reader-output-polydata as input, to create edges for a new empty polygon model.
parent 367870ff
......@@ -31,10 +31,36 @@ smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/CreateFaces.sbt" polygo
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/ForceCreateFace.sbt" polygonOperatorXML)
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/SplitEdge.sbt" polygonOperatorXML)
# The import operator is only available if there is VTK
if(SMTK_ENABLE_VTK_SUPPORT)
include("${VTK_USE_FILE}")
list(APPEND CMAKE_MODULE_PATH "${VTK_MODULES_DIR}")
set(polygonSrcs ${polygonSrcs}
operators/Import.cxx
)
set(polygonHeaders ${polygonHeaders}
operators/Import.h
)
smtk_operator_xml("${CMAKE_CURRENT_SOURCE_DIR}/operators/Import.sbt" polygonOperatorXML)
set(import_vtk_depends
vtkCommonCore
vtkCommonDataModel
vtkInteractionStyle
vtkIOParallel
vtkRenderingCore
vtkRenderingFreeType
vtkRendering${VTK_RENDERING_BACKEND}
vtkSMTKReaderExt
vtksys
)
endif()
add_library(smtkPolygonSession ${polygonSrcs})
target_link_libraries(smtkPolygonSession
LINK_PUBLIC
smtkCore
LINK_PRIVATE
${import_vtk_depends}
)
smtk_export_header(smtkPolygonSession Exports.h)
......
......@@ -4,7 +4,9 @@
{
"name": "native",
"filetypes": [
".map (Map polygon file)",
".poly (Triangle polygon file)",
".shp (Lines polygon file)",
".smesh (Surface mesh)"
]
}
......
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt 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.
//=========================================================================
#include "Import.h"
#include "smtk/bridge/polygon/Session.h"
#include "smtk/bridge/polygon/internal/Model.h"
#include "smtk/io/Logger.h"
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/DoubleItem.h"
#include "smtk/attribute/FileItem.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/attribute/ModelEntityItem.h"
#include "smtk/attribute/StringItem.h"
#include "smtk/model/Manager.h"
#include "smtk/model/Model.h"
#include "smtk/model/Operator.h"
#include "smtk/model/SessionRef.h"
#include "smtk/extension/vtk/reader/vtkCMBGeometryReader.h"
#ifdef SMTK_ENABLE_REMUS_SUPPORT
#include "smtk/extension/vtk/reader/vtkCMBPolygonModelImporter.h"
#include "smtk/extension/vtk/reader/vtkCMBMapReader.h"
#endif
#include "smtk/bridge/polygon/Import_xml.h"
#include "vtkCellArray.h"
#include "vtkDataSetSurfaceFilter.h"
#include "vtkNew.h"
#include "vtkPDataSetReader.h"
#include "vtkPolyData.h"
#include <vtksys/SystemTools.hxx>
#include "smtk/io/ExportJSON.h"
#include "cJSON.h"
using namespace smtk::model;
namespace smtk {
namespace bridge {
namespace polygon {
//----------------------------------------------------------------------------
int polyLines2modelEdges(vtkPolyData *mesh,
smtk::model::Model& model,
smtk::bridge::polygon::Session* sess)
{
int numEdges = 0;
vtkCellArray *lines = mesh->GetLines();
double p[3];
if (lines)
{
smtk::model::Operator::Ptr edgeOp = sess->op("create edge");
smtk::attribute::AttributePtr spec = edgeOp->specification();
spec->associateEntity(model);
smtk::attribute::IntItem::Ptr constructMethod = spec->findInt("construction method");
constructMethod->setValue(0); // "points coornidates"
smtk::attribute::IntItem::Ptr numCoords = spec->findInt("coordinates");
numCoords->setValue(3); // number of elements in coordinates
smtk::attribute::DoubleItem::Ptr pointsItem = spec->findDouble("points");
vtkIdType *pts,npts;
for (lines->SetTraversalLocation(0);lines->GetNextCell(npts,pts);)
{
std::vector<double> ptscoords;
for (vtkIdType j=0; j < npts; ++j)
{
mesh->GetPoint(pts[j],p);
ptscoords.insert(ptscoords.end(), &p[0], p+3);
}
pointsItem->setValues(ptscoords.begin(), ptscoords.end());
OperatorResult edgeResult = edgeOp->operate();
if (edgeResult->findInt("outcome")->value() == OPERATION_SUCCEEDED)
{
numEdges += edgeResult->findModelEntity("created")->numberOfValues();
}
}
}
return numEdges;
}
Import::Import()
{
}
bool Import::ableToOperate()
{
if(!this->specification()->isValid())
return false;
std::string filename = this->specification()->findFile("filename")->value();
if (filename.empty())
return false;
// support 2d models by vtkCMBGeometryReader
std::string ext = vtksys::SystemTools::GetFilenameLastExtension(filename);
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
if (ext == ".2dm" ||
#ifdef SMTK_ENABLE_REMUS_SUPPORT
ext == ".poly" || ext == ".smesh" || ext == ".map" || ext == ".shp" ||
#endif
ext == ".stl" ||
ext == ".vtp" ||
ext == ".vtk")
{
return true;
}
return false;
}
OperatorResult Import::operateInternal()
{
std::string filename = this->specification()->findFile("filename")->value();
if (filename.empty())
{
std::cerr << "File name is empty!\n";
return this->createResult(OPERATION_FAILED);
}
vtkPolyData* polyOutput = vtkPolyData::New();
// ******************************************************************************
// This is where we should have the logic to import files other than .cmb formats
// ******************************************************************************
std::string ext = vtksys::SystemTools::GetFilenameLastExtension(filename);
if (ext == ".2dm" ||
ext == ".3dm" ||
#ifdef SMTK_ENABLE_REMUS_SUPPORT
ext == ".poly" || ext == ".smesh" ||
#endif
/* ext == ".tin" ||
ext == ".fac" ||
ext == ".obj" ||
ext == ".sol" || */
ext == ".stl" ||
ext == ".vtp")
{
vtkNew<smtk::vtk::vtkCMBGeometryReader> reader;
reader->SetFileName(filename.c_str());
reader->SetPrepNonClosedSurfaceForModelCreation(false);
reader->SetEnablePostProcessMesh(false);
reader->Update();
polyOutput->ShallowCopy( reader->GetOutput() );
/*
bool hasBoundaryEdges = reader->GetHasBoundaryEdges();
if(ext == ".poly" || ext == ".smesh" || hasBoundaryEdges)
{
this->m_op->Operate(mod.GetPointer(), reader.GetPointer());
}
else
{
vtkNew<vtkMasterPolyDataNormals> normals;
normals->SetInputData(0, reader->GetOutputDataObject(0));
normals->Update();
vtkNew<vtkMergeDuplicateCells> merge;
merge->SetModelRegionArrayName(ModelParserHelper::GetShellTagName());
merge->SetModelFaceArrayName(ModelParserHelper::GetModelFaceTagName());
merge->SetInputData(0, normals->GetOutputDataObject(0));
merge->Update();
this->m_op->Operate(mod.GetPointer(), merge.GetPointer());
}
*/
}
#ifdef SMTK_ENABLE_REMUS_SUPPORT
else if(ext == ".map")
{
vtkNew<smtk::vtk::vtkCMBMapReader> reader;
reader->SetFileName(filename.c_str());
reader->Update();
polyOutput->ShallowCopy( reader->GetOutput() );
/*
vtkNew<vtkCMBTriangleMesher> trimesher;
trimesher->SetPreserveEdgesAndNodes(true);
trimesher->SetInputData(0, reader->GetOutputDataObject(0));
trimesher->Update();
this->m_mapOp->Operate(mod.GetPointer(), trimesher.GetPointer());
*/
}
else if(ext == ".shp")
{
vtkNew<smtk::vtk::vtkCMBPolygonModelImporter> reader;
reader->SetFileName(filename.c_str());
reader->Update();
polyOutput->ShallowCopy( reader->GetOutput() );
/*
smtk::attribute::StringItem::Ptr boundaryItem =
this->specification()->findString("ShapeBoundaryStyle");
if(boundaryItem->isEnabled())
{
vtkNew<smtk::vtk::vtkCMBGeometry2DReader> reader;
reader->SetFileName(filename.c_str());
std::string boundaryStyle = boundaryItem->value();
if (boundaryStyle == "None") // default
{
reader->SetBoundaryStyle(smtk::vtk::vtkCMBGeometry2DReader::NONE);
}
else if (boundaryStyle == "Relative Margin")
{
reader->SetBoundaryStyle(smtk::vtk::vtkCMBGeometry2DReader::RELATIVE_MARGIN);
smtk::attribute::StringItem::Ptr relMarginItem =
this->specification()->findString("relative margin");
reader->SetRelativeMarginString(relMarginItem->value().c_str());
}
else if (boundaryStyle == "Absolute Margin")
{
reader->SetBoundaryStyle(smtk::vtk::vtkCMBGeometry2DReader::ABSOLUTE_MARGIN);
smtk::attribute::StringItem::Ptr absMarginItem =
this->specification()->findString("absolute margin");
reader->SetAbsoluteMarginString(absMarginItem->value().c_str());
}
else if (boundaryStyle == "Bounding Box")
{
reader->SetBoundaryStyle(smtk::vtk::vtkCMBGeometry2DReader::ABSOLUTE_BOUNDS);
smtk::attribute::StringItem::Ptr absBoundsItem =
this->specification()->findString("absolute bounds");
reader->SetAbsoluteBoundsString(absBoundsItem->value().c_str());
}
else if (boundaryStyle == "Bounding File")
{
reader->SetBoundaryStyle(smtk::vtk::vtkCMBGeometry2DReader::IMPORTED_POLYGON);
smtk::attribute::StringItem::Ptr boundsFileItem =
this->specification()->findString("imported polygon");
reader->SetBoundaryFile(boundsFileItem->value().c_str());
}
else
{
std::cerr << "Invalid Shape file boundary. No boundary will be set.\n";
reader->SetBoundaryStyle(smtk::vtk::vtkCMBGeometry2DReader::NONE);
}
reader->Update();
polyOutput->ShallowCopy( reader->GetOutput() );
}
else
{
smtkInfoMacro(log(), "Shape file boundary has to be set.");
return this->createResult(OPERATION_FAILED);
}
*/
}
#endif
else if(ext == ".vtk")
{
vtkNew<vtkPDataSetReader> reader;
reader->SetFileName(filename.c_str());
reader->Update();
vtkNew<vtkDataSetSurfaceFilter> surface;
surface->SetInputData(0, reader->GetOutputDataObject(0));
surface->Update();
polyOutput->ShallowCopy( surface->GetOutput() );
/*
vtkNew<vtkMasterPolyDataNormals> normals;
normals->SetInputData(0, surface->GetOutputDataObject(0));
normals->Update();
vtkNew<vtkMergeDuplicateCells> merge;
merge->SetModelRegionArrayName(ModelParserHelper::GetShellTagName());
merge->SetModelFaceArrayName(ModelParserHelper::GetModelFaceTagName());
merge->SetInputData(0, normals->GetOutputDataObject(0));
merge->Update();
this->m_op->Operate(mod.GetPointer(), merge.GetPointer());
*/
}
else
{
smtkInfoMacro(log(), "Unhandled file extension " << ext << ".");
polyOutput->Delete();
return this->createResult(OPERATION_FAILED);
}
OperatorResult result;
// First create a model with CreateModel op, then use line cells from reader's
// output polydata to create edges
smtk::bridge::polygon::Session* sess = this->polygonSession();
if (sess)
{
smtk::model::Operator::Ptr modOp = sess->op("create model");
if(!modOp)
{
smtkInfoMacro(log(), "Failed to create CreateModel op.");
result = this->createResult(OPERATION_FAILED);
}
modOp->findInt("model scale")->setValue(1);
modOp->findDouble("feature size")->setValue(1.0);
OperatorResult modResult = modOp->operate();
if (modResult->findInt("outcome")->value() != OPERATION_SUCCEEDED)
{
smtkInfoMacro(log(), "CreateModel operator failed.");
result = this->createResult(OPERATION_FAILED);
}
smtk::model::Model model = modResult->findModelEntity("created")->value();
int numEdges = polyLines2modelEdges(polyOutput, model, sess);
std::cout << "Number of edges: " << numEdges << "\n";
result = this->createResult(OPERATION_SUCCEEDED);
this->addEntityToResult(result, model, CREATED);
/*
//#include "smtk/io/ExportJSON.h"
//#include "cJSON.h"
cJSON* json = cJSON_CreateObject();
smtk::io::ExportJSON::fromModelManager(json, this->manager());
std::cout << "Result " << cJSON_Print(json) << "\n";
cJSON_Delete(json);
*/
/*
std::string json = smtk::io::ExportJSON::fromModelManager(this->manager());
std::ofstream file("/tmp/import_op_out.json");
file << json;
file.close();
*/
}
else
{
smtkInfoMacro(log(), "Invalid polygon session.");
result = this->createResult(OPERATION_FAILED);
}
polyOutput->Delete();
return result;
}
} // namespace polygon
} // namespace bridge
} // namespace smtk
smtkImplementsModelOperator(
SMTKPOLYGONSESSION_EXPORT,
smtk::bridge::polygon::Import,
polygon_import,
"import",
Import_xml,
smtk::bridge::polygon::Session);
//=========================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt 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.
//=========================================================================
#ifndef __smtk_session_polygon_Import_h
#define __smtk_session_polygon_Import_h
#include "smtk/bridge/polygon/Operator.h"
namespace smtk {
namespace bridge {
namespace polygon {
/**\brief Import a CMB polygon model file.
*
* The supported file extensions currently:
* "Moab files (*.h5m *.sat *.brep *.stp *.cub *.exo)
*
* NOT YET:
* "VTK data files (*.vtk *.vtu *.vtp)
* "Solids (*.2dm *.3dm *.sol *.stl *.tin *.obj)
* "SimBuilder files (*.crf *.sbt *.sbi *.sbs)
* "Map files (*.map)
* "Poly files (*.poly *.smesh)
* "Shape files (*.shp)
*/
class SMTKPOLYGONSESSION_EXPORT Import : public Operator
{
public:
smtkTypeMacro(Import);
smtkCreateMacro(Import);
smtkSharedFromThisMacro(Operator);
smtkDeclareModelOperator();
virtual bool ableToOperate();
protected:
Import();
virtual smtk::model::OperatorResult operateInternal();
};
} // namespace polygon
} // namespace bridge
} // namespace smtk
#endif // __smtk_session_polygon_Import_h
<?xml version="1.0" encoding="utf-8" ?>
<!-- Description of the CMB polygon Model "import" Operator -->
<SMTK_AttributeSystem Version="2">
<Definitions>
<!-- Operator -->
<AttDef Type="import" BaseType="operator">
<ItemDefinitions>
<File Name="filename" Label="File Name" NumberOfRequiredValues="1"
ShouldExist="true"
FileFilters="Legacy VTK files (*.vtk);;Solids (*.2dm *.3dm *.stl *.sol *.tin *.obj);;Map files (*.map);;Poly files (*.poly *.smesh);;Shape files (*.shp);;All files (*.*)">
</File>
<String Name="ShapeBoundaryStyle" Label="Specify Shape File Boundary" Version="0" AdvanceLevel="0" NumberOfRequiredValues="1" Optional="true" IsEnabledByDefault="true">
<BriefDescription>This is required for shape file </BriefDescription>
<ChildrenDefinitions>
<String Name="relative margin" Label="As fraction of data diameter" NumberOfRequiredValues="1">
<DefaultValue>5</DefaultValue>
</String>
<String Name="absolute margin" Label="Absolute margin" NumberOfRequiredValues="1">
<DefaultValue>1</DefaultValue>
<BriefDescription>all or left+right, bottom+top or left, right, bottom, top</BriefDescription>
</String>
<String Name="absolute bounds" Label="Bounding box coordinates" NumberOfRequiredValues="1" >
<BriefDescription>left, right, bottom, top</BriefDescription>
</String>
<File Name="imported polygon" Label="Bounding polyline file" NumberOfRequiredValues="1"
ShouldExist="true"
FileFilters="Shape files (*.shp)">
</File>
</ChildrenDefinitions>
<DiscreteInfo DefaultIndex="0">
<Structure>
<Value Enum="Import File As-is">None</Value>
</Structure>
<Structure>
<Value Enum="Set Relative Margin">Relative Margin</Value>
<Items>
<Item>relative margin</Item>
</Items>
</Structure>
<Structure>
<Value Enum="Set Absolute Margin">Absolute Margin</Value>
<Items>
<Item>absolute margin</Item>
</Items>
</Structure>
<Structure>
<Value Enum="Set Bounding Box">Bounding Box</Value>
<Items>
<Item>absolute bounds</Item>
</Items>
</Structure>
<Structure>
<Value Enum="Set Bounding File">Bounding File</Value>
<Items>
<Item>imported polygon</Item>
</Items>
</Structure>
</DiscreteInfo>
</String>
</ItemDefinitions>
</AttDef>
<!-- Result -->
<AttDef Type="result(import)" BaseType="result"/>
</Definitions>
</SMTK_AttributeSystem>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment