dmpproject.cpp 8.9 KB
/**************************************************************************
* file:              dmpproject.cpp

* Author:            wanzhongping
* Date:              2021-07-07 16:46:54
* Email:             zhongpingw@chinadci.com
* copyright:         广州城市信息研究所有限公司
***************************************************************************/
#include <iostream>

#include <boost/algorithm/string/case_conv.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/typeof/typeof.hpp>
#include "dmpproject.h"
#include "dmptilelayer.h"
#include "dmpvectorlayer.h"
using namespace boost::property_tree;
DmpProject *DmpProject::project_ = nullptr;

DmpProject::DmpProject()
{
}

DmpProject *DmpProject::Instance()
{
  if (!project_)
  {
    project_ = new DmpProject;
  }
  return project_;
}

DmpProject::~DmpProject()
{
  if (this == project_)
  {
    project_ = nullptr;
  }

  std::map<std::string, DmpMapLayer *>::iterator iter = mapLayers_.begin();
  for (; iter != mapLayers_.end(); ++iter)
  {
    DmpMapLayer *mapLayer = iter->second;
    if (mapLayer)
    {
      delete mapLayer;
      mapLayer = nullptr;
    }
  }
  mapLayers_.clear();
  vectorLayers_.clear();
}

bool DmpProject::Read(const std::string &data)
{
  try
  {
    std::istringstream stream(data);
    ptree pt;
    read_xml(stream, pt);
    projectName_ = pt.get<std::string>("dmap.<xmlattr>.projectname");
    version_ = pt.get<std::string>("dmap.<xmlattr>.version");

    //坐标系
    ptree pSpatialRef = pt.get_child("dmap.projectCrs.spatialrefsys");
    if (!crs_.readXml(pSpatialRef))
    {
      return false;
    }

    //图层
    ptree pLayers = pt.get_child("dmap.projectlayers");
    for (BOOST_AUTO(pos, pLayers.begin()); pos != pLayers.end(); ++pos)
    {
      DmpMapLayer *mapLayer = nullptr;
      ptree pLayer = pos->second;
      int layerType = pLayer.get<int>("<xmlattr>.type");
      if (layerType == 0)
      {
        //tile
        mapLayer = new DmpTileLayer();
        
      }
      else if (layerType == 1)
      {
        //vector
        mapLayer = new DmpVectorLayer();
      }
      else if (layerType == 2)
      {
        //image
      }
      else
      {
        return false;
      }
      if (mapLayer && mapLayer->readXml(pLayer))
      {
        std::string name = mapLayer->name();
        boost::to_upper(name);
        mapLayers_[name] = mapLayer;
        vectorLayers_.push_back(mapLayer);
      }
      else
      {
        return false;
      }
    }
  }
  catch (const std::exception &e)
  {
    std::cerr << e.what() << '\n';
    return false;
  }
  return true;
}

bool DmpProject::Write(const std::string &filename, const std::string &data)
{
  std::istringstream stream(data);
  boost::property_tree::ptree pt;
  boost::property_tree::read_xml(stream, pt);
  auto setting = boost::property_tree::xml_writer_make_settings<std::string>('\t', 1);
  boost::property_tree::write_xml(filename, pt, std::locale(), setting);
  return true;
}

bool DmpProject::WritePtree(boost::property_tree::ptree& ptDoc) 
{
  //目前还未完善 只支持 矢量图层
  boost::property_tree::ptree ptDmap;

  ptDmap.add("<xmlattr>.projectname",projectName_);
  ptDmap.add("<xmlattr>.version",version_);

  boost::property_tree::ptree ptProjectCrs;
  crs_.write(ptProjectCrs);
  ptDmap.add_child("projectCrs",ptProjectCrs);

  boost::property_tree::ptree ptProjectlayers;

  for(int i =0; i< vectorLayers_.size(); i++)
  {
    DmpMapLayer *mapLayer = vectorLayers_[i];
    if (mapLayer && mapLayer->type() == DmpMapLayerType::VectorLayer)
    {
      boost::property_tree::ptree ptlayer;
      ptlayer.add("<xmlattr>.type", "1");
      DmpVectorLayer *vectorMapLayer = (DmpVectorLayer *)mapLayer;
      vectorMapLayer->writeXml(ptlayer);
      ptProjectlayers.add_child("maplayer", ptlayer);
    }
  }

  ptDmap.add_child("projectlayers", ptProjectlayers);
  ptDoc.add_child("dmap",ptDmap);

  return true;
}

std::string  DmpProject::WriteJson()
{
  boost::property_tree::ptree ptDoc;
  WritePtree(ptDoc);
  std::stringstream stream; 
  write_json(stream, ptDoc);
  std::string data = stream.str();
  return data;
}

std::string DmpProject::WriteXml()
{
  boost::property_tree::ptree ptDoc;
  WritePtree(ptDoc);
  std::stringstream stream; 
  write_xml(stream, ptDoc);
  std::string data = stream.str();
  return data;
}

DmpCoordinateReferenceSystem DmpProject::crs() const
{
  return crs_;
}

std::map<std::string, DmpMapLayer*> DmpProject::mapLayers() const
{
  return mapLayers_;
}

std::vector<DmpMapLayer*> DmpProject::vectorLayers() const
{
  return vectorLayers_;
}

DmpMapLayer *DmpProject::getLayer(const std::string &layerName) const
{
  if(layerName.empty()){
    return getLayer();
  }
  std::string name = boost::to_upper_copy(layerName); 
  std::map<std::string, DmpMapLayer*>::const_iterator iter = mapLayers_.find(name);
  if (iter != mapLayers_.end())
  {
    return iter->second;
  }
  else
  {
    return nullptr;
  }
}

DmpMapLayer *DmpProject::getLayer() const
{
  std::map<std::string, DmpMapLayer*>::const_iterator iter = mapLayers_.begin();
  if (iter != mapLayers_.end())
  {
    return iter->second;
  }
  else
  {
    return nullptr;
  }
}

bool DmpProject::initVectorLayerVacuate(std::function<std::string(const std::string &)> getVacuateFun)
{
  try
  {
    std::string tableguids = "";
    for (int i = 0; i < vectorLayers_.size(); i++)
    {
      DmpMapLayer *layer = vectorLayers_.at(i);
      if (layer->type() == DmpMapLayerType::VectorLayer)
      {
        if (!tableguids.empty())
        {
          tableguids += ",";
        }
        tableguids += layer->id();
      }
    }

    if (tableguids.empty())
    {
      return false;
    }

    std::string vacuateInfo = getVacuateFun(tableguids);
    if (vacuateInfo.empty())
    {
      return false;
    }

    std::istringstream stream(vacuateInfo);
    ptree pt;
    read_json(stream, pt);
    bool result = pt.get<bool>("result");
    if (!result)
    {
      return false;
    }

    //图层
    ptree pLayers = pt.get_child("data");
    // for (BOOST_AUTO(pos, pLayers.begin()); pos != pLayers.end(); ++pos)
    for (ptree::iterator pos = pLayers.begin(); pos != pLayers.end(); ++pos)
    {
      ptree pLayer = pos->second;
      int vacuateCount = pLayer.get<int>("vacuate_count");
      if (vacuateCount > 0)
      {
        std::string tableGuid = pLayer.get<std::string>("table_guid");
        std::string tableName = pLayer.get<std::string>("table_name");

        DmpMapLayer *layer = this->getLayer(tableName);
        if (layer && layer->type() == DmpMapLayerType::VectorLayer)
        {
          DmpVectorLayer *vectorLayer = (DmpVectorLayer *)layer;
          ptree ptableVacuates = pLayer.get_child("table_vacuate");
          for (BOOST_AUTO(pos1, ptableVacuates.begin()); pos1 != ptableVacuates.end(); ++pos1)
          {
            ptree pVacuateLayer = pos1->second;
            shared_ptr<DmpVectorVacuateLayer> vacuateLayer(new DmpVectorVacuateLayer());
            std::string name = pVacuateLayer.get<std::string>("name");
            std::string connectStr = pVacuateLayer.get<std::string>("connectstr");
            double pixel_distance = pVacuateLayer.get<double>("pixel_distance");
            vacuateLayer->Init(pixel_distance, name, connectStr);
            vectorLayer->ApplendCurrentScaleTable(vacuateLayer);
          }
        }
      }
    }//for
    return true;
  }
  catch (const std::exception &e)
  {
    std::cerr << e.what() << '\n';
    return false;
  }
  return false;
}

std::shared_ptr<DmpRectangle>  DmpProject::GetExtent()
{
  shared_ptr<DmpRectangle> rect(new DmpRectangle());
  for (size_t i = 0; i < this->vectorLayers_.size(); i++)
  {
      DmpMapLayer* layer = this->vectorLayers_.at(i);
      DmpRectangle layerExtent = layer->extent();
      rect->merge(layerExtent);
  }
  return rect;
}

bool DmpProject::initVectorLayerVacuate(DmpProject* project)
{
  if(!project) return false;
  for (size_t i = 0; i < project->vectorLayers().size(); i++)
  {
    DmpMapLayer *layer = project->vectorLayers().at(i);
    if (layer->type() == DmpMapLayerType::VectorLayer)
    {
      DmpVectorLayer *vectorLayer = (DmpVectorLayer *)layer;
      DmpVectorLayer *thisVectorLayer = (DmpVectorLayer*)this->getLayer(layer->name());
      for (size_t i0 = 0; i0 < vectorLayer->vacuateLayers().size(); i0++)
      {
          std::shared_ptr<DmpVectorVacuateLayer> pvectorVacuateLayer =  vectorLayer->vacuateLayers().at(i0);
          thisVectorLayer->ApplendCurrentScaleTable(pvectorVacuateLayer->clone());
          //thisVectorLayer->vacuateLayers().push_back(pvectorVacuateLayer->clone());
      }
      
    }
  }
  return true;
}