1 2 #ifndef WK_GEOGRAPHY_H 3 #define WK_GEOGRAPHY_H 4 5 #include <vector> 6 7 #include "wk/rcpp-io.hpp" 8 #include "wk/reader.hpp" 9 #include "wk/geometry-handler.hpp" 10 11 #include "point-geography.h" 12 #include "polyline-geography.h" 13 #include "polygon-geography.h" 14 #include "geography-collection.h" 15 16 #include <Rcpp.h> 17 #include "geography.h" 18 19 #define CODE_HAS_BUILD_ERROR 3938829 20 21 22 class WKGeographyWriter: public WKGeometryHandler { 23 public: 24 Rcpp::List output; 25 R_xlen_t featureId; 26 27 Rcpp::IntegerVector problemId; 28 Rcpp::CharacterVector problems; 29 WKGeographyWriter(R_xlen_t size)30 WKGeographyWriter(R_xlen_t size): 31 output(size), 32 builder(nullptr), 33 oriented(false), 34 check(true) {} 35 setOriented(bool oriented)36 void setOriented(bool oriented) { 37 this->oriented = oriented; 38 } 39 setCheck(bool check)40 void setCheck(bool check) { 41 this->check = check; 42 } 43 nextFeatureStart(size_t featureId)44 void nextFeatureStart(size_t featureId) { 45 this->builder = std::unique_ptr<GeographyBuilder>(nullptr); 46 this->featureId = featureId; 47 } 48 nextNull(size_t featureId)49 void nextNull(size_t featureId) { 50 this->output[featureId] = R_NilValue; 51 } 52 nextGeometryStart(const WKGeometryMeta & meta,uint32_t partId)53 void nextGeometryStart(const WKGeometryMeta& meta, uint32_t partId) { 54 if (!this->builder) { 55 switch (meta.geometryType) { 56 case WKGeometryType::Point: 57 case WKGeometryType::MultiPoint: 58 this->builder = absl::make_unique<PointGeography::Builder>(); 59 break; 60 case WKGeometryType::LineString: 61 case WKGeometryType::MultiLineString: 62 this->builder = absl::make_unique<PolylineGeography::Builder>(); 63 break; 64 case WKGeometryType::Polygon: 65 case WKGeometryType::MultiPolygon: 66 this->builder = absl::make_unique<PolygonGeography::Builder>( 67 this->oriented, 68 this->check 69 ); 70 break; 71 case WKGeometryType::GeometryCollection: 72 this->builder = absl::make_unique<GeographyCollection::Builder>( 73 this->oriented, 74 this->check 75 ); 76 break; 77 default: 78 std::stringstream err; 79 err << "Unknown geometry type in geography builder: " << meta.geometryType; 80 this->addProblem(err.str()); 81 throw WKParseException(CODE_HAS_BUILD_ERROR); 82 } 83 } 84 85 this->builder->nextGeometryStart(meta, partId); 86 } 87 nextLinearRingStart(const WKGeometryMeta & meta,uint32_t size,uint32_t ringId)88 void nextLinearRingStart(const WKGeometryMeta& meta, uint32_t size, uint32_t ringId) { 89 this->builder->nextLinearRingStart(meta, size, ringId); 90 } 91 nextCoordinate(const WKGeometryMeta & meta,const WKCoord & coord,uint32_t coordId)92 void nextCoordinate(const WKGeometryMeta& meta, const WKCoord& coord, uint32_t coordId) { 93 this->builder->nextCoordinate(meta, coord, coordId); 94 } 95 nextLinearRingEnd(const WKGeometryMeta & meta,uint32_t size,uint32_t ringId)96 void nextLinearRingEnd(const WKGeometryMeta& meta, uint32_t size, uint32_t ringId) { 97 try { 98 this->builder->nextLinearRingEnd(meta, size, ringId); 99 } catch (WKParseException& e) { 100 this->addProblem(e.what()); 101 throw WKParseException(CODE_HAS_BUILD_ERROR); 102 } 103 } 104 nextGeometryEnd(const WKGeometryMeta & meta,uint32_t partId)105 void nextGeometryEnd(const WKGeometryMeta& meta, uint32_t partId) { 106 this->builder->nextGeometryEnd(meta, partId); 107 } 108 nextFeatureEnd(size_t featureId)109 void nextFeatureEnd(size_t featureId) { 110 if (this->builder) { 111 try { 112 std::unique_ptr<Geography> feature = builder->build(); 113 this->output[featureId] = Rcpp::XPtr<Geography>(feature.release()); 114 } catch (WKParseException& e) { 115 this->addProblem(e.what()); 116 throw WKParseException(CODE_HAS_BUILD_ERROR); 117 } 118 } 119 } 120 nextError(WKParseException & error,size_t featureId)121 bool nextError(WKParseException& error, size_t featureId) { 122 if (error.code() == CODE_HAS_BUILD_ERROR) { 123 this->output[featureId] = R_NilValue; 124 return true; 125 } else { 126 return false; 127 } 128 129 this->nextFeatureEnd(featureId); 130 return true; 131 } 132 133 private: 134 std::unique_ptr<GeographyBuilder> builder; 135 bool oriented; 136 bool check; 137 addProblem(std::string what)138 void addProblem(std::string what) { 139 problemId.push_back(this->featureId); 140 problems.push_back(what); 141 } 142 }; 143 144 145 class WKGeographyReader: public WKReader { 146 public: 147 WKGeographyReader(WKRcppSEXPProvider & provider)148 WKGeographyReader(WKRcppSEXPProvider& provider): 149 WKReader(provider), provider(provider) {} 150 readFeature(size_t featureId)151 void readFeature(size_t featureId) { 152 this->handler->nextFeatureStart(featureId); 153 154 if (this->provider.featureIsNull()) { 155 this->handler->nextNull(featureId); 156 } else { 157 Rcpp::XPtr<Geography> geography(this->provider.feature()); 158 geography->Export(handler, WKReader::PART_ID_NONE); 159 } 160 161 this->handler->nextFeatureEnd(featureId); 162 } 163 164 private: 165 WKRcppSEXPProvider& provider; 166 }; 167 168 #endif 169