SEXP R_export2dataset(SEXP path, SEXP dataframe, SEXP shape, SEXP shape_info) { std::wstring dataset_name; tools::copy_to(path, dataset_name); struct _cleanup { typedef std::vector<cols_base*> c_type; std::vector<std::wstring> name; c_type c; ~_cleanup() { for (size_t i = 0, n = c.size(); i < n; i++) delete c[i]; } }cols; shape_extractor extractor; bool isShape = extractor.init(shape, shape_info) == S_OK; tools::getNames(dataframe, cols.name); R_xlen_t nlen = 0; ATLTRACE("dataframe type:%s", Rf_type2char(TYPEOF(dataframe))); if (Rf_isVectorList(dataframe)) { size_t k = tools::size(dataframe); ATLASSERT(cols.name.size() == k); cols.name.resize(k); for (size_t i = 0; i < k; i++) { nlen = std::max(nlen, tools::size(VECTOR_ELT(dataframe, i))); if (cols.name[i].empty()) cols.name[i] = L"data"; } } else { if (Rf_isNull(dataframe)) nlen = extractor.size(); else return showError<false>("unsupported datat type"), R_NilValue; } if (nlen == 0) return showError<false>("nothing to save: 0 length"), R_NilValue; if (isShape && nlen != extractor.size() ) Rf_warning("length of shape != data.frame length"); //return showError<false>("length of shape != data.frame"), R_NilValue; std::unique_ptr<arcobject::cursor> acur(arcobject::create_insert_cursor(dataset_name, extractor.geometry_info())); if (acur.get() == NULL) return showError<true>(), R_NilValue; arcobject::cursor* cur = acur.get(); for (size_t i = 0; i < cols.name.size(); i++) { ATLASSERT(!cols.name[i].empty()); SEXP it = VECTOR_ELT(dataframe, i); bool skip = false; if (isShape)//if(gt == esriGeometryPolygon || gt == esriGeometryLine) { skip = cols.name[i] == L"Shape_Area"; skip = !skip ? cols.name[i] == L"Shape_Length" : true; } if (!skip) { cols_base* item = setup_field(cur, it, cols.name[i]); if (!item) Rf_warning("unsupported data.field column type");//return showError<false>(L"unsupported data.field column type"), R_NilValue; else cols.c.push_back(item); } } if (!cur->begin()) return showError<true>(), R_NilValue; for (R_xlen_t i = 0; i < nlen; i++) { //ATLTRACE("\n"); for (const auto &c : cols.c) { if (c->pos < 0) continue; CComVariant val; c->get(i, val); if (!cur->setValue(c->pos, val)) return showError<true>("insert row value failed"), R_NilValue; } if (isShape) { if (extractor.isPoints()) cur->set_point(extractor.getPoint(i)); else cur->set_shape(extractor.getShape(i)); } if (!cur->next()) return showError<true>("insert row failed"), R_NilValue; } cur->commit(); return R_NilValue; }
SEXP R_export2dataset(SEXP path, SEXP dataframe, SEXP shape, SEXP shape_info) { std::wstring dataset_name; tools::copy_to(path, dataset_name); struct _cleanup { typedef std::vector<cols_base*> c_type; std::vector<std::wstring> name; c_type c; //std::vector<c_type::const_iterator> shape; c_type shape; ~_cleanup() { for (size_t i = 0; i < c.size(); i++) delete c[i]; for (size_t i = 0; i < shape.size(); i++) delete shape[i]; } }cols; shape_extractor extractor; bool isShape = extractor.init(shape, shape_info) == S_OK; //SEXP sinfo = Rf_getAttrib(shape, Rf_mkChar("shape_info")); //cols.name = df.attr("names"); tools::getNames(dataframe, cols.name); //tools::vectorGeneric shape_info(sinfo); //std::string gt_type; //tools::copy_to(shape_info.at("type"), gt_type); esriGeometryType gt = extractor.type();//str2geometryType(gt_type.c_str()); R_xlen_t n = 0; ATLTRACE("dataframe type:%s", Rf_type2char(TYPEOF(dataframe))); if (Rf_isVectorList(dataframe)) { size_t k = tools::size(dataframe); cols.name.resize(k); for (size_t i = 0; i < k; i++) { n = std::max(n, tools::size(VECTOR_ELT(dataframe, (R_xlen_t)i))); if (cols.name[i].empty()) cols.name[i] = L"data"; } } else { n = tools::size(dataframe); ATLASSERT(cols.name.empty()); } if (isShape == false && n == 0) return showError<false>(L"nothing to save"), R_NilValue; if (isShape && n != extractor.size() ) return showError<false>(L"length of shape != data.frame"), R_NilValue; CComPtr<IGPUtilities> ipDEUtil; if (ipDEUtil.CoCreateInstance(CLSID_GPUtilities) != S_OK) return showError<true>(L"IDEUtilitiesImpl - CoCreateInstance has failed"), R_NilValue; HRESULT hr = 0; CComPtr<IName> ipName; if (isShape) hr = ipDEUtil->CreateFeatureClassName(CComBSTR(dataset_name.c_str()), &ipName); else hr = ipDEUtil->CreateTableName(CComBSTR(dataset_name.c_str()), &ipName); CComQIPtr<IDatasetName> ipDatasetName(ipName); CComPtr<IWorkspaceName> ipWksName; CComQIPtr<IWorkspace> ipWks; if (hr == S_OK) hr = ipDatasetName->get_WorkspaceName(&ipWksName); if (hr == S_OK) { CComPtr<IUnknown> ipUnk; hr = CComQIPtr<IName>(ipWksName)->Open(&ipUnk); ipWks = ipUnk; } if (hr != S_OK) return showError<true>(L"invalid table name"), R_NilValue; CComQIPtr<IFeatureWorkspace> ipFWKS(ipWks); ATLASSERT(ipFWKS); if (!ipFWKS) return showError<true>(L"not a FeatureWorkspace"), R_NilValue; CComBSTR bstrTableName; ipDatasetName->get_Name(&bstrTableName); CComPtr<IFieldsEdit> ipFields; hr = ipFields.CoCreateInstance(CLSID_Fields); if (hr != S_OK) return showError<true>(L"CoCreateInstance"), R_NilValue; createField(NULL, esriFieldTypeOID, ipFields); CComPtr<ISpatialReference> ipSR; if (isShape) { long pos = createField(NULL, esriFieldTypeGeometry, ipFields); CComPtr<IGeometryDef> ipGeoDef; CComPtr<IField> ipField; ipFields->get_Field(pos, &ipField); ipField->get_GeometryDef(&ipGeoDef); CComQIPtr<IGeometryDefEdit> ipGeoDefEd(ipGeoDef); ipGeoDefEd->put_GeometryType(gt); ipGeoDefEd->putref_SpatialReference(extractor.sr()); } if (cols.name.empty()) { cols.name.push_back(L"data"); cols_base* item = setup_field(ipFields, dataframe, cols.name[0].c_str()); if (!item) return showError<false>(L"unsupported datat.field column type"), NULL; cols.c.push_back(item); item->name_ref = &cols.name[0]; } else for (size_t i = 0; i < cols.name.size(); i++) { if (cols.name[i].empty()) continue; const wchar_t* str = cols.name[i].c_str(); SEXP it = VECTOR_ELT(dataframe, (R_len_t)i); cols_base* item = setup_field(ipFields, it, str); if (!item) return showError<false>(L"unsupported datat.field column type"), NULL; cols.c.push_back(item); item->name_ref = &cols.name[i]; } CComPtr<IFieldChecker> ipFieldChecker; ipFieldChecker.CoCreateInstance(CLSID_FieldChecker); if (ipFieldChecker) { ipFieldChecker->putref_ValidateWorkspace(ipWks); long error = 0; //fix fields names CComPtr<IFields> ipFixedFields; CComPtr<IEnumFieldError> ipEError; hr = ipFieldChecker->Validate(ipFields, &ipEError, &ipFixedFields); if (hr != S_OK) return showError<true>(L"validate fields failed"), NULL; if (ipFixedFields) { ipFields = ipFixedFields; for (size_t c = 0; c < cols.c.size(); c++) { CComPtr<IField> ipFixedField; ipFixedFields->get_Field(cols.c[c]->pos, &ipFixedField); _bstr_t name; ipFixedField->get_Name(name.GetAddress()); cols.c[c]->name_ref->assign(name); } } } CComPtr<IUID> ipUID; ipUID.CoCreateInstance(CLSID_UID); if (ipUID) { OLECHAR buf[256]; ::StringFromGUID2(isShape ? CLSID_Feature : CLSID_Row, buf, 256); ipUID->put_Value(CComVariant(buf)); } CComQIPtr<ITable> ipTableNew; CComBSTR keyword(L""); hr = E_FAIL; if (isShape) { CComPtr<IFeatureClass> ipFClass; hr = ipFWKS->CreateFeatureClass(bstrTableName, ipFields, ipUID, 0, esriFTSimple, CComBSTR(L"Shape"), keyword, &ipFClass); ipTableNew = ipFClass; } else { hr = ipFWKS->CreateTable(bstrTableName, ipFields, ipUID, 0, keyword, &ipTableNew); } if (hr != S_OK) { std::wstring err_txt(isShape ? L"Create FeatureClass :" : L"Create Table :"); err_txt += bstrTableName; err_txt += L" has failed"; return showError<true>(err_txt.c_str()), R_NilValue; } CComVariant oid; CComPtr<ICursor> ipCursor; CComPtr<IRowBuffer> ipRowBuffer; hr = ipTableNew->Insert(VARIANT_TRUE, &ipCursor); if (hr != S_OK) return showError<true>(L"Insert cursor failed"), R_NilValue; hr = ipTableNew->CreateRowBuffer(&ipRowBuffer); if (hr != S_OK) return showError<true>(L"Insert cursor failed"), R_NilValue; //re-map fields CComPtr<IFields> ipRealFields; ipCursor->get_Fields(&ipRealFields); for (size_t c = 0; c < cols.c.size(); c++) { ipRealFields->FindField(CComBSTR(cols.c[c]->name_ref->c_str()), &(cols.c[c]->pos)); CComPtr<IField> ipField; ipRealFields->get_Field(cols.c[c]->pos, &ipField); VARIANT_BOOL b = VARIANT_FALSE; ipField->get_IsNullable(&b); if (b == VARIANT_FALSE) { esriFieldType ft = esriFieldTypeInteger; ipField->get_Type(&ft); switch(ft) { case esriFieldTypeInteger: cols.c[c]->vNULL = 0;//std::numeric_limits<int>::min(); break; case esriFieldTypeDouble: cols.c[c]->vNULL = 0.0;//-std::numeric_limits<double>::max(); break; case esriFieldTypeString: cols.c[c]->vNULL = L""; } } } CComQIPtr<IFeatureBuffer> ipFBuffer(ipRowBuffer); for (R_len_t i = 0; i < n; i++) { //ATLTRACE("\n"); for (size_t c = 0; c < cols.c.size(); c++) { if (cols.c[c]->pos < 0) continue; CComVariant val; cols.c[c]->get(i, val); if (val.vt == VT_NULL) hr = ipRowBuffer->put_Value(cols.c[c]->pos, cols.c[c]->vNULL); else hr = ipRowBuffer->put_Value(cols.c[c]->pos, val); if (FAILED(hr)) return showError<true>(L"insert row value failed"), R_NilValue; } VARIANT oid; if (isShape) { ATLASSERT(ipFBuffer); CComQIPtr<IGeometry> ipNewShape; hr = extractor.at(i, &ipNewShape); if (hr != S_OK) return R_NilValue; hr = ipFBuffer->putref_Shape(ipNewShape); if (FAILED(hr)) return showError<true>(L"insert shape failed"), R_NilValue; } hr = ipCursor->InsertRow(ipRowBuffer, &oid); if (hr != S_OK) return showError<true>(L"insert row failed"), R_NilValue; } return R_NilValue; }