text: #include "navmesh.h"
  
  namespace unnatural
  {
  	using namespace navoptim;
  
  	Holder<Mesh> navmeshOptimize(const Holder<Mesh> &navigation, const NavmeshOptimizeConfig &config)
  	{
  		CAGE_LOG(SeverityEnum::Info, "libnavmesh", "initiating navigation optimization");
  
  		switch (navigation->type())
  		{
  		case MeshTypeEnum::Triangles:
  		case MeshTypeEnum::Lines:
  			break;
  		default:
  			CAGE_THROW_ERROR(Exception, "unsupported mesh type");
  		}
  
  		Holder<Mesh> nav = navigation->copy();
  		
  		{
  			CAGE_LOG(SeverityEnum::Info, "libnavmesh", "merging close vertices");
  			MeshMergeCloseVerticesConfig cfg;
  			cfg.distanceThreshold = 1e-3;
  			meshMergeCloseVertices(+nav, cfg);
  		}
  
  		Graph graph = convertMeshToGraph(+nav, config.tileSize);
  		graphValidationUnconditional(graph); // input validation
  		printStatistics(graph);
  		const SpatialGraph original = convertToSpatialGraph(graph);
  
  		if (nav->type() == MeshTypeEnum::Triangles && config.pmpRegularization)
  		{
  			CAGE_LOG(SeverityEnum::Info, "libnavmesh", "initial regularization");
  			MeshRegularizeConfig cfg;
  			cfg.targetEdgeLength = config.tileSize;
  			cfg.iterations = 10;
  			meshRegularize(+nav, cfg);
  			graph = convertMeshToGraph(+nav, config.tileSize);
  			graphValidationDebugOnly(graph);
  			printStatistics(graph);
  		}
  		else
  			CAGE_LOG(SeverityEnum::Info, "libnavmesh", "skipping initial regularization");
  
  		if (nav->type() == MeshTypeEnum::Triangles && config.markBorderVertices)
  			markBorderNodes(graph);
  		else
  			CAGE_LOG(SeverityEnum::Info, "libnavmesh", "skipping marking border nodes");
  
  		for (uint32 iteration = 0; iteration < config.iterations; iteration++)
  		{
  			CAGE_LOG(SeverityEnum::Info, "libnavmesh", Stringizer() + "navmesh optimizing iteration: " + iteration);
  			optimizeNodePositions(graph);
  			addNeighborEdges(graph);
  			splitLongEdges(graph);
  			joinCloseNodes(graph);
  			removeSuboptimalEdges(graph);
  			updateNodeProperties(graph, original);
  			printStatistics(graph);
  		}
  
  		CAGE_LOG(SeverityEnum::Info, "libnavmesh", "finishing navigation optimization");
  		graphValidationUnconditional(graph); // output validation
  		nav = convertGraphToMesh(graph, config.tileSize);
  		return nav;
  	}
  }
  
  